[0.6.107] Change queue2 max-size-bytes in PD mode
[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 100
103
104 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
105
106 /*---------------------------------------------------------------------------
107 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
108 ---------------------------------------------------------------------------*/
109
110 /*---------------------------------------------------------------------------
111 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
112 ---------------------------------------------------------------------------*/
113
114 /*---------------------------------------------------------------------------
115 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
116 ---------------------------------------------------------------------------*/
117
118 /*---------------------------------------------------------------------------
119 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
120 ---------------------------------------------------------------------------*/
121 static sound_stream_info_h stream_info;
122
123 /*---------------------------------------------------------------------------
124 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
125 ---------------------------------------------------------------------------*/
126 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
127 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
128 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
129 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
130 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
131 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
132 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
133
134 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
135 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
136 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
137 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
138 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
139 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
140 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
141 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
142 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
143 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
144 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
145 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
146 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
147 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
151
152 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
153 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
154 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
155 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void             __mmplayer_release_misc(mm_player_t* player);
157 static void             __mmplayer_release_misc_post(mm_player_t* player);
158 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
159 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
160 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
161 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
162 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
163 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
164 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
166 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
167 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
168 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
169
170 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
171 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
172 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
173 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
174 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
175 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
176 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
177 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
178 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
179 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
180 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
181 static gpointer __mmplayer_next_play_thread(gpointer data);
182 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
183
184 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
185 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
186 static void __mmplayer_release_dump_list(GList *dump_list);
187
188 static int              __gst_realize(mm_player_t* player);
189 static int              __gst_unrealize(mm_player_t* player);
190 static int              __gst_start(mm_player_t* player);
191 static int              __gst_stop(mm_player_t* player);
192 static int              __gst_pause(mm_player_t* player, gboolean async);
193 static int              __gst_resume(mm_player_t* player, gboolean async);
194 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
195                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
196                                         gint64 cur, GstSeekType stop_type, gint64 stop);
197 static int __gst_pending_seek(mm_player_t* player);
198
199 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
200 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
201 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
202 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
203 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
204
205 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
206
207 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
208 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
209
210 /* util */
211 static gboolean __is_ms_buff_src(mm_player_t* player);
212 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
213
214 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
215 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
216 static int __mmplayer_start_streaming_ext(mm_player_t *player);
217 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
218 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
219
220 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
221 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
222 static void __mmplayer_check_pipeline(mm_player_t* player);
223 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
224 static void __mmplayer_deactivate_old_path(mm_player_t *player);
225
226 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
227 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
228
229 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
230 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
231 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
232 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
233 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
234 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
235 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
236 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
237 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
238 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
239 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
240 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
241 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
242 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
243 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
244 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
245
246 /*===========================================================================================
247 |                                                                                                                                                                                       |
248 |  FUNCTION DEFINITIONS                                                                                                                                         |
249 |                                                                                                                                                                                       |
250 ========================================================================================== */
251
252 #if 0 //debug
253 static void
254 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
255 {
256         gint i, count;
257
258         count = gst_tag_list_get_tag_size(list, tag);
259
260         LOGD("count = %d", count);
261
262         for (i = 0; i < count; i++) {
263                 gchar *str;
264
265                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
266                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
267                                 g_assert_not_reached();
268                 } else
269                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
270
271                 if (i == 0)
272                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
273                 else
274                         g_print("                 : %s\n", str);
275
276                 g_free(str);
277         }
278 }
279 #endif
280
281 /* This function should be called after the pipeline goes PAUSED or higher
282 state. */
283 gboolean
284 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
285 {
286         static gboolean has_duration = FALSE;
287         static gboolean has_video_attrs = FALSE;
288         static gboolean has_audio_attrs = FALSE;
289         static gboolean has_bitrate = FALSE;
290         gboolean missing_only = FALSE;
291         gboolean all = FALSE;
292         gint64 dur_nsec = 0;
293         GstStructure* p = NULL;
294         MMHandleType attrs = 0;
295         gchar *path = NULL;
296         struct stat sb;
297
298         MMPLAYER_FENTER();
299
300         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
301
302         /* check player state here */
303         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
304                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
305                 /* give warning now only */
306                 LOGW("be careful. content attributes may not available in this state ");
307         }
308
309         /* get content attribute first */
310         attrs = MMPLAYER_GET_ATTRS(player);
311         if (!attrs) {
312                 LOGE("cannot get content attribute");
313                 return FALSE;
314         }
315
316         /* get update flag */
317
318         if (flag & ATTR_MISSING_ONLY) {
319                 missing_only = TRUE;
320                 LOGD("updating missed attr only");
321         }
322
323         if (flag & ATTR_ALL) {
324                 all = TRUE;
325                 has_duration = FALSE;
326                 has_video_attrs = FALSE;
327                 has_audio_attrs = FALSE;
328                 has_bitrate = FALSE;
329
330                 LOGD("updating all attrs");
331         }
332
333         if (missing_only && all) {
334                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
335                 missing_only = FALSE;
336         }
337
338         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
339                 LOGD("try to update duration");
340                 has_duration = FALSE;
341
342                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
343                         player->duration = dur_nsec;
344                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
345                 }
346
347                 if (player->duration < 0) {
348                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
349                         player->duration = 0;
350                 }
351
352                 /* update streaming service type */
353                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
354
355                 /* check duration is OK */
356                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
357                         /* FIXIT : find another way to get duration here. */
358                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
359                 } else {
360                         /*update duration */
361                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
362                         has_duration = TRUE;
363                 }
364         }
365
366         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
367                 /* update audio params
368                 NOTE : We need original audio params and it can be only obtained from src pad of audio
369                 decoder. Below code only valid when we are not using 'resampler' just before
370                 'audioconverter'. */
371
372                 LOGD("try to update audio attrs");
373                 has_audio_attrs = FALSE;
374
375                 if (player->pipeline->audiobin &&
376                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
377                         GstCaps *caps_a = NULL;
378                         GstPad* pad = NULL;
379                         gint samplerate = 0, channels = 0;
380
381                         pad = gst_element_get_static_pad(
382                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
383
384                         if (pad) {
385                                 caps_a = gst_pad_get_current_caps(pad);
386
387                                 if (caps_a) {
388                                         p = gst_caps_get_structure(caps_a, 0);
389
390                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
391
392                                         gst_structure_get_int(p, "rate", &samplerate);
393                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
394
395                                         gst_structure_get_int(p, "channels", &channels);
396                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
397
398                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
399
400                                         gst_caps_unref(caps_a);
401                                         caps_a = NULL;
402
403                                         has_audio_attrs = TRUE;
404                                 } else
405                                         LOGW("not ready to get audio caps");
406
407                                 gst_object_unref(pad);
408                         } else
409                                 LOGW("failed to get pad from audiosink");
410                 }
411         }
412
413         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
414                 LOGD("try to update video attrs");
415                 has_video_attrs = FALSE;
416
417                 if (player->pipeline->videobin &&
418                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
419                         GstCaps *caps_v = NULL;
420                         GstPad* pad = NULL;
421                         gint tmpNu, tmpDe;
422                         gint width, height;
423
424                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
425                         if (pad) {
426                                 caps_v = gst_pad_get_current_caps(pad);
427
428                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
429                                 if (!caps_v && player->v_stream_caps) {
430                                         caps_v = player->v_stream_caps;
431                                         gst_caps_ref(caps_v);
432                                 }
433
434                                 if (caps_v) {
435                                         p = gst_caps_get_structure(caps_v, 0);
436                                         gst_structure_get_int(p, "width", &width);
437                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
438
439                                         gst_structure_get_int(p, "height", &height);
440                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
441
442                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
443
444                                         SECURE_LOGD("width : %d     height : %d", width, height);
445
446                                         gst_caps_unref(caps_v);
447                                         caps_v = NULL;
448
449                                         if (tmpDe > 0) {
450                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
451                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
452                                         }
453
454                                         has_video_attrs = TRUE;
455                                 } else
456                                         LOGD("no negitiated caps from videosink");
457                                 gst_object_unref(pad);
458                                 pad = NULL;
459                         } else
460                                 LOGD("no videosink sink pad");
461                 }
462         }
463
464
465         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
466                 has_bitrate = FALSE;
467
468                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
469                 if (player->duration) {
470                         guint64 data_size = 0;
471
472                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
473                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
474
475                                 if (stat(path, &sb) == 0)
476                                         data_size = (guint64)sb.st_size;
477                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
478                                 data_size = player->http_content_size;
479                         }
480                         LOGD("try to update bitrate : data_size = %lld", data_size);
481
482                         if (data_size) {
483                                 guint64 bitrate = 0;
484                                 guint64 msec_dur = 0;
485
486                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
487                                 if (msec_dur > 0) {
488                                         bitrate = data_size * 8 * 1000 / msec_dur;
489                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
490                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
491
492                                         has_bitrate = TRUE;
493                                 } else {
494                                         LOGD("player duration is less than 0");
495                                 }
496                         }
497
498                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
499                                 if (player->total_bitrate) {
500                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
501                                         has_bitrate = TRUE;
502                                 }
503                         }
504                 }
505         }
506
507         /* validate all */
508         if (mmf_attrs_commit(attrs)) {
509                 LOGE("failed to update attributes\n");
510                 return FALSE;
511         }
512
513         MMPLAYER_FLEAVE();
514
515         return TRUE;
516 }
517
518 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
519 {
520         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
521
522         MMPLAYER_FENTER();
523
524         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
525                         player->pipeline &&
526                         player->pipeline->mainbin &&
527                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
528                         STREAMING_SERVICE_NONE);
529
530         /* streaming service type if streaming */
531         if (!MMPLAYER_IS_STREAMING(player))
532                 return STREAMING_SERVICE_NONE;
533
534         if (MMPLAYER_IS_HTTP_STREAMING(player))
535                 streaming_type = (player->duration == 0) ?
536                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
537
538         switch (streaming_type) {
539         case STREAMING_SERVICE_LIVE:
540                 LOGD("it's live streaming");
541                 break;
542         case STREAMING_SERVICE_VOD:
543                 LOGD("it's vod streaming");
544                 break;
545         default:
546                 LOGE("should not get here");
547                 break;
548         }
549
550         MMPLAYER_FLEAVE();
551
552         return streaming_type;
553 }
554
555
556 /* this function sets the player state and also report
557  * it to applicaton by calling callback function
558  */
559 int
560 __mmplayer_set_state(mm_player_t* player, int state)
561 {
562         MMMessageParamType msg = {0, };
563         gboolean post_bos = FALSE;
564
565         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
566
567         if (MMPLAYER_CURRENT_STATE(player) == state) {
568                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
569                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
570                 return MM_ERROR_NONE;
571         }
572
573         /* update player states */
574         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
575         MMPLAYER_CURRENT_STATE(player) = state;
576
577         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
578                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
579
580         /* print state */
581         MMPLAYER_PRINT_STATE(player);
582
583         switch (MMPLAYER_CURRENT_STATE(player)) {
584         case MM_PLAYER_STATE_NULL:
585         case MM_PLAYER_STATE_READY:
586                 break;
587
588         case MM_PLAYER_STATE_PAUSED:
589                 {
590                         if (!player->sent_bos) {
591                                 /* rtsp case, get content attrs by GstMessage */
592                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
593                                         /* it's first time to update all content attrs. */
594                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
595                                 }
596                         }
597
598                         /* add audio callback probe if condition is satisfied */
599                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
600                                 __mmplayer_configure_audio_callback(player);
601
602                         /* FIXIT : handle return value */
603                 }
604                 break;
605
606         case MM_PLAYER_STATE_PLAYING:
607                 {
608                         /* try to get content metadata */
609                         if (!player->sent_bos) {
610                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
611                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
612                                  * legacy mmfw-player api */
613                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
614                         }
615
616                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
617                                 if (!player->sent_bos)
618                                         __mmplayer_handle_missed_plugin(player);
619                         }
620
621                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
622                                 /* initialize because auto resume is done well. */
623                                 player->resumed_by_rewind = FALSE;
624                                 player->playback_rate = 1.0;
625                         }
626
627                         if (!player->sent_bos) {
628                                 /* check audio codec field is set or not
629                                  * we can get it from typefinder or codec's caps.
630                                  */
631                                 gchar *audio_codec = NULL;
632                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
633
634                                 /* The codec format can't be sent for audio only case like amr, mid etc.
635                                  * Because, parser don't make related TAG.
636                                  * So, if it's not set yet, fill it with found data.
637                                  */
638                                 if (!audio_codec) {
639                                         if (g_strrstr(player->type, "audio/midi"))
640                                                 audio_codec = g_strdup("MIDI");
641                                         else if (g_strrstr(player->type, "audio/x-amr"))
642                                                 audio_codec = g_strdup("AMR");
643                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
644                                                 audio_codec = g_strdup("AAC");
645                                         else
646                                                 audio_codec = g_strdup("unknown");
647                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
648
649                                         MMPLAYER_FREEIF(audio_codec);
650                                         if (mmf_attrs_commit(player->attrs))
651                                                 LOGE("failed to update attributes\n");
652
653                                         LOGD("set audio codec type with caps\n");
654                                 }
655
656                                 post_bos = TRUE;
657                         }
658                 }
659                 break;
660
661         case MM_PLAYER_STATE_NONE:
662         default:
663                 LOGW("invalid target state, there is nothing to do.\n");
664                 break;
665         }
666
667
668         /* post message to application */
669         if (MMPLAYER_TARGET_STATE(player) == state) {
670                 /* fill the message with state of player */
671                 msg.union_type = MM_MSG_UNION_STATE;
672                 msg.state.previous = MMPLAYER_PREV_STATE(player);
673                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
674
675                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
676
677                 /* state changed by resource callback */
678                 if (player->interrupted_by_resource) {
679                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
680                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
681                 } else { /* state changed by usecase */
682                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
683                 }
684         } else {
685                 LOGD("intermediate state, do nothing.\n");
686                 MMPLAYER_PRINT_STATE(player);
687                 return MM_ERROR_NONE;
688         }
689
690         if (post_bos) {
691                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
692                 player->sent_bos = TRUE;
693         }
694
695         return MM_ERROR_NONE;
696 }
697
698 static gpointer __mmplayer_next_play_thread(gpointer data)
699 {
700         mm_player_t* player = (mm_player_t*) data;
701         MMPlayerGstElement *mainbin = NULL;
702
703         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
704
705         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
706         while (!player->next_play_thread_exit) {
707                 LOGD("next play thread started. waiting for signal.\n");
708                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
709
710                 LOGD("reconfigure pipeline for gapless play.\n");
711
712                 if (player->next_play_thread_exit) {
713                         if (player->gapless.reconfigure) {
714                                 player->gapless.reconfigure = false;
715                                 MMPLAYER_PLAYBACK_UNLOCK(player);
716                         }
717                         LOGD("exiting gapless play thread\n");
718                         break;
719                 }
720
721                 mainbin = player->pipeline->mainbin;
722
723                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
724                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
725                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
726                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
728
729                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
730         }
731         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
732
733         return NULL;
734 }
735
736 static void
737 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
738 {
739         MMHandleType attrs = 0;
740         guint64 data_size = 0;
741         gchar* path = NULL;
742         unsigned long pos_msec = 0;
743         struct stat sb;
744
745         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
746
747         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
748
749         attrs = MMPLAYER_GET_ATTRS(player);
750         if (!attrs) {
751                 LOGE("fail to get attributes.\n");
752                 return;
753         }
754
755         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
756                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
757
758                 if (stat(path, &sb) == 0)
759                         data_size = (guint64)sb.st_size;
760         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
761                 data_size = player->http_content_size;
762
763         __mm_player_streaming_buffering(player->streamer,
764                                                                                 buffering_msg,
765                                                                                 data_size,
766                                                                                 player->last_position,
767                                                                                 player->duration);
768
769         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
770
771         return;
772 }
773
774 static int
775 __mmplayer_handle_buffering_message(mm_player_t* player)
776 {
777         int ret = MM_ERROR_NONE;
778         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
779         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
780         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
781         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
782
783         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
784                 LOGW("do nothing for buffering msg\n");
785                 ret = MM_ERROR_PLAYER_INVALID_STATE;
786                 goto exit;
787         }
788
789         prev_state = MMPLAYER_PREV_STATE(player);
790         current_state = MMPLAYER_CURRENT_STATE(player);
791         target_state = MMPLAYER_TARGET_STATE(player);
792         pending_state = MMPLAYER_PENDING_STATE(player);
793
794         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
795                 MMPLAYER_STATE_GET_NAME(prev_state),
796                 MMPLAYER_STATE_GET_NAME(current_state),
797                 MMPLAYER_STATE_GET_NAME(pending_state),
798                 MMPLAYER_STATE_GET_NAME(target_state),
799                 player->streamer->is_buffering);
800
801         if (!player->streamer->is_buffering) {
802                 /* NOTE : if buffering has done, player has to go to target state. */
803                 switch (target_state) {
804                 case MM_PLAYER_STATE_PAUSED:
805                         {
806                                 switch (pending_state) {
807                                 case MM_PLAYER_STATE_PLAYING:
808                                         __gst_pause(player, TRUE);
809                                         break;
810
811                                 case MM_PLAYER_STATE_PAUSED:
812                                         LOGD("player is already going to paused state, there is nothing to do.\n");
813                                         break;
814
815                                 case MM_PLAYER_STATE_NONE:
816                                 case MM_PLAYER_STATE_NULL:
817                                 case MM_PLAYER_STATE_READY:
818                                 default:
819                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
820                                         break;
821                                 }
822                         }
823                         break;
824
825                 case MM_PLAYER_STATE_PLAYING:
826                         {
827                                 switch (pending_state) {
828                                 case MM_PLAYER_STATE_NONE:
829                                         {
830                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
831                                                         __gst_resume(player, TRUE);
832                                         }
833                                         break;
834
835                                 case MM_PLAYER_STATE_PAUSED:
836                                         /* NOTE: It should be worked as asynchronously.
837                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
838                                          */
839                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
840                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
841                                                  * The current state should be changed to paused purposely to prevent state conflict.
842                                                  */
843                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
844                                         }
845                                         __gst_resume(player, TRUE);
846                                         break;
847
848                                 case MM_PLAYER_STATE_PLAYING:
849                                         LOGD("player is already going to playing state, there is nothing to do.\n");
850                                         break;
851
852                                 case MM_PLAYER_STATE_NULL:
853                                 case MM_PLAYER_STATE_READY:
854                                 default:
855                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
856                                         break;
857                                 }
858                         }
859                         break;
860
861                 case MM_PLAYER_STATE_NULL:
862                 case MM_PLAYER_STATE_READY:
863                 case MM_PLAYER_STATE_NONE:
864                 default:
865                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
866                         break;
867                 }
868         } else {
869                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
870                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
871                  */
872                 switch (pending_state) {
873                 case MM_PLAYER_STATE_NONE:
874                         {
875                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
876                                         /* rtsp streaming pause makes rtsp server stop sending data. */
877                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
878                                                 LOGD("set pause state during buffering\n");
879                                                 __gst_pause(player, TRUE);
880                                         }
881                                 }
882                         }
883                         break;
884
885                 case MM_PLAYER_STATE_PLAYING:
886                         /* rtsp streaming pause makes rtsp server stop sending data. */
887                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
888                                 __gst_pause(player, TRUE);
889                         break;
890
891                 case MM_PLAYER_STATE_PAUSED:
892                         break;
893
894                 case MM_PLAYER_STATE_NULL:
895                 case MM_PLAYER_STATE_READY:
896                 default:
897                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
898                         break;
899                 }
900         }
901
902 exit:
903         return ret;
904 }
905
906 static void
907 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
908 {
909         MMPlayerGstElement *textbin;
910         MMPLAYER_FENTER();
911
912         MMPLAYER_RETURN_IF_FAIL(player &&
913                                         player->pipeline &&
914                                         player->pipeline->textbin);
915
916         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
917
918         textbin = player->pipeline->textbin;
919
920         if (is_drop) {
921                 LOGD("Drop subtitle text after getting EOS\n");
922
923                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
924                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
925
926                 player->is_subtitle_force_drop = TRUE;
927         } else {
928                 if (player->is_subtitle_force_drop == TRUE) {
929                         LOGD("Enable subtitle data path without drop\n");
930
931                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
932                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
933
934                         LOGD("non-connected with external display");
935
936                         player->is_subtitle_force_drop = FALSE;
937                 }
938         }
939 }
940
941 static VariantData *
942 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
943 {
944         VariantData *var_info = NULL;
945         g_return_val_if_fail(self != NULL, NULL);
946
947         var_info = g_new0(VariantData, 1);
948         if (!var_info) return NULL;
949         var_info->bandwidth = self->bandwidth;
950         var_info->width = self->width;
951         var_info->height = self->height;
952         return var_info;
953 }
954
955 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
956 {
957         mm_player_t* player = (mm_player_t*)hplayer;
958
959         MMPLAYER_FENTER();
960         MMPLAYER_RETURN_IF_FAIL(player);
961
962         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
963
964         /* destroy the gst bus msg thread */
965         if (player->bus_msg_thread) {
966                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
967                 player->bus_msg_thread_exit = TRUE;
968                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
969                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
970
971                 LOGD("gst bus msg thread exit.");
972                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
973                 player->bus_msg_thread = NULL;
974
975                 g_mutex_clear(&player->bus_msg_thread_mutex);
976                 g_cond_clear(&player->bus_msg_thread_cond);
977         }
978
979         MMPLAYER_FLEAVE();
980 }
981
982 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
983 {
984         mm_player_t *player = (mm_player_t*)(data);
985         GstMessage *msg = NULL;
986         GstBus *bus = NULL;
987
988         MMPLAYER_FENTER();
989         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
990                                                 player->pipeline &&
991                                                 player->pipeline->mainbin &&
992                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
993                                                 NULL);
994
995         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
996         if (!bus) {
997                 LOGE("cannot get BUS from the pipeline");
998                 return NULL;
999         }
1000
1001         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1002
1003         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1004         while (!player->bus_msg_thread_exit) {
1005                 msg = gst_bus_pop(bus);
1006                 if (msg == NULL) {
1007                         int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1008                         MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1009                         continue;
1010                 }
1011
1012                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1013                 /* handle the gst msg */
1014                 __mmplayer_gst_callback(msg, player);
1015                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016                 gst_message_unref(msg);
1017         }
1018
1019         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1020         gst_object_unref(GST_OBJECT(bus));
1021
1022         MMPLAYER_FLEAVE();
1023         return NULL;
1024 }
1025
1026 static void
1027 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1028 {
1029         mm_player_t* player = (mm_player_t*)(data);
1030         static gboolean async_done = FALSE;
1031
1032         MMPLAYER_RETURN_IF_FAIL(player);
1033         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1034
1035         switch (GST_MESSAGE_TYPE(msg)) {
1036         case GST_MESSAGE_UNKNOWN:
1037                 LOGD("unknown message received\n");
1038                 break;
1039
1040         case GST_MESSAGE_EOS:
1041                 {
1042                         MMHandleType attrs = 0;
1043                         gint count = 0;
1044
1045                         LOGD("GST_MESSAGE_EOS received\n");
1046
1047                         /* NOTE : EOS event is comming multiple time. watch out it */
1048                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1049                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1050                                 LOGD("EOS received on non-playing state. ignoring it\n");
1051                                 break;
1052                         }
1053
1054                         if (player->pipeline) {
1055                                 if (player->pipeline->textbin)
1056                                         __mmplayer_drop_subtitle(player, TRUE);
1057
1058                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1059                                         GstPad *pad = NULL;
1060
1061                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1062
1063                                         LOGD("release audio callback\n");
1064
1065                                         /* release audio callback */
1066                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1067                                         player->audio_cb_probe_id = 0;
1068                                         /* audio callback should be free because it can be called even though probe remove.*/
1069                                         player->audio_stream_cb = NULL;
1070                                         player->audio_stream_cb_user_param = NULL;
1071
1072                                 }
1073                         }
1074                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1075                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1076
1077                         /* rewind if repeat count is greater then zero */
1078                         /* get play count */
1079                         attrs = MMPLAYER_GET_ATTRS(player);
1080
1081                         if (attrs) {
1082                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1083
1084                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1085
1086                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1087                                         if (player->playback_rate < 0.0) {
1088                                                 player->resumed_by_rewind = TRUE;
1089                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1090                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1091                                         }
1092
1093                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1094
1095                                         /* initialize */
1096                                         player->sent_bos = FALSE;
1097
1098                                         /* not posting eos when repeating */
1099                                         break;
1100                                 }
1101                         }
1102
1103                         if (player->pipeline)
1104                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1105
1106                         /* post eos message to application */
1107                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1108
1109                         /* reset last position */
1110                         player->last_position = 0;
1111                 }
1112                 break;
1113
1114         case GST_MESSAGE_ERROR:
1115                 {
1116                         GError *error = NULL;
1117                         gchar* debug = NULL;
1118
1119                         /* generating debug info before returning error */
1120                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1121
1122                         /* get error code */
1123                         gst_message_parse_error(msg, &error, &debug);
1124
1125                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1126                                 /* Note : the streaming error from the streaming source is handled
1127                                  *   using __mmplayer_handle_streaming_error.
1128                                  */
1129                                 __mmplayer_handle_streaming_error(player, msg);
1130
1131                                 /* dump state of all element */
1132                                 __mmplayer_dump_pipeline_state(player);
1133                         } else {
1134                                 /* traslate gst error code to msl error code. then post it
1135                                  * to application if needed
1136                                  */
1137                                 __mmplayer_handle_gst_error(player, msg, error);
1138
1139                                 if (debug)
1140                                         LOGE("error debug : %s", debug);
1141                         }
1142
1143                         if (MMPLAYER_IS_HTTP_PD(player))
1144                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1145
1146                         MMPLAYER_FREEIF(debug);
1147                         g_error_free(error);
1148                 }
1149                 break;
1150
1151         case GST_MESSAGE_WARNING:
1152                 {
1153                         char* debug = NULL;
1154                         GError* error = NULL;
1155
1156                         gst_message_parse_warning(msg, &error, &debug);
1157
1158                         LOGD("warning : %s\n", error->message);
1159                         LOGD("debug : %s\n", debug);
1160
1161                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1162
1163                         MMPLAYER_FREEIF(debug);
1164                         g_error_free(error);
1165                 }
1166                 break;
1167
1168         case GST_MESSAGE_TAG:
1169                 {
1170                         LOGD("GST_MESSAGE_TAG\n");
1171                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1172                                 LOGW("failed to extract tags from gstmessage\n");
1173                 }
1174                 break;
1175
1176         case GST_MESSAGE_BUFFERING:
1177                 {
1178                         MMMessageParamType msg_param = {0, };
1179                         int bRet = MM_ERROR_NONE;
1180
1181                         if (!(player->pipeline && player->pipeline->mainbin)) {
1182                                 LOGE("player pipeline handle is null");
1183                                 break;
1184                         }
1185
1186                         if (!MMPLAYER_IS_STREAMING(player))
1187                                 break;
1188
1189                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1190                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1191                                         /* skip the playback control by buffering msg while user request is handled. */
1192                                         gint per = 0;
1193
1194                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1195
1196                                         gst_message_parse_buffering(msg, &per);
1197                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1198
1199                                         msg_param.connection.buffering = per;
1200                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1201                                         break;
1202                                 }
1203                         } else {
1204                                 MMPLAYER_CMD_LOCK(player);
1205                         }
1206
1207                         /* ignore the prev buffering message */
1208                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1209                                 && (player->streamer->is_buffering_done == TRUE)) {
1210                                 gint buffer_percent = 0;
1211
1212                                 gst_message_parse_buffering(msg, &buffer_percent);
1213
1214                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1215                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1216                                         player->streamer->is_buffering_done = FALSE;
1217                                 }
1218                                 MMPLAYER_CMD_UNLOCK(player);
1219                                 break;
1220                         }
1221
1222                         __mmplayer_update_buffer_setting(player, msg);
1223
1224                         bRet = __mmplayer_handle_buffering_message(player);
1225
1226                         if (bRet == MM_ERROR_NONE) {
1227                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1228                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1229
1230                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1231                                         player->pending_resume &&
1232                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1233
1234                                         player->is_external_subtitle_added_now = FALSE;
1235                                         player->pending_resume = FALSE;
1236                                         _mmplayer_resume((MMHandleType)player);
1237                                 }
1238
1239                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1240                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1241
1242                                         if (player->doing_seek) {
1243                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1244                                                         player->doing_seek = FALSE;
1245                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1246                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1247                                                         async_done = TRUE;
1248                                                 }
1249                                         }
1250                                 }
1251                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1252                                 if (!player->streamer) {
1253                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1254                                         MMPLAYER_CMD_UNLOCK(player);
1255                                         break;
1256                                 }
1257
1258                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1259
1260                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1261                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1262
1263                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1264                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1265                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1266                                         } else {
1267                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1268                                         }
1269                                 } else {
1270                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1271                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1272                                 }
1273                         }
1274                         MMPLAYER_CMD_UNLOCK(player);
1275                 }
1276                 break;
1277
1278         case GST_MESSAGE_STATE_CHANGED:
1279                 {
1280                         MMPlayerGstElement *mainbin;
1281                         const GValue *voldstate, *vnewstate, *vpending;
1282                         GstState oldstate = GST_STATE_NULL;
1283                         GstState newstate = GST_STATE_NULL;
1284                         GstState pending = GST_STATE_NULL;
1285
1286                         if (!(player->pipeline && player->pipeline->mainbin)) {
1287                                 LOGE("player pipeline handle is null");
1288                                 break;
1289                         }
1290
1291                         mainbin = player->pipeline->mainbin;
1292
1293                         /* we only handle messages from pipeline */
1294                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1295                                 break;
1296
1297                         /* get state info from msg */
1298                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1299                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1300                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1301
1302                         if (!voldstate || !vnewstate) {
1303                                 LOGE("received msg has wrong format.");
1304                                 break;
1305                         }
1306
1307                         oldstate = (GstState)voldstate->data[0].v_int;
1308                         newstate = (GstState)vnewstate->data[0].v_int;
1309                         if (vpending)
1310                                 pending = (GstState)vpending->data[0].v_int;
1311
1312                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1313                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1314                                 gst_element_state_get_name((GstState)oldstate),
1315                                 gst_element_state_get_name((GstState)newstate),
1316                                 gst_element_state_get_name((GstState)pending));
1317
1318                         if (newstate == GST_STATE_PLAYING) {
1319                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1320
1321                                         int retVal = MM_ERROR_NONE;
1322                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1323
1324                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1325
1326                                         if (MM_ERROR_NONE != retVal)
1327                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1328
1329                                         player->pending_seek.is_pending = FALSE;
1330                                 }
1331                         }
1332
1333                         if (oldstate == newstate) {
1334                                 LOGD("pipeline reports state transition to old state");
1335                                 break;
1336                         }
1337
1338                         switch (newstate) {
1339                         case GST_STATE_VOID_PENDING:
1340                                 break;
1341
1342                         case GST_STATE_NULL:
1343                                 break;
1344
1345                         case GST_STATE_READY:
1346                                 break;
1347
1348                         case GST_STATE_PAUSED:
1349                                 {
1350                                         gboolean prepare_async = FALSE;
1351                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1352
1353                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1354                                                 __mmplayer_configure_audio_callback(player);
1355
1356                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1357                                                 // managed prepare async case
1358                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1359                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1360                                         }
1361
1362                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1363                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1364
1365                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1366                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1367                                                                 player->total_maximum_bitrate, player->total_bitrate);
1368
1369                                                 if (player->pending_seek.is_pending) {
1370                                                         LOGW("trying to do pending seek");
1371                                                         MMPLAYER_CMD_LOCK(player);
1372                                                         __gst_pending_seek(player);
1373                                                         MMPLAYER_CMD_UNLOCK(player);
1374                                                 }
1375                                         }
1376                                 }
1377                                 break;
1378
1379                         case GST_STATE_PLAYING:
1380                                 {
1381                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1382
1383                                         if (MMPLAYER_IS_STREAMING(player)) {
1384                                                 // managed prepare async case when buffering is completed
1385                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1386                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1387                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1388                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1389
1390                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1391
1392                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1393                                                         if (player->streamer->buffering_percent < 100) {
1394
1395                                                                 MMMessageParamType msg_param = {0, };
1396                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1397
1398                                                                 msg_param.connection.buffering = 100;
1399                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1400                                                         }
1401                                                 }
1402                                         }
1403
1404                                         if (player->gapless.stream_changed) {
1405                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1406                                                 player->gapless.stream_changed = FALSE;
1407                                         }
1408
1409                                         if (player->doing_seek && async_done) {
1410                                                 player->doing_seek = FALSE;
1411                                                 async_done = FALSE;
1412                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1413                                         }
1414                                 }
1415                                 break;
1416
1417                         default:
1418                                 break;
1419                         }
1420                 }
1421                 break;
1422
1423         case GST_MESSAGE_CLOCK_LOST:
1424                         {
1425                                 GstClock *clock = NULL;
1426                                 gboolean need_new_clock = FALSE;
1427
1428                                 gst_message_parse_clock_lost(msg, &clock);
1429                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1430
1431                                 if (!player->videodec_linked)
1432                                         need_new_clock = TRUE;
1433                                 else if (!player->ini.use_system_clock)
1434                                         need_new_clock = TRUE;
1435
1436                                 if (need_new_clock) {
1437                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1438                                         __gst_pause(player, FALSE);
1439                                         __gst_resume(player, FALSE);
1440                                 }
1441                         }
1442                         break;
1443
1444         case GST_MESSAGE_NEW_CLOCK:
1445                         {
1446                                 GstClock *clock = NULL;
1447                                 gst_message_parse_new_clock(msg, &clock);
1448                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1449                         }
1450                         break;
1451
1452         case GST_MESSAGE_ELEMENT:
1453                         {
1454                                 const gchar *structure_name;
1455                                 gint count = 0, idx = 0;
1456                                 MMHandleType attrs = 0;
1457
1458                                 attrs = MMPLAYER_GET_ATTRS(player);
1459                                 if (!attrs) {
1460                                         LOGE("cannot get content attribute");
1461                                         break;
1462                                 }
1463
1464                                 if (gst_message_get_structure(msg) == NULL)
1465                                         break;
1466
1467                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1468                                 if (!structure_name)
1469                                         break;
1470
1471                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1472
1473                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1474                                         const GValue *var_info = NULL;
1475
1476                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1477                                         if (var_info != NULL) {
1478                                                 if (player->adaptive_info.var_list)
1479                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1480
1481                                                 /* share addr or copy the list */
1482                                                 player->adaptive_info.var_list =
1483                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1484
1485                                                 count = g_list_length(player->adaptive_info.var_list);
1486                                                 if (count > 0) {
1487                                                         VariantData *temp = NULL;
1488
1489                                                         /* print out for debug */
1490                                                         LOGD("num of variant_info %d", count);
1491                                                         for (idx = 0; idx < count; idx++) {
1492                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1493                                                                 if (temp)
1494                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1495                                                         }
1496                                                 }
1497                                         }
1498                                 }
1499
1500                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1501                                         gint num_buffers = 0;
1502                                         gint extra_num_buffers = 0;
1503
1504                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1505                                                 player->video_num_buffers = num_buffers;
1506                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1507                                         }
1508
1509                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1510                                                 player->video_extra_num_buffers = extra_num_buffers;
1511                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1512                                         }
1513                                         break;
1514                                 }
1515
1516                                 if (!strcmp(structure_name, "Language_list")) {
1517                                         const GValue *lang_list = NULL;
1518                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1519                                         if (lang_list != NULL) {
1520                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1521                                                 if (count > 1)
1522                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1523                                         }
1524                                 }
1525
1526                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1527                                         const GValue *lang_list = NULL;
1528                                         MMPlayerLangStruct *temp = NULL;
1529
1530                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1531                                         if (lang_list != NULL) {
1532                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1533                                                 if (count) {
1534                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1535                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1536                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1537                                                         if (mmf_attrs_commit(attrs))
1538                                                                 LOGE("failed to commit.\n");
1539                                                         LOGD("Total subtitle tracks = %d \n", count);
1540
1541                                                         while (count) {
1542                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1543                                                                 if (temp)
1544                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1545                                                                                                 temp->language_key, temp->language_code);
1546                                                                 count--;
1547                                                         }
1548                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1549                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1550                                                 }
1551                                         }
1552                                 }
1553
1554                                 /* custom message */
1555                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1556                                         MMMessageParamType msg_param = {0,};
1557                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1558                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1559                                 }
1560
1561                                 /* custom message for RTSP attribute :
1562                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1563                                     sdp which has contents info is received when rtsp connection is opened.
1564                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1565                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1566
1567                                         gchar *audio_codec = NULL;
1568                                         gchar *video_codec = NULL;
1569                                         gchar *video_frame_size = NULL;
1570
1571                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1572                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1573                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1574                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1575
1576                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1577                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1578                                         if (audio_codec)
1579                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1580
1581                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1582                                         LOGD("rtsp_video_codec : %s", video_codec);
1583                                         if (video_codec)
1584                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1585
1586                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1587                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1588                                         if (video_frame_size) {
1589
1590                                                 char *seperator = strchr(video_frame_size, '-');
1591                                                 if (seperator) {
1592
1593                                                         char video_width[10] = {0,};
1594                                                         int frame_size_len = strlen(video_frame_size);
1595                                                         int separtor_len = strlen(seperator);
1596
1597                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1598                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1599
1600                                                         seperator++;
1601                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1602                                                 }
1603                                         }
1604
1605                                         if (mmf_attrs_commit(attrs))
1606                                                 LOGE("failed to commit.\n");
1607                                 }
1608                         }
1609                         break;
1610
1611         case GST_MESSAGE_DURATION_CHANGED:
1612                 {
1613                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1614                         if (!__mmplayer_gst_handle_duration(player, msg))
1615                                 LOGW("failed to update duration");
1616                 }
1617
1618                 break;
1619
1620         case GST_MESSAGE_ASYNC_START:
1621                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1622                 break;
1623
1624         case GST_MESSAGE_ASYNC_DONE:
1625                 {
1626                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1627
1628                         /* we only handle messages from pipeline */
1629                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1630                                 break;
1631
1632                         if (player->doing_seek) {
1633                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1634                                         player->doing_seek = FALSE;
1635                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1636                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1637                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1638                                                 (player->streamer) &&
1639                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1640                                                 (player->streamer->is_buffering == FALSE)) {
1641                                                 GstQuery *query = NULL;
1642                                                 gboolean busy = FALSE;
1643                                                 gint percent = 0;
1644
1645                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1646                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1647                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1648                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1649                                                         gst_query_unref(query);
1650
1651                                                         LOGD("buffered percent(%s): %d\n",
1652                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1653                                                 }
1654
1655                                                 if (percent >= 100) {
1656                                                         player->streamer->is_buffering = FALSE;
1657                                                         __mmplayer_handle_buffering_message(player);
1658                                                 }
1659                                         }
1660
1661                                         async_done = TRUE;
1662                                 }
1663                         }
1664                 }
1665                 break;
1666
1667         #if 0 /* delete unnecessary logs */
1668         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1669         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1670         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1671         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1672         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1673         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1674         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1675         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1676         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1677         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1678         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1679         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1680         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1681         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1682         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1683         #endif
1684
1685         default:
1686                 break;
1687         }
1688
1689         /* should not call 'gst_message_unref(msg)' */
1690         return;
1691 }
1692
1693 static gboolean
1694 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1695 {
1696         gint64 bytes = 0;
1697
1698         MMPLAYER_FENTER();
1699
1700         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1701         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1702
1703         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1704                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1705                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1706
1707                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1708                         LOGD("data total size of http content: %lld", bytes);
1709                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1710                 }
1711         } else
1712                 /* handling audio clip which has vbr. means duration is keep changing */
1713                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1714
1715         MMPLAYER_FLEAVE();
1716
1717         return TRUE;
1718 }
1719
1720 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1721                 mm_player_spherical_metadata_t *metadata) {
1722         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1723         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1724         gst_tag_list_get_string(tags, "stitching_software",
1725                         &metadata->stitching_software);
1726         gst_tag_list_get_string(tags, "projection_type",
1727                         &metadata->projection_type_string);
1728         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1729         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1730         gst_tag_list_get_int(tags, "init_view_heading",
1731                         &metadata->init_view_heading);
1732         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1733         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1734         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1735         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1736                         &metadata->full_pano_width_pixels);
1737         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1738                         &metadata->full_pano_height_pixels);
1739         gst_tag_list_get_int(tags, "cropped_area_image_width",
1740                         &metadata->cropped_area_image_width);
1741         gst_tag_list_get_int(tags, "cropped_area_image_height",
1742                         &metadata->cropped_area_image_height);
1743         gst_tag_list_get_int(tags, "cropped_area_left",
1744                         &metadata->cropped_area_left);
1745         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1746         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1747         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1748         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1749 }
1750
1751 static gboolean
1752 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1753 {
1754
1755 /* macro for better code readability */
1756 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1757 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1758         if (string != NULL) { \
1759                 SECURE_LOGD("update tag string : %s\n", string); \
1760                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1761                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1762                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1763                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1764                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1765                         g_free(new_string); \
1766                         new_string = NULL; \
1767                 } else { \
1768                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1769                 } \
1770                 g_free(string); \
1771                 string = NULL; \
1772         } \
1773 }
1774
1775 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1776 do {    \
1777         GstSample *sample = NULL;\
1778         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1779                 GstMapInfo info = GST_MAP_INFO_INIT;\
1780                 buffer = gst_sample_get_buffer(sample);\
1781                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1782                         LOGD("failed to get image data from tag");\
1783                         gst_sample_unref(sample);\
1784                         return FALSE;\
1785                 } \
1786                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1787                 MMPLAYER_FREEIF(player->album_art);\
1788                 player->album_art = (gchar *)g_malloc(info.size);\
1789                 if (player->album_art) {\
1790                         memcpy(player->album_art, info.data, info.size);\
1791                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1792                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1793                                 msg_param.data = (void *)player->album_art;\
1794                                 msg_param.size = info.size;\
1795                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1796                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1797                         } \
1798                 } \
1799                 gst_buffer_unmap(buffer, &info);\
1800                 gst_sample_unref(sample);\
1801         }       \
1802 } while (0)
1803
1804 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1805 do {    \
1806         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1807                 if (v_uint) { \
1808                         int i = 0; \
1809                         gchar *tag_list_str = NULL; \
1810                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1811                         tag_list_str = gst_tag_list_to_string(tag_list); \
1812                         if (tag_list_str && strstr(tag_list_str, "audio")) \
1813                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1814                         else if (tag_list_str && strstr(tag_list_str, "video")) \
1815                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1816                         else \
1817                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1818                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1819                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1820                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1821                                 player->bitrate[track_type] = v_uint; \
1822                                 player->total_bitrate = 0; \
1823                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1824                                         player->total_bitrate += player->bitrate[i]; \
1825                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1826                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1827                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1828                                 player->maximum_bitrate[track_type] = v_uint; \
1829                                 player->total_maximum_bitrate = 0; \
1830                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1831                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1832                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1833                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1834                         } else { \
1835                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1836                         } \
1837                         v_uint = 0;\
1838                         g_free(tag_list_str); \
1839                 } \
1840         } \
1841 } while (0)
1842
1843 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1844 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1845         if (date != NULL) {\
1846                 string = g_strdup_printf("%d", g_date_get_year(date));\
1847                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1848                 SECURE_LOGD("metainfo year : %s\n", string);\
1849                 MMPLAYER_FREEIF(string);\
1850                 g_date_free(date);\
1851         } \
1852 }
1853
1854 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1856         if (datetime != NULL) {\
1857                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1858                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1859                 SECURE_LOGD("metainfo year : %s\n", string);\
1860                 MMPLAYER_FREEIF(string);\
1861                 gst_date_time_unref(datetime);\
1862         } \
1863 }
1864
1865 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1866 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1867         if (v_uint64) {\
1868                 /* FIXIT : don't know how to store date */\
1869                 g_assert(1);\
1870                 v_uint64 = 0;\
1871         } \
1872 }
1873
1874 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1875 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1876         if (v_double) {\
1877                 /* FIXIT : don't know how to store date */\
1878                 g_assert(1);\
1879                 v_double = 0;\
1880         } \
1881 }
1882
1883         /* function start */
1884         GstTagList* tag_list = NULL;
1885
1886         MMHandleType attrs = 0;
1887
1888         char *string = NULL;
1889         guint v_uint = 0;
1890         GDate *date = NULL;
1891         GstDateTime *datetime = NULL;
1892         /* album cover */
1893         GstBuffer *buffer = NULL;
1894         gint index = 0;
1895         MMMessageParamType msg_param = {0, };
1896
1897         /* currently not used. but those are needed for above macro */
1898         //guint64 v_uint64 = 0;
1899         //gdouble v_double = 0;
1900
1901         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1902
1903         attrs = MMPLAYER_GET_ATTRS(player);
1904
1905         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1906
1907         /* get tag list from gst message */
1908         gst_message_parse_tag(msg, &tag_list);
1909
1910         /* store tags to player attributes */
1911         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1912         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1913         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1914         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1915         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1916         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1917         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1918         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1919         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1920         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1922         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1923         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1924         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1925         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1926         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1927         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1928         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1929         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1930         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1931         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1932         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1933         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1934         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1937         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1938         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1939         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1940         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1941         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1942         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1943         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1944         MMPLAYER_UPDATE_TAG_LOCK(player);
1945         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1946         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1947         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1948         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1949         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1950         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1951         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1952         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1953         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1954         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1955         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1956         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1957         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1958         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1959         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1960
1961         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1962                 if (player->video360_metadata.is_spherical == -1) {
1963                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1964                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1965                                         player->video360_metadata.is_spherical);
1966                         if (player->video360_metadata.is_spherical == 1) {
1967                                 LOGD("This is spherical content for 360 playback.");
1968                                 player->is_content_spherical = TRUE;
1969                         } else {
1970                                 LOGD("This is not spherical content");
1971                                 player->is_content_spherical = FALSE;
1972                         }
1973
1974                         if (player->video360_metadata.projection_type_string) {
1975                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1976                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1977                                 } else {
1978                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1979                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1980                                 }
1981                         }
1982
1983                         if (player->video360_metadata.stereo_mode_string) {
1984                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1985                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1986                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1987                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1988                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1989                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1990                                 } else {
1991                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1992                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1993                                 }
1994                         }
1995                 }
1996         }
1997
1998         if (mmf_attrs_commit(attrs))
1999                 LOGE("failed to commit.\n");
2000
2001         gst_tag_list_free(tag_list);
2002
2003         return TRUE;
2004 }
2005
2006 static void
2007 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2008 {
2009         mm_player_t* player = (mm_player_t*) data;
2010
2011         MMPLAYER_FENTER();
2012
2013         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2014           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2015           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2016           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2017
2018           * [1] audio and video will be dumped with filesink.
2019           * [2] autoplugging is done by just using pad caps.
2020           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2021           * and the video will be dumped via filesink.
2022           */
2023         if (player->num_dynamic_pad == 0) {
2024                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2025
2026                 if (!__mmplayer_gst_remove_fakesink(player,
2027                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2028                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2029                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2030                          * source element are not same. To overcome this situation, this function will called
2031                          * several places and several times. Therefore, this is not an error case.
2032                          */
2033                         return;
2034         }
2035
2036         /* create dot before error-return. for debugging */
2037         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2038
2039         player->no_more_pad = TRUE;
2040
2041         MMPLAYER_FLEAVE();
2042 }
2043
2044 static gboolean
2045 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2046 {
2047         GstElement* parent = NULL;
2048
2049         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2050
2051         /* if we have no fakesink. this meas we are using decodebin which doesn'
2052         t need to add extra fakesink */
2053         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2054
2055         /* lock */
2056         MMPLAYER_FSINK_LOCK(player);
2057
2058         if (!fakesink->gst)
2059                 goto ERROR;
2060
2061         /* get parent of fakesink */
2062         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2063         if (!parent) {
2064                 LOGD("fakesink already removed\n");
2065                 goto ERROR;
2066         }
2067
2068         gst_element_set_locked_state(fakesink->gst, TRUE);
2069
2070         /* setting the state to NULL never returns async
2071          * so no need to wait for completion of state transiton
2072          */
2073         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2074                 LOGE("fakesink state change failure!\n");
2075                 /* FIXIT : should I return here? or try to proceed to next? */
2076                 /* return FALSE; */
2077
2078         /* remove fakesink from it's parent */
2079         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2080                 LOGE("failed to remove fakesink\n");
2081
2082                 gst_object_unref(parent);
2083
2084                 goto ERROR;
2085         }
2086
2087         gst_object_unref(parent);
2088
2089         LOGD("state-holder removed\n");
2090
2091         gst_element_set_locked_state(fakesink->gst, FALSE);
2092
2093         MMPLAYER_FSINK_UNLOCK(player);
2094         return TRUE;
2095
2096 ERROR:
2097         if (fakesink->gst)
2098                 gst_element_set_locked_state(fakesink->gst, FALSE);
2099
2100         MMPLAYER_FSINK_UNLOCK(player);
2101         return FALSE;
2102 }
2103
2104
2105 static void
2106 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2107 {
2108         GstPad *sinkpad = NULL;
2109         GstCaps* caps = NULL;
2110         GstElement* new_element = NULL;
2111         GstStructure* str = NULL;
2112         const gchar* name = NULL;
2113
2114         mm_player_t* player = (mm_player_t*) data;
2115
2116         MMPLAYER_FENTER();
2117
2118         MMPLAYER_RETURN_IF_FAIL(element && pad);
2119         MMPLAYER_RETURN_IF_FAIL(player &&
2120                                         player->pipeline &&
2121                                         player->pipeline->mainbin);
2122
2123
2124         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2125          * num_dynamic_pad will decreased after creating a sinkbin.
2126          */
2127         player->num_dynamic_pad++;
2128         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2129
2130         caps = gst_pad_query_caps(pad, NULL);
2131
2132         MMPLAYER_CHECK_NULL(caps);
2133
2134         /* clear  previous result*/
2135         player->have_dynamic_pad = FALSE;
2136
2137         str = gst_caps_get_structure(caps, 0);
2138
2139         if (!str) {
2140                 LOGE("cannot get structure from caps.\n");
2141                 goto ERROR;
2142         }
2143
2144         name = gst_structure_get_name(str);
2145         if (!name) {
2146                 LOGE("cannot get mimetype from structure.\n");
2147                 goto ERROR;
2148         }
2149
2150         if (strstr(name, "video")) {
2151                 gint stype = 0;
2152                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2153
2154                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2155                         if (player->v_stream_caps) {
2156                                 gst_caps_unref(player->v_stream_caps);
2157                                 player->v_stream_caps = NULL;
2158                         }
2159
2160                         new_element = gst_element_factory_make("fakesink", NULL);
2161                         player->num_dynamic_pad--;
2162                         goto NEW_ELEMENT;
2163                 }
2164         }
2165
2166         /* clear  previous result*/
2167         player->have_dynamic_pad = FALSE;
2168
2169         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2170                 LOGE("failed to autoplug for caps");
2171                 goto ERROR;
2172         }
2173
2174         /* check if there's dynamic pad*/
2175         if (player->have_dynamic_pad) {
2176                 LOGE("using pad caps assums there's no dynamic pad !\n");
2177                 goto ERROR;
2178         }
2179
2180         gst_caps_unref(caps);
2181         caps = NULL;
2182
2183 NEW_ELEMENT:
2184
2185         /* excute new_element if created*/
2186         if (new_element) {
2187                 LOGD("adding new element to pipeline\n");
2188
2189                 /* set state to READY before add to bin */
2190                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2191
2192                 /* add new element to the pipeline */
2193                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2194                         LOGE("failed to add autoplug element to bin\n");
2195                         goto ERROR;
2196                 }
2197
2198                 /* get pad from element */
2199                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2200                 if (!sinkpad) {
2201                         LOGE("failed to get sinkpad from autoplug element\n");
2202                         goto ERROR;
2203                 }
2204
2205                 /* link it */
2206                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2207                         LOGE("failed to link autoplug element\n");
2208                         goto ERROR;
2209                 }
2210
2211                 gst_object_unref(sinkpad);
2212                 sinkpad = NULL;
2213
2214                 /* run. setting PLAYING here since streamming source is live source */
2215                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2216         }
2217
2218         if (caps)
2219                 gst_caps_unref(caps);
2220
2221         MMPLAYER_FLEAVE();
2222
2223         return;
2224
2225 STATE_CHANGE_FAILED:
2226 ERROR:
2227         /* FIXIT : take care if new_element has already added to pipeline */
2228         if (new_element)
2229                 gst_object_unref(GST_OBJECT(new_element));
2230
2231         if (sinkpad)
2232                 gst_object_unref(GST_OBJECT(sinkpad));
2233
2234         if (caps)
2235                 gst_caps_unref(caps);
2236
2237         /* FIXIT : how to inform this error to MSL ????? */
2238         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2239          * then post an error to application
2240          */
2241 }
2242
2243 static GstPadProbeReturn
2244 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2245 {
2246         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2247         return GST_PAD_PROBE_OK;
2248 }
2249
2250 static GstPadProbeReturn
2251 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2252 {
2253         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2254         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2255         mm_player_t* player = (mm_player_t*)data;
2256         GstCaps* caps = NULL;
2257         GstStructure* str = NULL;
2258         const gchar* name = NULL;
2259         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2260
2261
2262         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2263                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2264                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2265                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2266                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2267                         return ret;
2268         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2269                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2270                         return ret;
2271         }
2272
2273         caps = gst_pad_query_caps(pad, NULL);
2274         if (!caps) {
2275                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2276                 return ret;
2277         }
2278
2279         str = gst_caps_get_structure(caps, 0);
2280         if (!str) {
2281                 LOGE("failed to get structure from caps");
2282                 goto ERROR;
2283         }
2284
2285         name = gst_structure_get_name(str);
2286         if (!name) {
2287                 LOGE("failed to get name from str");
2288                 goto ERROR;
2289         }
2290
2291         if (strstr(name, "audio")) {
2292                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2293         } else if (strstr(name, "video")) {
2294                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2295         } else {
2296                 /* text track is not supportable */
2297                 LOGE("invalid name %s", name);
2298                 goto ERROR;
2299         }
2300
2301         switch (GST_EVENT_TYPE(event)) {
2302         case GST_EVENT_EOS:
2303                 {
2304                         /* in case of gapless, drop eos event not to send it to sink */
2305                         if (player->gapless.reconfigure && !player->msg_posted) {
2306                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2307                                 ret = GST_PAD_PROBE_DROP;
2308                         }
2309                         break;
2310                 }
2311         case GST_EVENT_STREAM_START:
2312                 {
2313                         gint64 stop_running_time = 0;
2314                         gint64 position_running_time = 0;
2315                         gint64 position = 0;
2316                         gint idx = 0;
2317
2318                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2319                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2320                                         !(player->selector[idx].event_probe_id)) {
2321                                         /* LOGW("[%d] skip", idx); */
2322                                         continue;
2323                                 }
2324
2325                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2326                                         stop_running_time =
2327                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2328                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2329                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2330                                         stop_running_time =
2331                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2332                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2333                                 } else {
2334                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2335                                         stop_running_time =
2336                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2337                                                                 GST_FORMAT_TIME, player->duration);
2338                                 }
2339
2340                                 position_running_time =
2341                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2342                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2343
2344                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2345                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2346                                         idx,
2347                                         GST_TIME_ARGS(stop_running_time),
2348                                         GST_TIME_ARGS(position_running_time),
2349                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2350                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2351
2352                                 position_running_time = MAX(position_running_time, stop_running_time);
2353                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2354                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2355                                 position_running_time = MAX(0, position_running_time);
2356                                 position = MAX(position, position_running_time);
2357                         }
2358
2359                         if (position != 0) {
2360                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2361                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2362                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2363
2364                                 player->gapless.start_time[stream_type] += position;
2365                         }
2366                         break;
2367                 }
2368         case GST_EVENT_FLUSH_STOP:
2369                 {
2370                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2371                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2372                         player->gapless.start_time[stream_type] = 0;
2373                         break;
2374                 }
2375         case GST_EVENT_SEGMENT:
2376                 {
2377                         GstSegment segment;
2378                         GstEvent *tmpev;
2379
2380                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2381                         gst_event_copy_segment(event, &segment);
2382
2383                         if (segment.format == GST_FORMAT_TIME) {
2384                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2385                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2386                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2387                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2388                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2389                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2390
2391                                 /* keep the all the segment ev to cover the seeking */
2392                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2393                                 player->gapless.update_segment[stream_type] = TRUE;
2394
2395                                 if (!player->gapless.running)
2396                                         break;
2397
2398                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2399
2400                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2401
2402                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2403                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2404                                 gst_event_unref(event);
2405                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2406                         }
2407                         break;
2408                 }
2409         case GST_EVENT_QOS:
2410                 {
2411                         gdouble proportion = 0.0;
2412                         GstClockTimeDiff diff = 0;
2413                         GstClockTime timestamp = 0;
2414                         gint64 running_time_diff = -1;
2415                         GstQOSType type = 0;
2416                         GstEvent *tmpev = NULL;
2417
2418                         running_time_diff = player->gapless.segment[stream_type].base;
2419
2420                         if (running_time_diff <= 0) /* don't need to adjust */
2421                                 break;
2422
2423                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2424                         gst_event_unref(event);
2425
2426                         if (timestamp < running_time_diff) {
2427                                 LOGW("QOS event from previous group");
2428                                 ret = GST_PAD_PROBE_DROP;
2429                                 break;
2430                         }
2431
2432                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2433                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2434                                                 stream_type, GST_TIME_ARGS(timestamp),
2435                                                 GST_TIME_ARGS(running_time_diff),
2436                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2437
2438                         timestamp -= running_time_diff;
2439
2440                         /* That case is invalid for QoS events */
2441                         if (diff < 0 && -diff > timestamp) {
2442                                 LOGW("QOS event from previous group");
2443                                 ret = GST_PAD_PROBE_DROP;
2444                                 break;
2445                         }
2446
2447                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2448                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2449
2450                         break;
2451                 }
2452         default:
2453                 break;
2454         }
2455
2456 ERROR:
2457         if (caps)
2458                 gst_caps_unref(caps);
2459         return ret;
2460 }
2461
2462 static void
2463 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2464 {
2465         mm_player_t* player = NULL;
2466         GstElement* pipeline = NULL;
2467         GstElement* selector = NULL;
2468         GstElement* fakesink = NULL;
2469         GstCaps* caps = NULL;
2470         GstStructure* str = NULL;
2471         const gchar* name = NULL;
2472         GstPad* sinkpad = NULL;
2473         GstPad* srcpad = NULL;
2474         gboolean first_track = FALSE;
2475
2476         enum MainElementID elemId = MMPLAYER_M_NUM;
2477         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2478
2479         /* check handles */
2480         player = (mm_player_t*)data;
2481
2482         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2483         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2484
2485         //LOGD("pad-added signal handling\n");
2486
2487         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2488
2489         /* get mimetype from caps */
2490         caps = gst_pad_query_caps(pad, NULL);
2491         if (!caps) {
2492                 LOGE("cannot get caps from pad.\n");
2493                 goto ERROR;
2494         }
2495
2496         str = gst_caps_get_structure(caps, 0);
2497         if (!str) {
2498                 LOGE("cannot get structure from caps.\n");
2499                 goto ERROR;
2500         }
2501
2502         name = gst_structure_get_name(str);
2503         if (!name) {
2504                 LOGE("cannot get mimetype from structure.\n");
2505                 goto ERROR;
2506         }
2507
2508         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2509         //LOGD("detected mimetype : %s\n", name);
2510
2511         if (strstr(name, "video")) {
2512                 gint stype = 0;
2513
2514                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2515                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2516
2517                 /* don't make video because of not required, and not support multiple track */
2518                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2519                         LOGD("no video sink by null surface");
2520
2521                         gchar *caps_str = gst_caps_to_string(caps);
2522                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2523                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2524                                 player->set_mode.video_zc = TRUE;
2525
2526                         MMPLAYER_FREEIF(caps_str);
2527
2528                         if (player->v_stream_caps) {
2529                                 gst_caps_unref(player->v_stream_caps);
2530                                 player->v_stream_caps = NULL;
2531                         }
2532
2533                         LOGD("create fakesink instead of videobin");
2534
2535                         /* fake sink */
2536                         fakesink = gst_element_factory_make("fakesink", NULL);
2537                         if (fakesink == NULL) {
2538                                 LOGE("ERROR : fakesink create error\n");
2539                                 goto ERROR;
2540                         }
2541
2542                         if (player->ini.set_dump_element_flag)
2543                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2544
2545                         player->video_fakesink = fakesink;
2546
2547                         /* store it as it's sink element */
2548                         __mmplayer_add_sink(player, player->video_fakesink);
2549
2550                         gst_bin_add(GST_BIN(pipeline), fakesink);
2551
2552                         // link
2553                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2554
2555                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2556                                 LOGW("failed to link fakesink\n");
2557                                 gst_object_unref(GST_OBJECT(fakesink));
2558                                 goto ERROR;
2559                         }
2560
2561                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2562                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2563                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2564                         }
2565
2566                         if (player->set_mode.media_packet_video_stream) {
2567                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2568
2569                                 MMPLAYER_SIGNAL_CONNECT(player,
2570                                                                                 G_OBJECT(fakesink),
2571                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2572                                                                                 "handoff",
2573                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2574                                                                                 (gpointer)player);
2575
2576                                 MMPLAYER_SIGNAL_CONNECT(player,
2577                                                                                 G_OBJECT(fakesink),
2578                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2579                                                                                 "preroll-handoff",
2580                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2581                                                                                 (gpointer)player);
2582                         }
2583
2584                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2585                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2586                         goto DONE;
2587                 }
2588
2589                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2590                         __mmplayer_gst_decode_callback(elem, pad, player);
2591                         goto DONE;
2592                 }
2593
2594                 LOGD("video selector \n");
2595                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2596                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2597         } else {
2598                 if (strstr(name, "audio")) {
2599                         gint samplerate = 0;
2600                         gint channels = 0;
2601
2602                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2603                                 __mmplayer_gst_decode_callback(elem, pad, player);
2604                                 goto DONE;
2605                         }
2606
2607                         LOGD("audio selector \n");
2608                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2609                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2610
2611                         gst_structure_get_int(str, "rate", &samplerate);
2612                         gst_structure_get_int(str, "channels", &channels);
2613
2614                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2615                                 /* fake sink */
2616                                 fakesink = gst_element_factory_make("fakesink", NULL);
2617                                 if (fakesink == NULL) {
2618                                         LOGE("ERROR : fakesink create error\n");
2619                                         goto ERROR;
2620                                 }
2621
2622                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2623
2624                                 /* link */
2625                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2626
2627                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2628                                         LOGW("failed to link fakesink\n");
2629                                         gst_object_unref(GST_OBJECT(fakesink));
2630                                         goto ERROR;
2631                                 }
2632
2633                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2634                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2635                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2636
2637                                 goto DONE;
2638                         }
2639                 } else if (strstr(name, "text")) {
2640                         LOGD("text selector \n");
2641                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2642                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2643                 } else {
2644                         LOGE("wrong elem id \n");
2645                         goto ERROR;
2646                 }
2647         }
2648
2649         selector = player->pipeline->mainbin[elemId].gst;
2650         if (selector == NULL) {
2651                 selector = gst_element_factory_make("input-selector", NULL);
2652                 LOGD("Creating input-selector\n");
2653                 if (selector == NULL) {
2654                         LOGE("ERROR : input-selector create error\n");
2655                         goto ERROR;
2656                 }
2657                 g_object_set(selector, "sync-streams", TRUE, NULL);
2658
2659                 player->pipeline->mainbin[elemId].id = elemId;
2660                 player->pipeline->mainbin[elemId].gst = selector;
2661
2662                 first_track = TRUE;
2663                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2664
2665                 srcpad = gst_element_get_static_pad(selector, "src");
2666
2667                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2668                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2669                         __mmplayer_gst_selector_blocked, NULL, NULL);
2670                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2671                         __mmplayer_gst_selector_event_probe, player, NULL);
2672
2673                 gst_element_set_state(selector, GST_STATE_PAUSED);
2674                 gst_bin_add(GST_BIN(pipeline), selector);
2675         } else
2676                 LOGD("input-selector is already created.\n");
2677
2678         // link
2679         LOGD("Calling request pad with selector %p \n", selector);
2680         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2681
2682         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2683
2684         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2685                 LOGW("failed to link selector\n");
2686                 gst_object_unref(GST_OBJECT(selector));
2687                 goto ERROR;
2688         }
2689
2690         if (first_track) {
2691                 LOGD("this is first track --> active track \n");
2692                 g_object_set(selector, "active-pad", sinkpad, NULL);
2693         }
2694
2695         _mmplayer_track_update_info(player, stream_type, sinkpad);
2696
2697
2698 DONE:
2699 ERROR:
2700
2701         if (caps)
2702                 gst_caps_unref(caps);
2703
2704         if (sinkpad) {
2705                 gst_object_unref(GST_OBJECT(sinkpad));
2706                 sinkpad = NULL;
2707         }
2708
2709         if (srcpad) {
2710                 gst_object_unref(GST_OBJECT(srcpad));
2711                 srcpad = NULL;
2712         }
2713
2714         return;
2715 }
2716
2717 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2718 {
2719         GstPad* srcpad = NULL;
2720         MMHandleType attrs = 0;
2721         gint active_index = 0;
2722
2723         // [link] input-selector :: textbin
2724         srcpad = gst_element_get_static_pad(text_selector, "src");
2725         if (!srcpad) {
2726                 LOGE("failed to get srcpad from selector\n");
2727                 return;
2728         }
2729
2730         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2731
2732         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2733         if ((active_index != DEFAULT_TRACK) &&
2734                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2735                 LOGW("failed to change text track\n");
2736                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2737         }
2738
2739         player->no_more_pad = TRUE;
2740         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2741
2742         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2743         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2744                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2745                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2746         }
2747
2748         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2749
2750         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2751                 player->has_closed_caption = TRUE;
2752
2753         attrs = MMPLAYER_GET_ATTRS(player);
2754         if (attrs) {
2755                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2756                 if (mmf_attrs_commit(attrs))
2757                         LOGE("failed to commit.\n");
2758         } else
2759                 LOGE("cannot get content attribute");
2760
2761         if (srcpad) {
2762                 gst_object_unref(GST_OBJECT(srcpad));
2763                 srcpad = NULL;
2764         }
2765 }
2766
2767 static void
2768 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2769 {
2770         mm_player_t* player = (mm_player_t*)data;
2771         GstElement* selector = NULL;
2772         GstElement* queue = NULL;
2773
2774         GstPad* srcpad = NULL;
2775         GstPad* sinkpad = NULL;
2776         GstCaps* caps = NULL;
2777         gchar* caps_str = NULL;
2778
2779         MMPLAYER_FENTER();
2780         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2781
2782         caps = gst_pad_get_current_caps(pad);
2783         caps_str = gst_caps_to_string(caps);
2784         LOGD("deinterleave new caps : %s\n", caps_str);
2785         MMPLAYER_FREEIF(caps_str);
2786         gst_caps_unref(caps);
2787
2788         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2789                 LOGE("ERROR : queue create error\n");
2790                 goto ERROR;
2791         }
2792
2793         g_object_set(G_OBJECT(queue),
2794                                 "max-size-buffers", 10,
2795                                 "max-size-bytes", 0,
2796                                 "max-size-time", (guint64)0,
2797                                 NULL);
2798
2799         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2800
2801         if (!selector) {
2802                 LOGE("there is no audio channel selector.\n");
2803                 goto ERROR;
2804         }
2805
2806         srcpad = gst_element_get_static_pad(queue, "src");
2807         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2808
2809         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2810
2811         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2812                 LOGW("failed to link deinterleave - selector\n");
2813                 goto ERROR;
2814         }
2815
2816         gst_element_set_state(queue, GST_STATE_PAUSED);
2817         player->audio_mode.total_track_num++;
2818
2819 ERROR:
2820
2821         if (srcpad) {
2822                 gst_object_unref(GST_OBJECT(srcpad));
2823                 srcpad = NULL;
2824         }
2825
2826         if (sinkpad) {
2827                 gst_object_unref(GST_OBJECT(sinkpad));
2828                 sinkpad = NULL;
2829         }
2830
2831         MMPLAYER_FLEAVE();
2832         return;
2833 }
2834
2835 static void
2836 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2837 {
2838         mm_player_t* player = NULL;
2839         GstElement* selector = NULL;
2840         GstPad* sinkpad = NULL;
2841         gint active_index = 0;
2842         gchar* change_pad_name = NULL;
2843         GstCaps* caps = NULL;   // no need to unref
2844         gint default_audio_ch = 0;
2845
2846         MMPLAYER_FENTER();
2847         player = (mm_player_t*) data;
2848
2849         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2850
2851         if (!selector) {
2852                 LOGE("there is no audio channel selector.\n");
2853                 goto ERROR;
2854         }
2855
2856         active_index = player->audio_mode.active_pad_index;
2857
2858         if (active_index != default_audio_ch) {
2859                 gint audio_ch = default_audio_ch;
2860
2861                 /*To get the new pad from the selector*/
2862                 change_pad_name = g_strdup_printf("sink%d", active_index);
2863                 if (change_pad_name != NULL) {
2864                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2865                         if (sinkpad != NULL) {
2866                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2867                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2868
2869                                 audio_ch = active_index;
2870
2871                                 caps = gst_pad_get_current_caps(sinkpad);
2872                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2873
2874                                 __mmplayer_set_audio_attrs(player, caps);
2875                                 gst_caps_unref(caps);
2876                         }
2877                         MMPLAYER_FREEIF(change_pad_name);
2878                 }
2879
2880                 player->audio_mode.active_pad_index = audio_ch;
2881                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2882         }
2883
2884 ERROR:
2885
2886         if (sinkpad)
2887                 gst_object_unref(sinkpad);
2888
2889         MMPLAYER_FLEAVE();
2890         return;
2891 }
2892
2893 static void
2894 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2895 {
2896         mm_player_t* player = NULL;
2897         MMPlayerGstElement *mainbin = NULL;
2898
2899         GstElement* tee = NULL;
2900         GstElement* stereo_queue = NULL;
2901         GstElement* mono_queue = NULL;
2902         GstElement* conv = NULL;
2903         GstElement* filter = NULL;
2904         GstElement* deinterleave = NULL;
2905         GstElement* selector = NULL;
2906
2907         GstPad* srcpad = NULL;
2908         GstPad* selector_srcpad = NULL;
2909         GstPad* sinkpad = NULL;
2910         GstCaps* caps = NULL;
2911         gulong block_id = 0;
2912
2913         MMPLAYER_FENTER();
2914
2915         /* check handles */
2916         player = (mm_player_t*) data;
2917
2918         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2919         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2920
2921         mainbin = player->pipeline->mainbin;
2922
2923         /* tee */
2924         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2925                 LOGE("ERROR : tee create error\n");
2926                 goto ERROR;
2927         }
2928
2929         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2930         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2931
2932         gst_element_set_state(tee, GST_STATE_PAUSED);
2933
2934         /* queue */
2935         srcpad = gst_element_get_request_pad(tee, "src_%u");
2936         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2937                 LOGE("ERROR : stereo queue create error\n");
2938                 goto ERROR;
2939         }
2940
2941         g_object_set(G_OBJECT(stereo_queue),
2942                                 "max-size-buffers", 10,
2943                                 "max-size-bytes", 0,
2944                                 "max-size-time", (guint64)0,
2945                                 NULL);
2946
2947         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2948         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2949
2950         if (srcpad) {
2951                 gst_object_unref(GST_OBJECT(srcpad));
2952                 srcpad = NULL;
2953         }
2954
2955         srcpad = gst_element_get_request_pad(tee, "src_%u");
2956
2957         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2958                 LOGE("ERROR : mono queue create error\n");
2959                 goto ERROR;
2960         }
2961
2962         g_object_set(G_OBJECT(mono_queue),
2963                                 "max-size-buffers", 10,
2964                                 "max-size-bytes", 0,
2965                                 "max-size-time", (guint64)0,
2966                                 NULL);
2967
2968         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2969         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2970
2971         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2972         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2973
2974         /* audioconvert */
2975         srcpad = gst_element_get_static_pad(mono_queue, "src");
2976         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2977                 LOGE("ERROR : audioconvert create error\n");
2978                 goto ERROR;
2979         }
2980
2981         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2982         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2983
2984         /* caps filter */
2985         if (srcpad) {
2986                 gst_object_unref(GST_OBJECT(srcpad));
2987                 srcpad = NULL;
2988         }
2989         srcpad = gst_element_get_static_pad(conv, "src");
2990
2991         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2992                 LOGE("ERROR : capsfilter create error\n");
2993                 goto ERROR;
2994         }
2995
2996         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2997         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2998
2999         caps = gst_caps_from_string("audio/x-raw-int, "
3000                                 "width = (int) 16, "
3001                                 "depth = (int) 16, "
3002                                 "channels = (int) 2");
3003
3004         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3005         gst_caps_unref(caps);
3006
3007         gst_element_set_state(conv, GST_STATE_PAUSED);
3008         gst_element_set_state(filter, GST_STATE_PAUSED);
3009
3010         /* deinterleave */
3011         if (srcpad) {
3012                 gst_object_unref(GST_OBJECT(srcpad));
3013                 srcpad = NULL;
3014         }
3015         srcpad = gst_element_get_static_pad(filter, "src");
3016
3017         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3018                 LOGE("ERROR : deinterleave create error\n");
3019                 goto ERROR;
3020         }
3021
3022         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3023
3024         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3025                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3026
3027         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3028                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3029
3030         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3031         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3032
3033         /* selector */
3034         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3035         if (selector == NULL) {
3036                 LOGE("ERROR : audio-selector create error\n");
3037                 goto ERROR;
3038         }
3039
3040         g_object_set(selector, "sync-streams", TRUE, NULL);
3041         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3042
3043         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3044         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3045
3046         selector_srcpad = gst_element_get_static_pad(selector, "src");
3047
3048         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3049         block_id =
3050                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3051                         __mmplayer_gst_selector_blocked, NULL, NULL);
3052
3053         if (srcpad) {
3054                 gst_object_unref(GST_OBJECT(srcpad));
3055                 srcpad = NULL;
3056         }
3057
3058         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3059         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3060
3061         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3062                 LOGW("failed to link queue_stereo - selector\n");
3063                 goto ERROR;
3064         }
3065
3066         player->audio_mode.total_track_num++;
3067
3068         g_object_set(selector, "active-pad", sinkpad, NULL);
3069         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3070         gst_element_set_state(selector, GST_STATE_PAUSED);
3071
3072         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3073
3074 ERROR:
3075
3076         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3077         if (block_id != 0) {
3078                 gst_pad_remove_probe(selector_srcpad, block_id);
3079                 block_id = 0;
3080         }
3081
3082         if (sinkpad) {
3083                 gst_object_unref(GST_OBJECT(sinkpad));
3084                 sinkpad = NULL;
3085         }
3086
3087         if (srcpad) {
3088                 gst_object_unref(GST_OBJECT(srcpad));
3089                 srcpad = NULL;
3090         }
3091
3092         if (selector_srcpad) {
3093                 gst_object_unref(GST_OBJECT(selector_srcpad));
3094                 selector_srcpad = NULL;
3095         }
3096
3097         MMPLAYER_FLEAVE();
3098         return;
3099 }
3100
3101 static void
3102 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3103 {
3104         mm_player_t* player = NULL;
3105         GstPad* srcpad = NULL;
3106         GstElement* video_selector = NULL;
3107         GstElement* audio_selector = NULL;
3108         GstElement* text_selector = NULL;
3109         MMHandleType attrs = 0;
3110         gint active_index = 0;
3111         gint64 dur_bytes = 0L;
3112
3113         player = (mm_player_t*) data;
3114
3115         LOGD("no-more-pad signal handling\n");
3116
3117         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3118                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3119                 LOGW("no need to go more");
3120
3121                 if (player->gapless.reconfigure) {
3122                         player->gapless.reconfigure = FALSE;
3123                         MMPLAYER_PLAYBACK_UNLOCK(player);
3124                 }
3125
3126                 return;
3127         }
3128
3129         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3130                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3131                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3132                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3133                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3134
3135                 if (NULL == player->streamer) {
3136                         LOGW("invalid state for buffering");
3137                         goto ERROR;
3138                 }
3139
3140                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3141                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3142
3143                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3144                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3145
3146                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3147
3148                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3149                         LOGE("fail to get duration.\n");
3150
3151                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3152                 // use file information was already set on Q2 when it was created.
3153                 __mm_player_streaming_set_queue2(player->streamer,
3154                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3155                                                 TRUE,                                                           // use_buffering
3156                                                 buffer_bytes,
3157                                                 init_buffering_time,
3158                                                 1.0,                                                            // low percent
3159                                                 player->ini.http_buffering_limit,       // high percent
3160                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3161                                                 NULL,
3162                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3163         }
3164
3165         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3166         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3167         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3168         if (video_selector) {
3169                 // [link] input-selector :: videobin
3170                 srcpad = gst_element_get_static_pad(video_selector, "src");
3171                 if (!srcpad) {
3172                         LOGE("failed to get srcpad from video selector\n");
3173                         goto ERROR;
3174                 }
3175
3176                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3177                 if (!text_selector && !audio_selector)
3178                         player->no_more_pad = TRUE;
3179
3180                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3181
3182                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3183                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3184                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3185                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3186                 }
3187         }
3188
3189         if (audio_selector) {
3190                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3191                 if ((active_index != DEFAULT_TRACK) &&
3192                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3193                         LOGW("failed to change audio track\n");
3194                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3195                 }
3196
3197                 // [link] input-selector :: audiobin
3198                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3199                 if (!srcpad) {
3200                         LOGE("failed to get srcpad from selector\n");
3201                         goto ERROR;
3202                 }
3203
3204                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3205                 if (!text_selector)
3206                         player->no_more_pad = TRUE;
3207
3208                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3209                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3210                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3211                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3212                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3213                         }
3214
3215                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3216                 } else {
3217                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3218
3219                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3220                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3221                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3222                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3223                         }
3224                 }
3225
3226                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3227
3228                 attrs = MMPLAYER_GET_ATTRS(player);
3229                 if (attrs) {
3230                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3231                         if (mmf_attrs_commit(attrs))
3232                                 LOGE("failed to commit.\n");
3233                 } else
3234                         LOGE("cannot get content attribute");
3235         } else {
3236                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3237                         LOGD("There is no audio track : remove audiobin");
3238
3239                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3240                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3241
3242                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3243                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3244                 }
3245
3246                 if (player->num_dynamic_pad == 0)
3247                         __mmplayer_pipeline_complete(NULL, player);
3248         }
3249
3250         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3251                 if (text_selector)
3252                         __mmplayer_handle_text_decode_path(player, text_selector);
3253         }
3254
3255         MMPLAYER_FLEAVE();
3256
3257 ERROR:
3258         if (srcpad) {
3259                 gst_object_unref(GST_OBJECT(srcpad));
3260                 srcpad = NULL;
3261         }
3262
3263         if (player->gapless.reconfigure) {
3264                 player->gapless.reconfigure = FALSE;
3265                 MMPLAYER_PLAYBACK_UNLOCK(player);
3266         }
3267 }
3268
3269 static void
3270 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3271 {
3272         mm_player_t* player = NULL;
3273         MMHandleType attrs = 0;
3274         GstElement* pipeline = NULL;
3275         GstCaps* caps = NULL;
3276         gchar* caps_str = NULL;
3277         GstStructure* str = NULL;
3278         const gchar* name = NULL;
3279         GstPad* sinkpad = NULL;
3280         GstElement* sinkbin = NULL;
3281         gboolean reusing = FALSE;
3282         GstElement *text_selector = NULL;
3283
3284         /* check handles */
3285         player = (mm_player_t*) data;
3286
3287         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3288         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3289
3290         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3291
3292         attrs = MMPLAYER_GET_ATTRS(player);
3293         if (!attrs) {
3294                 LOGE("cannot get content attribute\n");
3295                 goto ERROR;
3296         }
3297
3298         /* get mimetype from caps */
3299         caps = gst_pad_query_caps(pad, NULL);
3300         if (!caps) {
3301                 LOGE("cannot get caps from pad.\n");
3302                 goto ERROR;
3303         }
3304         caps_str = gst_caps_to_string(caps);
3305
3306         str = gst_caps_get_structure(caps, 0);
3307         if (!str) {
3308                 LOGE("cannot get structure from caps.\n");
3309                 goto ERROR;
3310         }
3311
3312         name = gst_structure_get_name(str);
3313         if (!name) {
3314                 LOGE("cannot get mimetype from structure.\n");
3315                 goto ERROR;
3316         }
3317
3318         //LOGD("detected mimetype : %s\n", name);
3319
3320         if (strstr(name, "audio")) {
3321                 if (player->pipeline->audiobin == NULL) {
3322                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3323                                 LOGE("failed to create audiobin. continuing without audio\n");
3324                                 goto ERROR;
3325                         }
3326
3327                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3328                         LOGD("creating audiosink bin success\n");
3329                 } else {
3330                         reusing = TRUE;
3331                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3332                         LOGD("reusing audiobin\n");
3333                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3334                 }
3335
3336                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3337                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3338
3339                 player->audiosink_linked  = 1;
3340
3341                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3342                 if (!sinkpad) {
3343                         LOGE("failed to get pad from sinkbin\n");
3344                         goto ERROR;
3345                 }
3346         } else if (strstr(name, "video")) {
3347                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3348                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3349                         player->set_mode.video_zc = TRUE;
3350
3351                 if (player->pipeline->videobin == NULL) {
3352                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3353                         /* get video surface type */
3354                         int surface_type = 0;
3355                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3356                         LOGD("display_surface_type(%d)\n", surface_type);
3357
3358                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3359                                 LOGD("not make videobin because it dose not want\n");
3360                                 goto ERROR;
3361                         }
3362
3363                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3364                                 /* mark video overlay for acquire */
3365                                 if (player->video_overlay_resource == NULL) {
3366                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3367                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3368                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3369                                                         &player->video_overlay_resource)
3370                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3371                                                 LOGE("could not mark video_overlay resource for acquire\n");
3372                                                 goto ERROR;
3373                                         }
3374                                 }
3375                         }
3376
3377                         player->interrupted_by_resource = FALSE;
3378                         /* acquire resources for video overlay */
3379                         if (mm_resource_manager_commit(player->resource_manager) !=
3380                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3381                                 LOGE("could not acquire resources for video playing\n");
3382                                 goto ERROR;
3383                         }
3384
3385                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3386                                 LOGE("failed to create videobin. continuing without video\n");
3387                                 goto ERROR;
3388                         }
3389
3390                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3391                         LOGD("creating videosink bin success\n");
3392                 } else {
3393                         reusing = TRUE;
3394                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3395                         LOGD("re-using videobin\n");
3396                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3397                 }
3398
3399                 player->videosink_linked  = 1;
3400
3401                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3402                 if (!sinkpad) {
3403                         LOGE("failed to get pad from sinkbin\n");
3404                         goto ERROR;
3405                 }
3406         } else if (strstr(name, "text")) {
3407                 if (player->pipeline->textbin == NULL) {
3408                         MMPlayerGstElement* mainbin = NULL;
3409
3410                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3411                                 LOGE("failed to create text sink bin. continuing without text\n");
3412                                 goto ERROR;
3413                         }
3414
3415                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3416                         LOGD("creating textsink bin success\n");
3417
3418                         /* FIXIT : track number shouldn't be hardcoded */
3419                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3420
3421                         player->textsink_linked  = 1;
3422                         LOGI("player->textsink_linked set to 1\n");
3423
3424                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3425                         if (!sinkpad) {
3426                                 LOGE("failed to get pad from sinkbin\n");
3427                                 goto ERROR;
3428                         }
3429
3430                         mainbin = player->pipeline->mainbin;
3431
3432                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3433                                 /* input selector */
3434                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3435                                 if (!text_selector) {
3436                                         LOGE("failed to create subtitle input selector element\n");
3437                                         goto ERROR;
3438                                 }
3439                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3440
3441                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3442                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3443
3444                                 /* warm up */
3445                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3446                                         LOGE("failed to set state(READY) to sinkbin\n");
3447                                         goto ERROR;
3448                                 }
3449
3450                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3451                                         LOGW("failed to add subtitle input selector\n");
3452                                         goto ERROR;
3453                                 }
3454
3455                                 LOGD("created element input-selector");
3456
3457                         } else {
3458                                 LOGD("already having subtitle input selector");
3459                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3460                         }
3461                 } else {
3462                         if (!player->textsink_linked) {
3463                                 LOGD("re-using textbin\n");
3464
3465                                 reusing = TRUE;
3466                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3467
3468                                 player->textsink_linked  = 1;
3469                                 LOGI("player->textsink_linked set to 1\n");
3470                         } else
3471                                 LOGD("ignoring internal subtutle since external subtitle is available");
3472                 }
3473         } else {
3474                 LOGW("unknown type of elementary stream!ignoring it...\n");
3475                 goto ERROR;
3476         }
3477
3478         if (sinkbin) {
3479                 if (!reusing) {
3480                         /* warm up */
3481                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3482                                 LOGE("failed to set state(READY) to sinkbin\n");
3483                                 goto ERROR;
3484                         }
3485
3486                         /* Added for multi audio support to avoid adding audio bin again*/
3487                         /* add */
3488                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3489                                 LOGE("failed to add sinkbin to pipeline\n");
3490                                 goto ERROR;
3491                         }
3492                 }
3493
3494                 /* link */
3495                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3496                         LOGE("failed to get pad from sinkbin\n");
3497                         goto ERROR;
3498                 }
3499
3500                 if (!reusing) {
3501                         /* run */
3502                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3503                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3504                                 goto ERROR;
3505                         }
3506
3507                         if (text_selector) {
3508                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3509                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3510                                         goto ERROR;
3511                                 }
3512                         }
3513                 }
3514
3515                 gst_object_unref(sinkpad);
3516                 sinkpad = NULL;
3517         }
3518
3519         LOGD("[handle: %p] linking sink bin success", player);
3520
3521         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3522          * streaming task. if the task blocked, then buffer will not flow to the next element
3523          *(autoplugging element). so this is special hack for streaming. please try to remove it
3524          */
3525         /* dec stream count. we can remove fakesink if it's zero */
3526         if (player->num_dynamic_pad)
3527                 player->num_dynamic_pad--;
3528
3529         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3530
3531         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3532                 __mmplayer_pipeline_complete(NULL, player);
3533
3534 ERROR:
3535
3536         MMPLAYER_FREEIF(caps_str);
3537
3538         if (caps)
3539                 gst_caps_unref(caps);
3540
3541         if (sinkpad)
3542                 gst_object_unref(GST_OBJECT(sinkpad));
3543
3544         /* flusing out new attributes */
3545         if (mmf_attrs_commit(attrs))
3546                 LOGE("failed to comit attributes\n");
3547
3548         return;
3549 }
3550
3551 static gboolean
3552 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3553 {
3554         int pro_value = 0; // in the case of expection, default will be returned.
3555         int dest_angle = rotation_angle;
3556         int rotation_type = -1;
3557
3558         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3559         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3560         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3561
3562         if (rotation_angle >= 360)
3563                 dest_angle = rotation_angle - 360;
3564
3565         /* chech if supported or not */
3566         if (dest_angle % 90) {
3567                 LOGD("not supported rotation angle = %d", rotation_angle);
3568                 return FALSE;
3569         }
3570
3571         /*
3572           * tizenwlsink (A)
3573           * custom_convert - none (B)
3574           * videoflip - none (C)
3575           */
3576         if (player->set_mode.video_zc) {
3577                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3578                         rotation_type = ROTATION_USING_CUSTOM;
3579                 else // A
3580                         rotation_type = ROTATION_USING_SINK;
3581         } else {
3582                 int surface_type = 0;
3583                 rotation_type = ROTATION_USING_FLIP;
3584
3585                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3586                 LOGD("check display surface type attribute: %d", surface_type);
3587
3588                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3589                         rotation_type = ROTATION_USING_SINK;
3590                 else
3591                         rotation_type = ROTATION_USING_FLIP; //C
3592
3593                 LOGD("using %d type for rotation", rotation_type);
3594         }
3595
3596         /* get property value for setting */
3597         switch (rotation_type) {
3598         case ROTATION_USING_SINK: // tizenwlsink
3599                 {
3600                         switch (dest_angle) {
3601                         case 0:
3602                                 break;
3603                         case 90:
3604                                 pro_value = 3; // clockwise 90
3605                                 break;
3606                         case 180:
3607                                 pro_value = 2;
3608                                 break;
3609                         case 270:
3610                                 pro_value = 1; // counter-clockwise 90
3611                                 break;
3612                         }
3613                 }
3614                 break;
3615         case ROTATION_USING_CUSTOM:
3616                 {
3617                         gchar *ename = NULL;
3618                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3619
3620                         if (g_strrstr(ename, "fimcconvert")) {
3621                                 switch (dest_angle) {
3622                                 case 0:
3623                                         break;
3624                                 case 90:
3625                                         pro_value = 90; // clockwise 90
3626                                         break;
3627                                 case 180:
3628                                         pro_value = 180;
3629                                         break;
3630                                 case 270:
3631                                         pro_value = 270; // counter-clockwise 90
3632                                         break;
3633                                 }
3634                         }
3635                 }
3636                 break;
3637         case ROTATION_USING_FLIP: // videoflip
3638                 {
3639                                 switch (dest_angle) {
3640                                 case 0:
3641                                         break;
3642                                 case 90:
3643                                         pro_value = 1; // clockwise 90
3644                                         break;
3645                                 case 180:
3646                                         pro_value = 2;
3647                                         break;
3648                                 case 270:
3649                                         pro_value = 3; // counter-clockwise 90
3650                                         break;
3651                                 }
3652                 }
3653                 break;
3654         }
3655
3656         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3657
3658         *value = pro_value;
3659
3660         return TRUE;
3661 }
3662
3663 int
3664 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3665 {
3666         /* check video sinkbin is created */
3667         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3668                 player->pipeline &&
3669                 player->pipeline->videobin &&
3670                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3671                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3672                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3673
3674         return MM_ERROR_NONE;
3675 }
3676
3677 void
3678 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3679 {
3680         int rotation_value = 0;
3681         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3682         int user_angle = 0;
3683         MMPLAYER_FENTER();
3684
3685         /* check video sinkbin is created */
3686         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3687                 return;
3688
3689         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3690
3691         /* get rotation value to set */
3692         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3693         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3694         LOGD("set video param : rotate %d", rotation_value);
3695 }
3696
3697 void
3698 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3699 {
3700         MMHandleType attrs = 0;
3701         int visible = 0;
3702         MMPLAYER_FENTER();
3703
3704         /* check video sinkbin is created */
3705         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3706                 return;
3707
3708         attrs = MMPLAYER_GET_ATTRS(player);
3709         MMPLAYER_RETURN_IF_FAIL(attrs);
3710
3711         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3712         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3713         LOGD("set video param : visible %d", visible);
3714 }
3715
3716 void
3717 __mmplayer_video_param_set_display_method(mm_player_t* player)
3718 {
3719         MMHandleType attrs = 0;
3720         int display_method = 0;
3721         MMPLAYER_FENTER();
3722
3723         /* check video sinkbin is created */
3724         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3725                 return;
3726
3727         attrs = MMPLAYER_GET_ATTRS(player);
3728         MMPLAYER_RETURN_IF_FAIL(attrs);
3729
3730         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3731         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3732         LOGD("set video param : method %d", display_method);
3733 }
3734
3735 void
3736 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3737 {
3738         MMHandleType attrs = 0;
3739         void *handle = NULL;
3740         /*set wl_display*/
3741         int wl_window_x = 0;
3742         int wl_window_y = 0;
3743         int wl_window_width = 0;
3744         int wl_window_height = 0;
3745         MMPLAYER_FENTER();
3746
3747         /* check video sinkbin is created */
3748         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3749                 return;
3750
3751         attrs = MMPLAYER_GET_ATTRS(player);
3752         MMPLAYER_RETURN_IF_FAIL(attrs);
3753
3754         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3755
3756         if (handle) {
3757                 /*It should be set after setting window*/
3758                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3759                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3760                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3761                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3762
3763                 /* After setting window handle, set render      rectangle */
3764                 gst_video_overlay_set_render_rectangle(
3765                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3766                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3767                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3768                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3769
3770         }
3771 }
3772 void
3773 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3774 {
3775         MMHandleType attrs = 0;
3776         void *handle = NULL;
3777
3778         /* check video sinkbin is created */
3779         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3780                 return;
3781
3782         attrs = MMPLAYER_GET_ATTRS(player);
3783         MMPLAYER_RETURN_IF_FAIL(attrs);
3784
3785         /* common case if using overlay surface */
3786         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3787
3788         if (handle) {
3789                 /* default is using wl_surface_id */
3790                 unsigned int wl_surface_id      = 0;
3791                 wl_surface_id = *(int*)handle;
3792                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3793                 gst_video_overlay_set_wl_window_wl_surface_id(
3794                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3795                                 *(int*)handle);
3796         } else
3797                 /* FIXIT : is it error case? */
3798                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3799 }
3800
3801
3802 int
3803 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3804 {
3805         bool update_all_param = FALSE;
3806         MMPLAYER_FENTER();
3807
3808         /* check video sinkbin is created */
3809         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3810                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3811
3812         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3813                 LOGE("can not find tizenwlsink");
3814                 return MM_ERROR_PLAYER_INTERNAL;
3815         }
3816
3817         LOGD("param_name : %s", param_name);
3818         if (!g_strcmp0(param_name, "update_all_param"))
3819                 update_all_param = TRUE;
3820
3821         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3822                 __mmplayer_video_param_set_display_overlay(player);
3823         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3824                 __mmplayer_video_param_set_display_method(player);
3825         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3826                 __mmplayer_video_param_set_render_rectangle(player);
3827         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3828                 __mmplayer_video_param_set_display_visible(player);
3829         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3830                 __mmplayer_video_param_set_display_rotation(player);
3831
3832         return MM_ERROR_NONE;
3833 }
3834
3835 int
3836 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3837 {
3838         MMHandleType attrs = 0;
3839         int surface_type = 0;
3840         int ret = MM_ERROR_NONE;
3841
3842         MMPLAYER_FENTER();
3843
3844         /* check video sinkbin is created */
3845         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3846                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3847
3848         attrs = MMPLAYER_GET_ATTRS(player);
3849         if (!attrs) {
3850                 LOGE("cannot get content attribute");
3851                 return MM_ERROR_PLAYER_INTERNAL;
3852         }
3853         LOGD("param_name : %s", param_name);
3854
3855         /* update display surface */
3856         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3857         LOGD("check display surface type attribute: %d", surface_type);
3858
3859         /* configuring display */
3860         switch (surface_type) {
3861         case MM_DISPLAY_SURFACE_OVERLAY:
3862                 {
3863                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3864                         if (ret != MM_ERROR_NONE)
3865                                 return ret;
3866                 }
3867                 break;
3868         }
3869
3870         MMPLAYER_FLEAVE();
3871
3872         return MM_ERROR_NONE;
3873 }
3874
3875 int
3876 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3877 {
3878         gboolean disable_overlay = FALSE;
3879         mm_player_t* player = (mm_player_t*) hplayer;
3880         int ret = MM_ERROR_NONE;
3881
3882         MMPLAYER_FENTER();
3883         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3885                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3886                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3887
3888         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3889                 LOGW("Display control is not supported");
3890                 return MM_ERROR_PLAYER_INTERNAL;
3891         }
3892
3893         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3894
3895         if (audio_only == (bool)disable_overlay) {
3896                 LOGE("It's the same with current setting: (%d)", audio_only);
3897                 return MM_ERROR_NONE;
3898         }
3899
3900         if (audio_only) {
3901                 LOGE("disable overlay");
3902                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3903
3904                 /* release overlay resource */
3905                 if (player->video_overlay_resource != NULL) {
3906                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3907                                         player->video_overlay_resource);
3908                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3909                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3910                                 goto ERROR;
3911                         }
3912                         player->video_overlay_resource = NULL;
3913                 }
3914
3915                 ret = mm_resource_manager_commit(player->resource_manager);
3916                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3917                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3918                         goto ERROR;
3919                 }
3920         } else {
3921                 /* mark video overlay for acquire */
3922                 if (player->video_overlay_resource == NULL) {
3923                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3924                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3925                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3926                                         &player->video_overlay_resource);
3927                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3928                                 LOGE("could not prepare for video_overlay resource\n");
3929                                 goto ERROR;
3930                         }
3931                 }
3932
3933                 player->interrupted_by_resource = FALSE;
3934                 /* acquire resources for video overlay */
3935                 ret = mm_resource_manager_commit(player->resource_manager);
3936                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3937                         LOGE("could not acquire resources for video playing\n");
3938                         goto ERROR;
3939                 }
3940
3941                 LOGD("enable overlay");
3942                 __mmplayer_video_param_set_display_overlay(player);
3943                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3944         }
3945
3946 ERROR:
3947         MMPLAYER_FLEAVE();
3948         return MM_ERROR_NONE;
3949 }
3950
3951 int
3952 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3953 {
3954         mm_player_t* player = (mm_player_t*) hplayer;
3955         gboolean disable_overlay = FALSE;
3956
3957         MMPLAYER_FENTER();
3958
3959         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3960         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3961         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3962                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3963                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3964
3965         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3966                 LOGW("Display control is not supported");
3967                 return MM_ERROR_PLAYER_INTERNAL;
3968         }
3969
3970         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3971
3972         *paudio_only = (bool)(disable_overlay);
3973
3974         LOGD("audio_only : %d", *paudio_only);
3975
3976         MMPLAYER_FLEAVE();
3977
3978         return MM_ERROR_NONE;
3979 }
3980
3981 static int
3982 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3983 {
3984         GList* bucket = element_bucket;
3985         MMPlayerGstElement* element = NULL;
3986         MMPlayerGstElement* prv_element = NULL;
3987         gint successful_link_count = 0;
3988
3989         MMPLAYER_FENTER();
3990
3991         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3992
3993         prv_element = (MMPlayerGstElement*)bucket->data;
3994         bucket = bucket->next;
3995
3996         for (; bucket; bucket = bucket->next) {
3997                 element = (MMPlayerGstElement*)bucket->data;
3998
3999                 if (element && element->gst) {
4000                         /* If next element is audio appsrc then make a separate audio pipeline */
4001                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4002                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4003                                 prv_element = element;
4004                                 continue;
4005                         }
4006
4007                         if (prv_element && prv_element->gst) {
4008                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4009                                         LOGD("linking [%s] to [%s] success\n",
4010                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4011                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4012                                         successful_link_count++;
4013                                 } else {
4014                                         LOGD("linking [%s] to [%s] failed\n",
4015                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4017                                         return -1;
4018                                 }
4019                         }
4020                 }
4021
4022                 prv_element = element;
4023         }
4024
4025         MMPLAYER_FLEAVE();
4026
4027         return successful_link_count;
4028 }
4029
4030 static int
4031 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4032 {
4033         GList* bucket = element_bucket;
4034         MMPlayerGstElement* element = NULL;
4035         int successful_add_count = 0;
4036
4037         MMPLAYER_FENTER();
4038
4039         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4040         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4041
4042         for (; bucket; bucket = bucket->next) {
4043                 element = (MMPlayerGstElement*)bucket->data;
4044
4045                 if (element && element->gst) {
4046                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4047                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4048                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4049                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4050                                 return 0;
4051                         }
4052                         successful_add_count++;
4053                 }
4054         }
4055
4056         MMPLAYER_FLEAVE();
4057
4058         return successful_add_count;
4059 }
4060
4061 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4062 {
4063         mm_player_t* player = (mm_player_t*) data;
4064         GstCaps *caps = NULL;
4065         GstStructure *str = NULL;
4066         const char *name;
4067
4068         MMPLAYER_FENTER();
4069
4070         MMPLAYER_RETURN_IF_FAIL(pad)
4071         MMPLAYER_RETURN_IF_FAIL(unused)
4072         MMPLAYER_RETURN_IF_FAIL(data)
4073
4074         caps = gst_pad_get_current_caps(pad);
4075         if (!caps)
4076                 return;
4077
4078         str = gst_caps_get_structure(caps, 0);
4079         if (!str)
4080                 goto ERROR;
4081
4082         name = gst_structure_get_name(str);
4083         if (!name)
4084                 goto ERROR;
4085
4086         LOGD("name = %s\n", name);
4087
4088         if (strstr(name, "audio")) {
4089                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4090
4091                 if (player->audio_stream_changed_cb) {
4092                         LOGE("call the audio stream changed cb\n");
4093                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4094                 }
4095         } else if (strstr(name, "video")) {
4096                 if ((name = gst_structure_get_string(str, "format")))
4097                         player->set_mode.video_zc = name[0] == 'S';
4098
4099                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4100
4101                 if (player->video_stream_changed_cb) {
4102                         LOGE("call the video stream changed cb\n");
4103                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4104                 }
4105         } else
4106                 goto ERROR;
4107
4108 ERROR:
4109
4110         gst_caps_unref(caps);
4111
4112         MMPLAYER_FLEAVE();
4113
4114         return;
4115 }
4116
4117
4118
4119 /**
4120  * This function is to create audio pipeline for playing.
4121  *
4122  * @param       player          [in]    handle of player
4123  *
4124  * @return      This function returns zero on success.
4125  * @remark
4126  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4127  */
4128 /* macro for code readability. just for sinkbin-creation functions */
4129 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4130 do {\
4131         x_bin[x_id].id = x_id;\
4132         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4133         if (!x_bin[x_id].gst) {\
4134                 LOGE("failed to create %s \n", x_factory);\
4135                 goto ERROR;\
4136         } else {\
4137                 if (x_player->ini.set_dump_element_flag)\
4138                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4139         } \
4140         if (x_add_bucket)\
4141                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4142 } while (0);
4143
4144 static void
4145 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4146 {
4147         GList *l = NULL;
4148
4149         MMPLAYER_FENTER();
4150         MMPLAYER_RETURN_IF_FAIL(player);
4151
4152         if (player->audio_stream_buff_list) {
4153                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4154                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4155                         if (tmp) {
4156                                 if (send_all) {
4157                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4158                                         __mmplayer_audio_stream_send_data(player, tmp);
4159                                 }
4160                                 if (tmp->pcm_data)
4161                                         g_free(tmp->pcm_data);
4162                                 g_free(tmp);
4163                         }
4164                 }
4165                 g_list_free(player->audio_stream_buff_list);
4166                 player->audio_stream_buff_list = NULL;
4167         }
4168
4169         MMPLAYER_FLEAVE();
4170 }
4171
4172 static void
4173 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4174 {
4175         MMPlayerAudioStreamDataType audio_stream = { 0, };
4176
4177         MMPLAYER_FENTER();
4178         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4179
4180         audio_stream.bitrate = a_buffer->bitrate;
4181         audio_stream.channel = a_buffer->channel;
4182         audio_stream.depth = a_buffer->depth;
4183         audio_stream.is_little_endian = a_buffer->is_little_endian;
4184         audio_stream.channel_mask = a_buffer->channel_mask;
4185         audio_stream.data_size = a_buffer->data_size;
4186         audio_stream.data = a_buffer->pcm_data;
4187
4188         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4189         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4190
4191         MMPLAYER_FLEAVE();
4192 }
4193
4194 static void
4195 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4196 {
4197         mm_player_t* player = (mm_player_t*) data;
4198
4199         gint channel = 0;
4200         gint rate = 0;
4201         gint depth = 0;
4202         gint endianness = 0;
4203         guint64 channel_mask = 0;
4204         void *a_data = NULL;
4205         gint a_size = 0;
4206         mm_player_audio_stream_buff_t *a_buffer = NULL;
4207         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4208         GList *l = NULL;
4209
4210         MMPLAYER_FENTER();
4211         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4212
4213         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4214         a_data = mapinfo.data;
4215         a_size = mapinfo.size;
4216
4217         GstCaps *caps = gst_pad_get_current_caps(pad);
4218         GstStructure *structure = gst_caps_get_structure(caps, 0);
4219
4220         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4221         gst_structure_get_int(structure, "rate", &rate);
4222         gst_structure_get_int(structure, "channels", &channel);
4223         gst_structure_get_int(structure, "depth", &depth);
4224         gst_structure_get_int(structure, "endianness", &endianness);
4225         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4226         gst_caps_unref(GST_CAPS(caps));
4227
4228         /* In case of the sync is false, use buffer list.              *
4229          * The num of buffer list depends on the num of audio channels */
4230         if (player->audio_stream_buff_list) {
4231                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4232                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4233                         if (tmp) {
4234                                 if (channel_mask == tmp->channel_mask) {
4235                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4236                                         if (tmp->data_size + a_size < tmp->buff_size) {
4237                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4238                                                 tmp->data_size += a_size;
4239                                         } else {
4240                                                 /* send data to client */
4241                                                 __mmplayer_audio_stream_send_data(player, tmp);
4242
4243                                                 if (a_size > tmp->buff_size) {
4244                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4245                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4246                                                         if (tmp->pcm_data == NULL) {
4247                                                                 LOGE("failed to realloc data.");
4248                                                                 goto DONE;
4249                                                         }
4250                                                         tmp->buff_size = a_size;
4251                                                 }
4252                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4253                                                 memcpy(tmp->pcm_data, a_data, a_size);
4254                                                 tmp->data_size = a_size;
4255                                         }
4256                                         goto DONE;
4257                                 }
4258                         } else {
4259                                 LOGE("data is empty in list.");
4260                                 goto DONE;
4261                         }
4262                 }
4263         }
4264
4265         /* create new audio stream data */
4266         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4267         if (a_buffer == NULL) {
4268                 LOGE("failed to alloc data.");
4269                 goto DONE;
4270         }
4271         a_buffer->bitrate = rate;
4272         a_buffer->channel = channel;
4273         a_buffer->depth = depth;
4274         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4275         a_buffer->channel_mask = channel_mask;
4276         a_buffer->data_size = a_size;
4277
4278         if (!player->audio_stream_sink_sync) {
4279                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4280                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4281                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4282                 if (a_buffer->pcm_data == NULL) {
4283                         LOGE("failed to alloc data.");
4284                         g_free(a_buffer);
4285                         goto DONE;
4286                 }
4287                 memcpy(a_buffer->pcm_data, a_data, a_size);
4288                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4289                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4290         } else {
4291                 /* If sync is TRUE, send data directly. */
4292                 a_buffer->pcm_data = a_data;
4293                 __mmplayer_audio_stream_send_data(player, a_buffer);
4294                 g_free(a_buffer);
4295         }
4296
4297 DONE:
4298         gst_buffer_unmap(buffer, &mapinfo);
4299         MMPLAYER_FLEAVE();
4300 }
4301
4302 static void
4303 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4304 {
4305         mm_player_t* player = (mm_player_t*)data;
4306         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4307         GstPad* sinkpad = NULL;
4308         GstElement *queue = NULL, *sink = NULL;
4309
4310         MMPLAYER_FENTER();
4311         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4312
4313         queue = gst_element_factory_make("queue", NULL);
4314         if (queue == NULL) {
4315                 LOGD("fail make queue\n");
4316                 goto ERROR;
4317         }
4318
4319         sink = gst_element_factory_make("fakesink", NULL);
4320         if (sink == NULL) {
4321                 LOGD("fail make fakesink\n");
4322                 goto ERROR;
4323         }
4324
4325         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4326
4327         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4328                 LOGW("failed to link queue & sink\n");
4329                 goto ERROR;
4330         }
4331
4332         sinkpad = gst_element_get_static_pad(queue, "sink");
4333
4334         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4335                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4336                 goto ERROR;
4337         }
4338
4339         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4340
4341         gst_object_unref(sinkpad);
4342         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4343         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4344
4345         gst_element_set_state(sink, GST_STATE_PAUSED);
4346         gst_element_set_state(queue, GST_STATE_PAUSED);
4347
4348         MMPLAYER_SIGNAL_CONNECT(player,
4349                 G_OBJECT(sink),
4350                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4351                 "handoff",
4352                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4353                 (gpointer)player);
4354
4355         MMPLAYER_FLEAVE();
4356         return;
4357
4358 ERROR:
4359         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4360         if (queue) {
4361                 gst_object_unref(GST_OBJECT(queue));
4362                 queue = NULL;
4363         }
4364         if (sink) {
4365                 gst_object_unref(GST_OBJECT(sink));
4366                 sink = NULL;
4367         }
4368         if (sinkpad) {
4369                 gst_object_unref(GST_OBJECT(sinkpad));
4370                 sinkpad = NULL;
4371         }
4372
4373         return;
4374 }
4375
4376 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4377 {
4378         #define MAX_PROPS_LEN 128
4379         gint latency_mode = 0;
4380         gchar *stream_type = NULL;
4381         gchar *latency = NULL;
4382         gint stream_id = 0;
4383         gchar stream_props[MAX_PROPS_LEN] = {0,};
4384         GstStructure *props = NULL;
4385
4386         /* set volume table
4387          * It should be set after player creation through attribute.
4388          * But, it can not be changed during playing.
4389          */
4390         MMPLAYER_FENTER();
4391         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4392         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4393
4394         if (!stream_type) {
4395                 LOGE("stream_type is null.\n");
4396         } else {
4397                 if (player->sound.focus_id)
4398                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4399                                         stream_type, stream_id, player->sound.focus_id);
4400                 else
4401                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4402                                         stream_type, stream_id);
4403                 props = gst_structure_from_string(stream_props, NULL);
4404                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4405                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4406                         stream_type, stream_id, player->sound.focus_id, stream_props);
4407                 gst_structure_free(props);
4408         }
4409
4410         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4411
4412         switch (latency_mode) {
4413         case AUDIO_LATENCY_MODE_LOW:
4414                 latency = g_strndup("low", 3);
4415                 break;
4416         case AUDIO_LATENCY_MODE_MID:
4417                 latency = g_strndup("mid", 3);
4418                 break;
4419         case AUDIO_LATENCY_MODE_HIGH:
4420                 latency = g_strndup("high", 4);
4421                 break;
4422         };
4423
4424         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4425                         "latency", latency,
4426                         NULL);
4427
4428         LOGD("audiosink property - latency=%s \n", latency);
4429
4430         g_free(latency);
4431
4432         MMPLAYER_FLEAVE();
4433 }
4434
4435 static int
4436 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4437 {
4438         MMPlayerGstElement* first_element = NULL;
4439         MMPlayerGstElement* audiobin = NULL;
4440         MMHandleType attrs = 0;
4441         GstPad *pad = NULL;
4442         GstPad *ghostpad = NULL;
4443         GList* element_bucket = NULL;
4444         gboolean link_audio_sink_now = TRUE;
4445         int i = 0;
4446         GstCaps *acaps;
4447
4448         MMPLAYER_FENTER();
4449
4450         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4451
4452         /* alloc handles */
4453         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4454         if (!audiobin) {
4455                 LOGE("failed to allocate memory for audiobin\n");
4456                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4457         }
4458
4459         attrs = MMPLAYER_GET_ATTRS(player);
4460
4461         /* create bin */
4462         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4463         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4464         if (!audiobin[MMPLAYER_A_BIN].gst) {
4465                 LOGE("failed to create audiobin\n");
4466                 goto ERROR;
4467         }
4468
4469         /* take it */
4470         player->pipeline->audiobin = audiobin;
4471
4472         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4473
4474         /* Adding audiotp plugin for reverse trickplay feature */
4475 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4476
4477         /* converter */
4478         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4479
4480         /* replaygain volume */
4481         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4482         if (player->sound.rg_enable)
4483                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4484         else
4485                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4486
4487         /* resampler */
4488         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4489
4490         if (player->set_mode.pcm_extraction) {
4491                 // pcm extraction only and no sound output
4492                 if (player->audio_stream_render_cb_ex) {
4493                         char *caps_str = NULL;
4494                         GstCaps* caps = NULL;
4495                         gchar *format = NULL;
4496
4497                         /* capsfilter */
4498                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4499
4500                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4501
4502                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4503
4504                         caps = gst_caps_new_simple("audio/x-raw",
4505                                         "format", G_TYPE_STRING, format,
4506                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4507                                         "channels", G_TYPE_INT, player->pcm_channel,
4508                                         NULL);
4509                         caps_str = gst_caps_to_string(caps);
4510                         LOGD("new caps : %s\n", caps_str);
4511
4512                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4513
4514                         /* clean */
4515                         gst_caps_unref(caps);
4516                         MMPLAYER_FREEIF(caps_str);
4517
4518                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4519
4520                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4521                         /* raw pad handling signal */
4522                         MMPLAYER_SIGNAL_CONNECT(player,
4523                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4524                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4525                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4526                 } else {
4527                         int dst_samplerate = 0;
4528                         int dst_channels = 0;
4529                         int dst_depth = 0;
4530                         char *caps_str = NULL;
4531                         GstCaps* caps = NULL;
4532
4533                         /* get conf. values */
4534                         mm_attrs_multiple_get(player->attrs,
4535                                                 NULL,
4536                                                 "pcm_extraction_samplerate", &dst_samplerate,
4537                                                 "pcm_extraction_channels", &dst_channels,
4538                                                 "pcm_extraction_depth", &dst_depth,
4539                                                 NULL);
4540
4541                         /* capsfilter */
4542                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4543                         caps = gst_caps_new_simple("audio/x-raw",
4544                                         "rate", G_TYPE_INT, dst_samplerate,
4545                                         "channels", G_TYPE_INT, dst_channels,
4546                                         "depth", G_TYPE_INT, dst_depth,
4547                                         NULL);
4548                         caps_str = gst_caps_to_string(caps);
4549                         LOGD("new caps : %s\n", caps_str);
4550
4551                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4552
4553                         /* clean */
4554                         gst_caps_unref(caps);
4555                         MMPLAYER_FREEIF(caps_str);
4556
4557                         /* fake sink */
4558                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4559
4560                         /* set sync */
4561                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4562                 }
4563         } else {
4564                 // normal playback
4565                 //GstCaps* caps = NULL;
4566                 gint channels = 0;
4567
4568                 /* for logical volume control */
4569                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4570                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4571
4572                 if (player->sound.mute) {
4573                         LOGD("mute enabled\n");
4574                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4575                 }
4576
4577 #if 0
4578                 /*capsfilter */
4579                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4580                 caps = gst_caps_from_string("audio/x-raw-int, "
4581                                         "endianness = (int) LITTLE_ENDIAN, "
4582                                         "signed = (boolean) true, "
4583                                         "width = (int) 16, "
4584                                         "depth = (int) 16");
4585                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4586                 gst_caps_unref(caps);
4587 #endif
4588
4589                 /* check if multi-channels */
4590                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4591                         GstPad *srcpad = NULL;
4592                         GstCaps *caps = NULL;
4593
4594                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4595                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4596                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4597                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4598                                         if (str)
4599                                                 gst_structure_get_int(str, "channels", &channels);
4600                                         gst_caps_unref(caps);
4601                                 }
4602                                 gst_object_unref(srcpad);
4603                         }
4604                 }
4605
4606                 /* audio effect element. if audio effect is enabled */
4607                 if ((strcmp(player->ini.audioeffect_element, ""))
4608                         && (channels <= 2)
4609                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4610                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4611
4612                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4613
4614                         if ((!player->bypass_audio_effect)
4615                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4616                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4617                                         if (!_mmplayer_audio_effect_custom_apply(player))
4618                                                 LOGI("apply audio effect(custom) setting success\n");
4619                                 }
4620                         }
4621
4622                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4623                                 && (player->set_mode.rich_audio))
4624                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4625                 }
4626
4627                 /* create audio sink */
4628                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4629                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4630                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4631
4632                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4633                 if (player->is_content_spherical &&
4634                                 channels == 4 &&
4635                                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4636                                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4637                                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4638
4639                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4640
4641                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4642
4643                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4644                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4645                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4646                         gst_caps_unref(acaps);
4647
4648                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4649                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4650                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4651                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4652
4653                         player->is_openal_plugin_used = TRUE;
4654
4655                         if (player->video360_yaw_radians <= M_PI &&
4656                                         player->video360_yaw_radians >= -M_PI &&
4657                                         player->video360_pitch_radians <= M_PI_2 &&
4658                                         player->video360_pitch_radians >= -M_PI_2) {
4659                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4660                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4661                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4662                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4663                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4664                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4665                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4666                         }
4667                 } else {
4668                         if (player->is_content_spherical)
4669                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4670                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4671                 }
4672
4673                 /* qos on */
4674                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4675                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4676
4677
4678                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4679                         (player->videodec_linked && player->ini.use_system_clock)) {
4680                         LOGD("system clock will be used.\n");
4681                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4682                 }
4683
4684                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4685                         __mmplayer_gst_set_audiosink_property(player, attrs);
4686         }
4687
4688         if (audiobin[MMPLAYER_A_SINK].gst) {
4689                 GstPad *sink_pad = NULL;
4690                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4691                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4692                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4693                 gst_object_unref(GST_OBJECT(sink_pad));
4694         }
4695
4696         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4697
4698         /* adding created elements to bin */
4699         LOGD("adding created elements to bin\n");
4700         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4701                 LOGE("failed to add elements\n");
4702                 goto ERROR;
4703         }
4704
4705         /* linking elements in the bucket by added order. */
4706         LOGD("Linking elements in the bucket by added order.\n");
4707         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4708                 LOGE("failed to link elements\n");
4709                 goto ERROR;
4710         }
4711
4712         /* get first element's sinkpad for creating ghostpad */
4713         first_element = (MMPlayerGstElement *)element_bucket->data;
4714         if (!first_element) {
4715                 LOGE("failed to get first elem\n");
4716                 goto ERROR;
4717         }
4718
4719         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4720         if (!pad) {
4721                 LOGE("failed to get pad from first element of audiobin\n");
4722                 goto ERROR;
4723         }
4724
4725         ghostpad = gst_ghost_pad_new("sink", pad);
4726         if (!ghostpad) {
4727                 LOGE("failed to create ghostpad\n");
4728                 goto ERROR;
4729         }
4730
4731         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4732                 LOGE("failed to add ghostpad to audiobin\n");
4733                 goto ERROR;
4734         }
4735
4736         gst_object_unref(pad);
4737
4738         g_list_free(element_bucket);
4739         MMPLAYER_FLEAVE();
4740
4741         return MM_ERROR_NONE;
4742
4743 ERROR:
4744
4745         LOGD("ERROR : releasing audiobin\n");
4746
4747         if (pad)
4748                 gst_object_unref(GST_OBJECT(pad));
4749
4750         if (ghostpad)
4751                 gst_object_unref(GST_OBJECT(ghostpad));
4752
4753         if (element_bucket)
4754                 g_list_free(element_bucket);
4755
4756         /* release element which are not added to bin */
4757         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4758                 /* NOTE : skip bin */
4759                 if (audiobin[i].gst) {
4760                         GstObject* parent = NULL;
4761                         parent = gst_element_get_parent(audiobin[i].gst);
4762
4763                         if (!parent) {
4764                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4765                                 audiobin[i].gst = NULL;
4766                         } else
4767                                 gst_object_unref(GST_OBJECT(parent));
4768                 }
4769         }
4770
4771         /* release audiobin with it's childs */
4772         if (audiobin[MMPLAYER_A_BIN].gst)
4773                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4774
4775         MMPLAYER_FREEIF(audiobin);
4776
4777         player->pipeline->audiobin = NULL;
4778
4779         return MM_ERROR_PLAYER_INTERNAL;
4780 }
4781
4782 static GstPadProbeReturn
4783 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4784 {
4785         mm_player_t* player = (mm_player_t*) u_data;
4786         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4787         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4788
4789         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4790
4791         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4792                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4793
4794         return GST_PAD_PROBE_OK;
4795 }
4796
4797 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4798 {
4799         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4800 }
4801
4802 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4803 {
4804         int ret = MM_ERROR_NONE;
4805         GList *l = NULL;
4806         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4807         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4808
4809         MMPLAYER_VIDEO_BO_LOCK(player);
4810
4811         if (player->video_bo_list) {
4812                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4813                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4814                         if (tmp && tmp->bo == bo) {
4815                                 tmp->using = FALSE;
4816                                 LOGD("release bo %p", bo);
4817                                 tbm_bo_unref(tmp->bo);
4818                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4819                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4820                                 return ret;
4821                         }
4822                 }
4823         } else {
4824                 /* hw codec is running or the list was reset for DRC. */
4825                 LOGW("there is no bo list.");
4826         }
4827         MMPLAYER_VIDEO_BO_UNLOCK(player);
4828
4829         LOGW("failed to find bo %p", bo);
4830         return ret;
4831 }
4832
4833 static void
4834 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4835 {
4836         GList *l = NULL;
4837
4838         MMPLAYER_FENTER();
4839         MMPLAYER_RETURN_IF_FAIL(player);
4840
4841         MMPLAYER_VIDEO_BO_LOCK(player);
4842         if (player->video_bo_list) {
4843                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4844                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4845                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4846                         if (tmp) {
4847                                 if (tmp->bo)
4848                                         tbm_bo_unref(tmp->bo);
4849                                 g_free(tmp);
4850                         }
4851                 }
4852                 g_list_free(player->video_bo_list);
4853                 player->video_bo_list = NULL;
4854         }
4855         player->video_bo_size = 0;
4856         MMPLAYER_VIDEO_BO_UNLOCK(player);
4857
4858         MMPLAYER_FLEAVE();
4859         return;
4860 }
4861
4862 static void*
4863 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4864 {
4865         GList *l = NULL;
4866         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4867         gboolean ret = TRUE;
4868
4869         /* check DRC, if it is, destroy the prev bo list to create again */
4870         if (player->video_bo_size != size) {
4871                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4872                 __mmplayer_video_stream_destroy_bo_list(player);
4873                 player->video_bo_size = size;
4874         }
4875
4876         MMPLAYER_VIDEO_BO_LOCK(player);
4877
4878         if ((!player->video_bo_list) ||
4879                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4880
4881                 /* create bo list */
4882                 int idx = 0;
4883                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4884
4885                 if (player->video_bo_list) {
4886                         /* if bo list did not created all, try it again. */
4887                         idx = g_list_length(player->video_bo_list);
4888                         LOGD("bo list exist(len: %d)", idx);
4889                 }
4890
4891                 for (; idx < player->ini.num_of_video_bo; idx++) {
4892                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4893                         if (!bo_info) {
4894                                 LOGE("Fail to alloc bo_info.");
4895                                 break;
4896                         }
4897                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4898                         if (!bo_info->bo) {
4899                                 LOGE("Fail to tbm_bo_alloc.");
4900                                 g_free(bo_info);
4901                                 break;
4902                         }
4903                         bo_info->using = FALSE;
4904                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4905                 }
4906
4907                 /* update video num buffers */
4908                 player->video_num_buffers = idx;
4909                 if (idx == player->ini.num_of_video_bo)
4910                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4911
4912                 if (idx == 0) {
4913                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4914                         return NULL;
4915                 }
4916
4917                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4918         }
4919
4920         while (TRUE) {
4921                 /* get bo from list*/
4922                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4923                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4924                         if (tmp && (tmp->using == FALSE)) {
4925                                 LOGD("found bo %p to use", tmp->bo);
4926                                 tmp->using = TRUE;
4927                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4928                                 return tbm_bo_ref(tmp->bo);
4929                         }
4930                 }
4931                 if (!ret) {
4932                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4933                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4934                         return NULL;
4935                 }
4936
4937                 if (player->ini.video_bo_timeout <= 0) {
4938                         MMPLAYER_VIDEO_BO_WAIT(player);
4939                 } else {
4940                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4941                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4942                 }
4943                 continue;
4944         }
4945 }
4946
4947 static void
4948 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4949 {
4950         mm_player_t* player = (mm_player_t*)data;
4951         MMPLAYER_FENTER();
4952         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4953
4954         /* send prerolled pkt */
4955         player->video_stream_prerolled = FALSE;
4956
4957         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4958
4959         /* not to send prerolled pkt again */
4960         player->video_stream_prerolled = TRUE;
4961 }
4962
4963 static void
4964 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4965 {
4966         mm_player_t* player = (mm_player_t*)data;
4967         GstCaps *caps = NULL;
4968         MMPlayerVideoStreamDataType *stream = NULL;
4969         MMVideoBuffer *video_buffer = NULL;
4970         GstMemory *dataBlock = NULL;
4971         GstMemory *metaBlock = NULL;
4972         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4973         GstStructure *structure = NULL;
4974         const gchar *string_format = NULL;
4975         unsigned int fourcc = 0;
4976
4977         MMPLAYER_FENTER();
4978         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4979
4980         if (player->video_stream_prerolled) {
4981                 player->video_stream_prerolled = FALSE;
4982                 LOGD("skip the prerolled pkt not to send it again");
4983                 return;
4984         }
4985
4986         caps = gst_pad_get_current_caps(pad);
4987         if (caps == NULL) {
4988                 LOGE("Caps is NULL.");
4989                 return;
4990         }
4991
4992         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4993
4994         /* clear stream data structure */
4995         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4996         if (!stream) {
4997                 LOGE("failed to alloc mem for video data");
4998                 return;
4999         }
5000
5001         structure = gst_caps_get_structure(caps, 0);
5002         gst_structure_get_int(structure, "width", &(stream->width));
5003         gst_structure_get_int(structure, "height", &(stream->height));
5004         string_format = gst_structure_get_string(structure, "format");
5005         if (string_format)
5006                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5007         stream->format = util_get_pixtype(fourcc);
5008         gst_caps_unref(caps);
5009         caps = NULL;
5010
5011     /*
5012         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5013                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5014     */
5015
5016         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5017                 LOGE("Wrong condition!!");
5018                 goto ERROR;
5019         }
5020
5021         /* set size and timestamp */
5022         dataBlock = gst_buffer_peek_memory(buffer, 0);
5023         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5024         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5025
5026         /* check zero-copy */
5027         if (player->set_mode.video_zc &&
5028                 player->set_mode.media_packet_video_stream &&
5029                 gst_buffer_n_memory(buffer) > 1) {
5030                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5031                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5032                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5033         }
5034
5035         if (video_buffer) { /* hw codec */
5036                 /* set tbm bo */
5037                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5038                         int i = 0;
5039
5040                         /* copy pointer of tbm bo, stride, elevation */
5041                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5042                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5043                                 i++;
5044                         }
5045                 } else {
5046                         LOGE("Not support video buffer format");
5047                         goto ERROR;
5048                 }
5049                 memcpy(stream->stride, video_buffer->stride_width,
5050                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5051                 memcpy(stream->elevation, video_buffer->stride_height,
5052                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5053
5054                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5055                 stream->internal_buffer = gst_buffer_ref(buffer);
5056         } else { /* sw codec */
5057                 int i = 0;
5058                 int j = 0;
5059                 int k = 0;
5060                 int ret = TBM_SURFACE_ERROR_NONE;
5061                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5062                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5063                 int size = 0;
5064                 unsigned char *src = NULL;
5065                 unsigned char *dest = NULL;
5066                 tbm_bo_handle thandle;
5067                 tbm_surface_h surface;
5068                 tbm_surface_info_s info;
5069                 gboolean gst_ret;
5070
5071                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5072                 if (!gst_ret) {
5073                         LOGE("fail to gst_memory_map");
5074                         goto ERROR;
5075                 }
5076
5077
5078                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5079                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5080
5081                         ret = tbm_surface_get_info(surface, &info);
5082
5083                         if (ret != TBM_SURFACE_ERROR_NONE) {
5084                                 tbm_surface_destroy(surface);
5085                                 goto ERROR;
5086                         }
5087                         tbm_surface_destroy(surface);
5088
5089                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5090                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5091                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5092                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5093                         stream->stride[0] = info.planes[0].stride;
5094                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5095                         stream->stride[1] = info.planes[1].stride;
5096                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5097                         stream->stride[2] = info.planes[2].stride;
5098                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5099                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5100                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5101                         stream->stride[0] = stream->width * 4;
5102                         stream->elevation[0] = stream->height;
5103                         size = stream->stride[0] * stream->height;
5104                 } else {
5105                         LOGE("Not support format %d", stream->format);
5106                         goto ERROR;
5107                 }
5108
5109                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5110                 if (!stream->bo[0]) {
5111                         LOGE("Fail to tbm_bo_alloc!!");
5112                         goto ERROR;
5113                 }
5114
5115                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5116                 if (thandle.ptr && mapinfo.data) {
5117                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5118                                 for (i = 0; i < 3; i++) {
5119                                         src = mapinfo.data + src_offset[i];
5120                                         dest = thandle.ptr + info.planes[i].offset;
5121
5122                                         if (i > 0) k = 1;
5123                                         for (j = 0; j < stream->height>>k; j++) {
5124                                                 memcpy(dest, src, stream->width>>k);
5125                                                 src += src_stride[i];
5126                                                 dest += stream->stride[i];
5127                                         }
5128                                 }
5129                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5130                                 memcpy(thandle.ptr, mapinfo.data, size);
5131                         } else {
5132                                 LOGE("Not support format %d", stream->format);
5133                                 goto ERROR;
5134                         }
5135                 } else {
5136                         LOGE("data pointer is wrong. dest : %p, src : %p",
5137                                         thandle.ptr, mapinfo.data);
5138                         goto ERROR;
5139                 }
5140                 tbm_bo_unmap(stream->bo[0]);
5141         }
5142
5143         if (player->video_stream_cb) { /* This has been already checked at the entry */
5144                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5145                         LOGE("failed to send video stream data.");
5146                         goto ERROR;
5147                 }
5148         }
5149
5150         if (metaBlock)
5151                 gst_memory_unmap(metaBlock, &mapinfo);
5152         else
5153                 gst_memory_unmap(dataBlock, &mapinfo);
5154
5155         return;
5156
5157 ERROR:
5158         LOGE("release video stream resource.");
5159         if (metaBlock) {
5160                 int i = 0;
5161                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5162                         if (stream->bo[i])
5163                                 tbm_bo_unref(stream->bo[i]);
5164                 }
5165                 gst_memory_unmap(metaBlock, &mapinfo);
5166
5167                 /* unref gst buffer */
5168                 if (stream->internal_buffer)
5169                         gst_buffer_unref(stream->internal_buffer);
5170         } else if (dataBlock) {
5171                 if (stream->bo[0])
5172                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5173                 gst_memory_unmap(dataBlock, &mapinfo);
5174         }
5175
5176         g_free(stream);
5177         return;
5178 }
5179
5180 static int
5181 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5182 {
5183         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5184         GList* element_bucket = NULL;
5185
5186         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5187
5188         MMPLAYER_FENTER();
5189
5190         if (player->set_mode.video_zc || player->is_content_spherical) {
5191                 LOGD("do not need to add video filters.");
5192                 return MM_ERROR_NONE;
5193         }
5194
5195         /* in case of sw codec except 360 playback,
5196          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5197         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5198         LOGD("using video converter: %s", video_csc);
5199
5200         /* set video rotator */
5201         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5202
5203         *bucket = element_bucket;
5204         MMPLAYER_FLEAVE();
5205         return MM_ERROR_NONE;
5206
5207 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5208         g_list_free(element_bucket);
5209
5210         *bucket = NULL;
5211         MMPLAYER_FLEAVE();
5212         return MM_ERROR_PLAYER_INTERNAL;
5213 }
5214
5215 /**
5216  * This function is to create video pipeline.
5217  *
5218  * @param       player          [in]    handle of player
5219  *              caps            [in]    src caps of decoder
5220  *              surface_type    [in]    surface type for video rendering
5221  *
5222  * @return      This function returns zero on success.
5223  * @remark
5224  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5225  */
5226 /**
5227   * VIDEO PIPELINE
5228   * - video overlay surface(arm/x86) : tizenwlsink
5229   */
5230 static int
5231 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5232 {
5233         GstPad *pad = NULL;
5234         MMHandleType attrs;
5235         GList*element_bucket = NULL;
5236         MMPlayerGstElement* first_element = NULL;
5237         MMPlayerGstElement* videobin = NULL;
5238         gchar *videosink_element = NULL;
5239
5240         MMPLAYER_FENTER();
5241
5242         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5243
5244         /* alloc handles */
5245         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5246         if (!videobin)
5247                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5248
5249         player->pipeline->videobin = videobin;
5250
5251         attrs = MMPLAYER_GET_ATTRS(player);
5252         if (!attrs) {
5253                 LOGE("cannot get content attribute");
5254                 return MM_ERROR_PLAYER_INTERNAL;
5255         }
5256
5257         /* create bin */
5258         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5259         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5260         if (!videobin[MMPLAYER_V_BIN].gst) {
5261                 LOGE("failed to create videobin");
5262                 goto ERROR;
5263         }
5264
5265         int enable_video_decoded_cb = 0;
5266         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5267
5268         if (player->is_content_spherical) {
5269                 LOGD("video360 elem will be added.");
5270
5271                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5272                                 "video-360", TRUE, player);
5273
5274                 /* Set spatial media metadata and/or user settings to the element.
5275                  * */
5276                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5277                                 "projection-type", player->video360_metadata.projection_type, NULL);
5278
5279                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5280                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5281
5282                 if (player->video360_metadata.full_pano_width_pixels &&
5283                                 player->video360_metadata.full_pano_height_pixels &&
5284                                 player->video360_metadata.cropped_area_image_width &&
5285                                 player->video360_metadata.cropped_area_image_height) {
5286                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5287                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5288                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5289                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5290                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5291                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5292                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5293                                         NULL);
5294                 }
5295
5296                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5297                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5298                                         "horizontal-fov", player->video360_horizontal_fov,
5299                                         "vertical-fov", player->video360_vertical_fov, NULL);
5300                 }
5301
5302                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5303                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5304                                         "zoom", 1.0f / player->video360_zoom, NULL);
5305                 }
5306
5307                 if (player->video360_yaw_radians <= M_PI &&
5308                                 player->video360_yaw_radians >= -M_PI &&
5309                                 player->video360_pitch_radians <= M_PI_2 &&
5310                                 player->video360_pitch_radians >= -M_PI_2) {
5311                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5312                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5313                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5314                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5315                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316                                         "pose-yaw", player->video360_metadata.init_view_heading,
5317                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5318                 }
5319
5320                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5321                                 "passthrough", !player->is_video360_enabled, NULL);
5322         }
5323
5324         /* set video sink */
5325         switch (surface_type) {
5326         case MM_DISPLAY_SURFACE_OVERLAY:
5327                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5328                         goto ERROR;
5329                 if (strlen(player->ini.videosink_element_overlay) > 0)
5330                         videosink_element = player->ini.videosink_element_overlay;
5331                 else
5332                         goto ERROR;
5333                 break;
5334         case MM_DISPLAY_SURFACE_NULL:
5335                 if (strlen(player->ini.videosink_element_fake) > 0)
5336                         videosink_element = player->ini.videosink_element_fake;
5337                 else
5338                         goto ERROR;
5339                 break;
5340         case MM_DISPLAY_SURFACE_REMOTE:
5341                 if (strlen(player->ini.videosink_element_fake) > 0)
5342                         videosink_element = player->ini.videosink_element_fake;
5343                 else
5344                         goto ERROR;
5345                 break;
5346         default:
5347                 LOGE("unidentified surface type");
5348                 goto ERROR;
5349         }
5350         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5351
5352         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5353
5354         /* additional setting for sink plug-in */
5355         switch (surface_type) {
5356         case MM_DISPLAY_SURFACE_OVERLAY:
5357         {
5358                 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5359                 if (!use_tbm) {
5360                         LOGD("selected videosink name: %s", videosink_element);
5361
5362                         /* support shard memory with S/W codec on HawkP */
5363                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5364                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5365                                         "use-tbm", use_tbm, NULL);
5366                         }
5367                 } else {
5368                         if (attrs) {
5369                                 int gapless = 0;
5370
5371                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5372
5373                                 if (gapless > 0) {
5374                                         LOGD("disable last-sample");
5375                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5376                                 }
5377                         }
5378                 }
5379                 if (player->set_mode.media_packet_video_stream) {
5380                         int enable = 0;
5381                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5382                         if (enable)
5383                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5384
5385                         MMPLAYER_SIGNAL_CONNECT(player,
5386                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5387                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5388                                                                         "handoff",
5389                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5390                                                                         (gpointer)player);
5391
5392                         MMPLAYER_SIGNAL_CONNECT(player,
5393                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5394                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5395                                                                         "preroll-handoff",
5396                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5397                                                                         (gpointer)player);
5398                 }
5399                 break;
5400         }
5401         case MM_DISPLAY_SURFACE_REMOTE:
5402         {
5403                 if (player->set_mode.media_packet_video_stream) {
5404                         LOGE("add data probe at videosink");
5405                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5406                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5407
5408                         MMPLAYER_SIGNAL_CONNECT(player,
5409                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5410                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5411                                                                         "handoff",
5412                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5413                                                                         (gpointer)player);
5414
5415                         MMPLAYER_SIGNAL_CONNECT(player,
5416                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5417                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5418                                                                         "preroll-handoff",
5419                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5420                                                                         (gpointer)player);
5421                         if (attrs) {
5422                                 int gapless = 0;
5423
5424                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5425
5426                                 if (gapless > 0) {
5427                                         LOGD("disable last-sample");
5428                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5429                                 }
5430                         }
5431                 }
5432                 break;
5433         }
5434         default:
5435                 break;
5436         }
5437
5438         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5439                 goto ERROR;
5440
5441         if (videobin[MMPLAYER_V_SINK].gst) {
5442                 GstPad *sink_pad = NULL;
5443                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5444                 if (sink_pad) {
5445                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5446                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5447                         gst_object_unref(GST_OBJECT(sink_pad));
5448                 } else
5449                         LOGW("failed to get sink pad from videosink\n");
5450         }
5451
5452         /* store it as it's sink element */
5453         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5454
5455         /* adding created elements to bin */
5456         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5457                 LOGE("failed to add elements\n");
5458                 goto ERROR;
5459         }
5460
5461         /* Linking elements in the bucket by added order */
5462         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5463                 LOGE("failed to link elements\n");
5464                 goto ERROR;
5465         }
5466
5467         /* get first element's sinkpad for creating ghostpad */
5468         if (element_bucket)
5469                 first_element = (MMPlayerGstElement *)element_bucket->data;
5470         if (!first_element) {
5471                 LOGE("failed to get first element from bucket\n");
5472                 goto ERROR;
5473         }
5474
5475         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5476         if (!pad) {
5477                 LOGE("failed to get pad from first element\n");
5478                 goto ERROR;
5479         }
5480
5481         /* create ghostpad */
5482         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5483         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5484                 LOGE("failed to add ghostpad to videobin\n");
5485                 goto ERROR;
5486         }
5487         gst_object_unref(pad);
5488
5489         /* done. free allocated variables */
5490         if (element_bucket)
5491                 g_list_free(element_bucket);
5492
5493         MMPLAYER_FLEAVE();
5494
5495         return MM_ERROR_NONE;
5496
5497 ERROR:
5498         LOGE("ERROR : releasing videobin\n");
5499
5500         g_list_free(element_bucket);
5501
5502         if (pad)
5503                 gst_object_unref(GST_OBJECT(pad));
5504
5505         /* release videobin with it's childs */
5506         if (videobin[MMPLAYER_V_BIN].gst)
5507                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5508
5509
5510         MMPLAYER_FREEIF(videobin);
5511
5512         player->pipeline->videobin = NULL;
5513
5514         return MM_ERROR_PLAYER_INTERNAL;
5515 }
5516
5517 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5518 {
5519         GList *element_bucket = NULL;
5520         MMPlayerGstElement *textbin = player->pipeline->textbin;
5521
5522         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5523         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5524         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5525                                                         "signal-handoffs", FALSE,
5526                                                         NULL);
5527
5528         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5529         MMPLAYER_SIGNAL_CONNECT(player,
5530                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5531                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5532                                                         "handoff",
5533                                                         G_CALLBACK(__mmplayer_update_subtitle),
5534                                                         (gpointer)player);
5535
5536         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5537         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5538         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5539
5540         if (!player->play_subtitle) {
5541                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5542                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5543         }
5544
5545         /* adding created elements to bin */
5546         LOGD("adding created elements to bin\n");
5547         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5548                 LOGE("failed to add elements\n");
5549                 goto ERROR;
5550         }
5551
5552         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5553         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5554         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5555
5556         /* linking elements in the bucket by added order. */
5557         LOGD("Linking elements in the bucket by added order.\n");
5558         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5559                 LOGE("failed to link elements\n");
5560                 goto ERROR;
5561         }
5562
5563         /* done. free allocated variables */
5564         g_list_free(element_bucket);
5565
5566         if (textbin[MMPLAYER_T_QUEUE].gst) {
5567                 GstPad *pad = NULL;
5568                 GstPad *ghostpad = NULL;
5569
5570                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5571                 if (!pad) {
5572                         LOGE("failed to get sink pad of text queue");
5573                         goto ERROR;
5574                 }
5575
5576                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5577                 gst_object_unref(pad);
5578
5579                 if (!ghostpad) {
5580                         LOGE("failed to create ghostpad of textbin\n");
5581                         goto ERROR;
5582                 }
5583
5584                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5585                         LOGE("failed to add ghostpad to textbin\n");
5586                         gst_object_unref(ghostpad);
5587                         goto ERROR;
5588                 }
5589         }
5590
5591         return MM_ERROR_NONE;
5592
5593 ERROR:
5594         g_list_free(element_bucket);
5595
5596         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5597                 LOGE("remove textbin sink from sink list");
5598                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5599         }
5600
5601         /* release element at __mmplayer_gst_create_text_sink_bin */
5602         return MM_ERROR_PLAYER_INTERNAL;
5603 }
5604
5605 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5606 {
5607         MMPlayerGstElement *textbin = NULL;
5608         GList *element_bucket = NULL;
5609         int surface_type = 0;
5610         gint i = 0;
5611
5612         MMPLAYER_FENTER();
5613
5614         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5615
5616         /* alloc handles */
5617         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5618         if (!textbin) {
5619                 LOGE("failed to allocate memory for textbin\n");
5620                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5621         }
5622
5623         /* create bin */
5624         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5625         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5626         if (!textbin[MMPLAYER_T_BIN].gst) {
5627                 LOGE("failed to create textbin\n");
5628                 goto ERROR;
5629         }
5630
5631         /* take it */
5632         player->pipeline->textbin = textbin;
5633
5634         /* fakesink */
5635         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5636         LOGD("surface type for subtitle : %d", surface_type);
5637         switch (surface_type) {
5638         case MM_DISPLAY_SURFACE_OVERLAY:
5639         case MM_DISPLAY_SURFACE_NULL:
5640         case MM_DISPLAY_SURFACE_REMOTE:
5641                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5642                         LOGE("failed to make plain text elements\n");
5643                         goto ERROR;
5644                 }
5645                 break;
5646         default:
5647                 goto ERROR;
5648                 break;
5649         }
5650
5651         MMPLAYER_FLEAVE();
5652
5653         return MM_ERROR_NONE;
5654
5655 ERROR:
5656
5657         LOGD("ERROR : releasing textbin\n");
5658
5659         g_list_free(element_bucket);
5660
5661         /* release signal */
5662         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5663
5664         /* release element which are not added to bin */
5665         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5666                 /* NOTE : skip bin */
5667                 if (textbin[i].gst) {
5668                         GstObject* parent = NULL;
5669                         parent = gst_element_get_parent(textbin[i].gst);
5670
5671                         if (!parent) {
5672                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5673                                 textbin[i].gst = NULL;
5674                         } else {
5675                                 gst_object_unref(GST_OBJECT(parent));
5676                         }
5677                 }
5678         }
5679
5680         /* release textbin with it's childs */
5681         if (textbin[MMPLAYER_T_BIN].gst)
5682                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5683
5684         MMPLAYER_FREEIF(player->pipeline->textbin);
5685         player->pipeline->textbin = NULL;
5686
5687         MMPLAYER_FLEAVE();
5688         return MM_ERROR_PLAYER_INTERNAL;
5689 }
5690
5691
5692 static int
5693 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5694 {
5695         MMPlayerGstElement* mainbin = NULL;
5696         MMPlayerGstElement* textbin = NULL;
5697         MMHandleType attrs = 0;
5698         GstElement *subsrc = NULL;
5699         GstElement *subparse = NULL;
5700         gchar *subtitle_uri = NULL;
5701         const gchar *charset = NULL;
5702         GstPad *pad = NULL;
5703
5704         MMPLAYER_FENTER();
5705
5706         /* get mainbin */
5707         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5708                                                                 player->pipeline &&
5709                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5710
5711         mainbin = player->pipeline->mainbin;
5712
5713         attrs = MMPLAYER_GET_ATTRS(player);
5714         if (!attrs) {
5715                 LOGE("cannot get content attribute\n");
5716                 return MM_ERROR_PLAYER_INTERNAL;
5717         }
5718
5719         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5720         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5721                 LOGE("subtitle uri is not proper filepath.\n");
5722                 return MM_ERROR_PLAYER_INVALID_URI;
5723         }
5724
5725         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5726                 LOGE("failed to get storage info of subtitle path");
5727                 return MM_ERROR_PLAYER_INVALID_URI;
5728         }
5729
5730         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5731
5732         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5733         player->subtitle_language_list = NULL;
5734         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5735
5736         /* create the subtitle source */
5737         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5738         if (!subsrc) {
5739                 LOGE("failed to create filesrc element\n");
5740                 goto ERROR;
5741         }
5742         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5743
5744         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5745         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5746
5747         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5748                 LOGW("failed to add queue\n");
5749                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5750                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5751                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5752                 goto ERROR;
5753         }
5754
5755         /* subparse */
5756         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5757         if (!subparse) {
5758                 LOGE("failed to create subparse element\n");
5759                 goto ERROR;
5760         }
5761
5762         charset = util_get_charset(subtitle_uri);
5763         if (charset) {
5764                 LOGD("detected charset is %s\n", charset);
5765                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5766         }
5767
5768         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5769         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5770
5771         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5772                 LOGW("failed to add subparse\n");
5773                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5774                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5775                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5776                 goto ERROR;
5777         }
5778
5779         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5780                 LOGW("failed to link subsrc and subparse\n");
5781                 goto ERROR;
5782         }
5783
5784         player->play_subtitle = TRUE;
5785         player->adjust_subtitle_pos = 0;
5786
5787         LOGD("play subtitle using subtitle file\n");
5788
5789         if (player->pipeline->textbin == NULL) {
5790                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5791                         LOGE("failed to create text sink bin. continuing without text\n");
5792                         goto ERROR;
5793                 }
5794
5795                 textbin = player->pipeline->textbin;
5796
5797                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5798                         LOGW("failed to add textbin\n");
5799
5800                         /* release signal */
5801                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5802
5803                         /* release textbin with it's childs */
5804                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5805                         MMPLAYER_FREEIF(player->pipeline->textbin);
5806                         player->pipeline->textbin = textbin = NULL;
5807                         goto ERROR;
5808                 }
5809
5810                 LOGD("link text input selector and textbin ghost pad");
5811
5812                 player->textsink_linked = 1;
5813                 player->external_text_idx = 0;
5814                 LOGI("player->textsink_linked set to 1\n");
5815         } else {
5816                 textbin = player->pipeline->textbin;
5817                 LOGD("text bin has been created. reuse it.");
5818                 player->external_text_idx = 1;
5819         }
5820
5821         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5822                 LOGW("failed to link subparse and textbin\n");
5823                 goto ERROR;
5824         }
5825
5826         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5827         if (!pad) {
5828                 LOGE("failed to get sink pad from textsink to probe data");
5829                 goto ERROR;
5830         }
5831
5832         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5833                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5834
5835         gst_object_unref(pad);
5836         pad = NULL;
5837
5838         /* create dot. for debugging */
5839         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5840         MMPLAYER_FLEAVE();
5841
5842         return MM_ERROR_NONE;
5843
5844 ERROR:
5845         /* release text pipeline resource */
5846         player->textsink_linked = 0;
5847
5848         /* release signal */
5849         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5850
5851         if (player->pipeline->textbin) {
5852                 LOGE("remove textbin");
5853
5854                 /* release textbin with it's childs */
5855                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5856                 MMPLAYER_FREEIF(player->pipeline->textbin);
5857                 player->pipeline->textbin = NULL;
5858
5859         }
5860
5861         /* release subtitle elem */
5862         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5863         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5864
5865         return MM_ERROR_PLAYER_INTERNAL;
5866 }
5867
5868 gboolean
5869 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5870 {
5871         mm_player_t* player = (mm_player_t*) data;
5872         MMMessageParamType msg = {0, };
5873         GstClockTime duration = 0;
5874         gpointer text = NULL;
5875         guint text_size = 0;
5876         gboolean ret = TRUE;
5877         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5878
5879         MMPLAYER_FENTER();
5880
5881         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5882         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5883
5884         if (player->is_subtitle_force_drop) {
5885                 LOGW("subtitle is dropped forcedly.");
5886                 return ret;
5887         }
5888
5889         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5890         text = mapinfo.data;
5891         text_size = mapinfo.size;
5892         duration = GST_BUFFER_DURATION(buffer);
5893
5894         if (player->set_mode.subtitle_off) {
5895                 LOGD("subtitle is OFF.\n");
5896                 return TRUE;
5897         }
5898
5899         if (!text || (text_size == 0)) {
5900                 LOGD("There is no subtitle to be displayed.\n");
5901                 return TRUE;
5902         }
5903
5904         msg.data = (void *) text;
5905         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5906
5907         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5908
5909         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5910         gst_buffer_unmap(buffer, &mapinfo);
5911
5912         MMPLAYER_FLEAVE();
5913
5914         return ret;
5915 }
5916
5917 static GstPadProbeReturn
5918 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5919 {
5920         mm_player_t *player = (mm_player_t *) u_data;
5921         GstClockTime cur_timestamp = 0;
5922         gint64 adjusted_timestamp = 0;
5923         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5924
5925         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5926
5927         if (player->set_mode.subtitle_off) {
5928                 LOGD("subtitle is OFF.\n");
5929                 return TRUE;
5930         }
5931
5932         if (player->adjust_subtitle_pos == 0) {
5933                 LOGD("nothing to do");
5934                 return TRUE;
5935         }
5936
5937         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5938         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5939
5940         if (adjusted_timestamp < 0) {
5941                 LOGD("adjusted_timestamp under zero");
5942                 MMPLAYER_FLEAVE();
5943                 return FALSE;
5944         }
5945
5946         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5947         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5948                                 GST_TIME_ARGS(cur_timestamp),
5949                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5950
5951         return GST_PAD_PROBE_OK;
5952 }
5953 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5954 {
5955         MMPLAYER_FENTER();
5956
5957         /* check player and subtitlebin are created */
5958         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5959         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5960
5961         if (position == 0) {
5962                 LOGD("nothing to do\n");
5963                 MMPLAYER_FLEAVE();
5964                 return MM_ERROR_NONE;
5965         }
5966
5967         switch (format) {
5968         case MM_PLAYER_POS_FORMAT_TIME:
5969                 {
5970                         /* check current postion */
5971                         player->adjust_subtitle_pos = position;
5972
5973                         LOGD("save adjust_subtitle_pos in player") ;
5974                 }
5975                 break;
5976
5977         default:
5978                 {
5979                         LOGW("invalid format.\n");
5980                         MMPLAYER_FLEAVE();
5981                         return MM_ERROR_INVALID_ARGUMENT;
5982                 }
5983         }
5984
5985         MMPLAYER_FLEAVE();
5986
5987         return MM_ERROR_NONE;
5988 }
5989 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5990 {
5991         MMPLAYER_FENTER();
5992         LOGD("adjusting video_pos in player") ;
5993         int current_pos = 0;
5994         /* check player and videobin are created */
5995         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5996         if (!player->pipeline->videobin ||
5997                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5998                 LOGD("no video pipeline or sink is there");
5999                 return MM_ERROR_PLAYER_INVALID_STATE ;
6000         }
6001         if (offset == 0) {
6002                 LOGD("nothing to do\n");
6003                 MMPLAYER_FLEAVE();
6004                 return MM_ERROR_NONE;
6005         }
6006         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6007                 LOGD("failed to get current position");
6008                 return MM_ERROR_PLAYER_INTERNAL;
6009         }
6010         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6011                 LOGD("enter video delay is valid");
6012         } else {
6013                 LOGD("enter video delay is crossing content boundary");
6014                 return MM_ERROR_INVALID_ARGUMENT ;
6015         }
6016         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6017         LOGD("video delay has been done");
6018         MMPLAYER_FLEAVE();
6019
6020         return MM_ERROR_NONE;
6021 }
6022
6023 static void
6024 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6025 {
6026         GstElement *appsrc = element;
6027         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6028         GstBuffer *buffer = NULL;
6029         GstFlowReturn ret = GST_FLOW_OK;
6030         gint len = size;
6031
6032         MMPLAYER_RETURN_IF_FAIL(element);
6033         MMPLAYER_RETURN_IF_FAIL(buf);
6034
6035         buffer = gst_buffer_new();
6036
6037         if (buf->offset >= buf->len) {
6038                 LOGD("call eos appsrc\n");
6039                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6040                 return;
6041         }
6042
6043         if (buf->len - buf->offset < size)
6044                 len = buf->len - buf->offset;
6045
6046         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6047         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6048         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6049
6050         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6051         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6052
6053         buf->offset += len;
6054 }
6055
6056 static gboolean
6057 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6058 {
6059         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6060
6061         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6062
6063         buf->offset  = (int)size;
6064
6065         return TRUE;
6066 }
6067
6068 static GstBusSyncReply
6069 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6070 {
6071         mm_player_t *player = (mm_player_t *)data;
6072         GstBusSyncReply reply = GST_BUS_DROP;
6073
6074         if (!(player->pipeline && player->pipeline->mainbin)) {
6075                 LOGE("player pipeline handle is null");
6076                 return GST_BUS_PASS;
6077         }
6078
6079         if (!__mmplayer_check_useful_message(player, message)) {
6080                 gst_message_unref(message);
6081                 return GST_BUS_DROP;
6082         }
6083
6084         switch (GST_MESSAGE_TYPE(message)) {
6085         case GST_MESSAGE_STATE_CHANGED:
6086                 /* post directly for fast launch */
6087                 if (player->sync_handler) {
6088                         __mmplayer_gst_callback(message, player);
6089                         reply = GST_BUS_DROP;
6090                 } else
6091                         reply = GST_BUS_PASS;
6092                 break;
6093         case GST_MESSAGE_TAG:
6094                 __mmplayer_gst_extract_tag_from_msg(player, message);
6095
6096                 #if 0 // debug
6097                 {
6098                         GstTagList *tags = NULL;
6099
6100                         gst_message_parse_tag(message, &tags);
6101                         if (tags) {
6102                                 LOGE("TAGS received from element \"%s\".\n",
6103                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6104
6105                                 gst_tag_list_foreach(tags, print_tag, NULL);
6106                                 gst_tag_list_free(tags);
6107                                 tags = NULL;
6108                         }
6109                         break;
6110                 }
6111                 #endif
6112                 break;
6113
6114         case GST_MESSAGE_DURATION_CHANGED:
6115                 __mmplayer_gst_handle_duration(player, message);
6116                 break;
6117         case GST_MESSAGE_ASYNC_DONE:
6118                 /* NOTE:Don't call gst_callback directly
6119                  * because previous frame can be showed even though this message is received for seek.
6120                  */
6121         default:
6122                 reply = GST_BUS_PASS;
6123                 break;
6124         }
6125
6126         if (reply == GST_BUS_DROP)
6127                 gst_message_unref(message);
6128
6129         return reply;
6130 }
6131
6132 static gboolean
6133 __mmplayer_gst_create_decoder(mm_player_t *player,
6134                                                                 MMPlayerTrackType track,
6135                                                                 GstPad* srcpad,
6136                                                                 enum MainElementID elemId,
6137                                                                 const gchar* name)
6138 {
6139         gboolean ret = TRUE;
6140         GstPad *sinkpad = NULL;
6141
6142         MMPLAYER_FENTER();
6143
6144         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6145                                                 player->pipeline &&
6146                                                 player->pipeline->mainbin, FALSE);
6147         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6148         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6149         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6150
6151         GstElement *decodebin = NULL;
6152         GstCaps *dec_caps = NULL;
6153
6154         /* create decodebin */
6155         decodebin = gst_element_factory_make("decodebin", name);
6156
6157         if (!decodebin) {
6158                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6159                 ret = FALSE;
6160                 goto ERROR;
6161         }
6162
6163         /* raw pad handling signal */
6164         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6165                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6166
6167         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6168         before looking for any elements that can handle that stream.*/
6169         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6170                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6171
6172         /* This signal is emitted when a element is added to the bin.*/
6173         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6174                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6175
6176         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6177                 LOGE("failed to add new decodebin\n");
6178                 ret = FALSE;
6179                 goto ERROR;
6180         }
6181
6182         dec_caps = gst_pad_query_caps(srcpad, NULL);
6183         if (dec_caps) {
6184                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6185                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6186                 gst_caps_unref(dec_caps);
6187         }
6188
6189         player->pipeline->mainbin[elemId].id = elemId;
6190         player->pipeline->mainbin[elemId].gst = decodebin;
6191
6192         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6193
6194         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6195                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6196                 gst_object_unref(GST_OBJECT(decodebin));
6197         }
6198
6199         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6200                 LOGE("failed to sync second level decodebin state with parent\n");
6201
6202         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6203
6204 ERROR:
6205         if (sinkpad) {
6206                 gst_object_unref(GST_OBJECT(sinkpad));
6207                 sinkpad = NULL;
6208         }
6209         MMPLAYER_FLEAVE();
6210
6211         return ret;
6212 }
6213
6214 /**
6215  * This function is to create  audio or video pipeline for playing.
6216  *
6217  * @param       player          [in]    handle of player
6218  *
6219  * @return      This function returns zero on success.
6220  * @remark
6221  * @see
6222  */
6223 static int
6224 __mmplayer_gst_create_pipeline(mm_player_t* player)
6225 {
6226         GstBus  *bus = NULL;
6227         MMPlayerGstElement *mainbin = NULL;
6228         MMHandleType attrs = 0;
6229         GstElement* element = NULL;
6230         GstElement* elem_src_audio = NULL;
6231         GstElement* elem_src_subtitle = NULL;
6232         GstElement* es_video_queue = NULL;
6233         GstElement* es_audio_queue = NULL;
6234         GstElement* es_subtitle_queue = NULL;
6235         GList* element_bucket = NULL;
6236         gboolean need_state_holder = TRUE;
6237         gint i = 0;
6238 #ifdef SW_CODEC_ONLY
6239         int surface_type = 0;
6240 #endif
6241         MMPLAYER_FENTER();
6242
6243         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6244
6245         /* get profile attribute */
6246         attrs = MMPLAYER_GET_ATTRS(player);
6247         if (!attrs) {
6248                 LOGE("cannot get content attribute\n");
6249                 goto INIT_ERROR;
6250         }
6251
6252         /* create pipeline handles */
6253         if (player->pipeline) {
6254                 LOGW("pipeline should be released before create new one\n");
6255                 goto INIT_ERROR;
6256         }
6257
6258         player->video360_metadata.is_spherical = -1;
6259         player->is_openal_plugin_used = FALSE;
6260
6261         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6262         if (player->pipeline == NULL)
6263                 goto INIT_ERROR;
6264
6265         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6266
6267         /* create mainbin */
6268         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6269         if (mainbin == NULL)
6270                 goto INIT_ERROR;
6271
6272         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6273
6274         /* create pipeline */
6275         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6276         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6277         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6278                 LOGE("failed to create pipeline\n");
6279                 goto INIT_ERROR;
6280         }
6281         player->demux_pad_index = 0;
6282         player->subtitle_language_list = NULL;
6283
6284         player->is_subtitle_force_drop = FALSE;
6285         player->last_multiwin_status = FALSE;
6286
6287         _mmplayer_track_initialize(player);
6288         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6289
6290         /* create source element */
6291         switch (player->profile.uri_type) {
6292         /* rtsp streamming */
6293         case MM_PLAYER_URI_TYPE_URL_RTSP:
6294                 {
6295                         gchar *user_agent;
6296
6297                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6298
6299                         if (!element) {
6300                                 LOGE("failed to create streaming source element\n");
6301                                 break;
6302                         }
6303
6304                         /* make it zero */
6305                         user_agent = NULL;
6306
6307                         /* get attribute */
6308                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6309
6310                         SECURE_LOGD("user_agent : %s\n", user_agent);
6311
6312                         /* setting property to streaming source */
6313                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6314                         if (user_agent)
6315                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6316
6317                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6318                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6319                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6320                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6321                 }
6322                 break;
6323
6324         /* http streaming*/
6325         case MM_PLAYER_URI_TYPE_URL_HTTP:
6326                 {
6327                         gchar *user_agent, *cookies, **cookie_list;
6328                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6329                         user_agent = cookies = NULL;
6330                         cookie_list = NULL;
6331                         gint mode = MM_PLAYER_PD_MODE_NONE;
6332
6333                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6334
6335                         player->pd_mode = mode;
6336
6337                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6338
6339                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6340                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6341                                 if (!element) {
6342                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6343                                         break;
6344                                 }
6345                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6346
6347                                 /* get attribute */
6348                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6349                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6350
6351                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6352                                         LOGD("get timeout from ini\n");
6353                                         http_timeout = player->ini.http_timeout;
6354                                 }
6355
6356                                 /* get attribute */
6357                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6358                                 SECURE_LOGD("cookies : %s\n", cookies);
6359                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6360                                 LOGD("timeout : %d\n",  http_timeout);
6361
6362                                 /* setting property to streaming source */
6363                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6364                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6365                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6366
6367                                 /* parsing cookies */
6368                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6369                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6370                                         g_strfreev(cookie_list);
6371                                 }
6372                                 if (user_agent)
6373                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6374
6375                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6376                                         LOGW("it's dash. and it's still experimental feature.");
6377                         } else {
6378                                 // progressive download
6379                                 gchar* location = NULL;
6380
6381                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6382                                         gchar *path = NULL;
6383
6384                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6385
6386                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6387
6388                                         LOGD("PD Location : %s\n", path);
6389
6390                                         if (path) {
6391                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6392                                                         LOGE("failed to get storage info");
6393                                                         break;
6394                                                 }
6395                                                 player->pd_file_save_path = g_strdup(path);
6396                                         } else {
6397                                                 LOGE("can't find pd location so, it should be set \n");
6398                                                 break;
6399                                         }
6400                                 }
6401
6402                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6403                                 if (!element) {
6404                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6405                                         break;
6406                                 }
6407
6408                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6409                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6410                                 else
6411                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6412                                 g_object_get(element, "location", &location, NULL);
6413                                 LOGD("PD_LOCATION [%s].\n", location);
6414                                 if (location)
6415                                         g_free(location);
6416                         }
6417                 }
6418                 break;
6419
6420         /* file source */
6421         case MM_PLAYER_URI_TYPE_FILE:
6422                 {
6423                         LOGD("using filesrc for 'file://' handler.\n");
6424                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6425                                 LOGE("failed to get storage info");
6426                                 break;
6427                         }
6428
6429                         element = gst_element_factory_make("filesrc", "source");
6430                         if (!element) {
6431                                 LOGE("failed to create filesrc\n");
6432                                 break;
6433                         }
6434
6435                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6436                 }
6437                 break;
6438
6439         case MM_PLAYER_URI_TYPE_SS:
6440                 {
6441                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6442                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6443                         if (!element) {
6444                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6445                                 break;
6446                         }
6447
6448                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6449                                 LOGD("get timeout from ini\n");
6450                                 http_timeout = player->ini.http_timeout;
6451                         }
6452
6453                         /* setting property to streaming source */
6454                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6455                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6456                 }
6457                 break;
6458         case MM_PLAYER_URI_TYPE_MS_BUFF:
6459                 {
6460                         LOGD("MS buff src is selected\n");
6461
6462                         if (player->v_stream_caps) {
6463                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6464                                 if (!element) {
6465                                         LOGF("failed to create video app source element[appsrc].\n");
6466                                         break;
6467                                 }
6468
6469                                 if (player->a_stream_caps) {
6470                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6471                                         if (!elem_src_audio) {
6472                                                 LOGF("failed to create audio app source element[appsrc].\n");
6473                                                 break;
6474                                         }
6475                                 }
6476                         } else if (player->a_stream_caps) {
6477                                 /* no video, only audio pipeline*/
6478                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6479                                 if (!element) {
6480                                         LOGF("failed to create audio app source element[appsrc].\n");
6481                                         break;
6482                                 }
6483                         }
6484
6485                         if (player->s_stream_caps) {
6486                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6487                                 if (!elem_src_subtitle) {
6488                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6489                                         break;
6490                                 }
6491                         }
6492
6493                         LOGD("setting app sources properties.\n");
6494                         LOGD("location : %s\n", player->profile.uri);
6495
6496                         if (player->v_stream_caps && element) {
6497                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6498                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6499                                                                                                 "caps", player->v_stream_caps, NULL);
6500
6501                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6502                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6503                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6504                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6505
6506                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6507                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6508                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6509                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6510
6511                                 if (player->a_stream_caps && elem_src_audio) {
6512                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6513                                                                                                                         "caps", player->a_stream_caps, NULL);
6514
6515                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6516                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6517                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6518                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6519
6520                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6521                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6522                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6523                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6524                                 }
6525                         } else if (player->a_stream_caps && element) {
6526                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6527                                                                                                 "caps", player->a_stream_caps, NULL);
6528
6529                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6530                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6531                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6532                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6533
6534                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6535                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6536                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6537                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6538                         }
6539
6540                         if (player->s_stream_caps && elem_src_subtitle) {
6541                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6542                                                                                                                  "caps", player->s_stream_caps, NULL);
6543
6544                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6545                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6546                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6547                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6548
6549                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6550
6551                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6552                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6553                         }
6554
6555                         if (player->v_stream_caps && element) {
6556                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6557                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6558                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6559                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6560
6561                                 if (player->a_stream_caps && elem_src_audio) {
6562                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6563                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6564                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6565                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6566                                 }
6567                         } else if (player->a_stream_caps && element) {
6568                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6569                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6570                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6571                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6572                         }
6573
6574                         if (player->s_stream_caps && elem_src_subtitle)
6575                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6576                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6577
6578                         need_state_holder = FALSE;
6579
6580                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6581                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6582                                 LOGE("failed to commit\n");
6583                 }
6584                 break;
6585         /* appsrc */
6586         case MM_PLAYER_URI_TYPE_MEM:
6587                 {
6588                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6589
6590                         LOGD("mem src is selected\n");
6591
6592                         element = gst_element_factory_make("appsrc", "mem-source");
6593                         if (!element) {
6594                                 LOGE("failed to create appsrc element\n");
6595                                 break;
6596                         }
6597
6598                         g_object_set(element, "stream-type", stream_type, NULL);
6599                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6600                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6601
6602                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6603                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6604                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6605                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6606                 }
6607                 break;
6608         case MM_PLAYER_URI_TYPE_URL:
6609                 break;
6610
6611         case MM_PLAYER_URI_TYPE_TEMP:
6612                 break;
6613
6614         case MM_PLAYER_URI_TYPE_NONE:
6615         default:
6616                 break;
6617         }
6618
6619         /* check source element is OK */
6620         if (!element) {
6621                 LOGE("no source element was created.\n");
6622                 goto INIT_ERROR;
6623         }
6624
6625         /* take source element */
6626         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6627         mainbin[MMPLAYER_M_SRC].gst = element;
6628         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6629
6630         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6631                 player->streamer = __mm_player_streaming_create();
6632                 __mm_player_streaming_initialize(player->streamer);
6633         }
6634
6635         if (MMPLAYER_IS_HTTP_PD(player)) {
6636                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6637
6638                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6639                 element = gst_element_factory_make("queue2", "queue2");
6640                 if (!element) {
6641                         LOGE("failed to create http streaming buffer element\n");
6642                         goto INIT_ERROR;
6643                 }
6644
6645                 /* take it */
6646                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6647                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6648                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6649
6650                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6651
6652                 __mm_player_streaming_set_queue2(player->streamer,
6653                                 element,
6654                                 TRUE,
6655                                 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6656                                 pre_buffering_time,
6657                                 1.0,
6658                                 player->ini.http_buffering_limit,
6659                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6660                                 NULL,
6661                                 0);
6662         }
6663         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6664                 if (player->v_stream_caps) {
6665                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6666                         if (!es_video_queue) {
6667                                 LOGE("create es_video_queue for es player failed\n");
6668                                 goto INIT_ERROR;
6669                         }
6670                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6671                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6672                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6673                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6674
6675                         /* Adding audio appsrc to bucket */
6676                         if (player->a_stream_caps && elem_src_audio) {
6677                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6678                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6679                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6680
6681                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6682                                 if (!es_audio_queue) {
6683                                         LOGE("create es_audio_queue for es player failed\n");
6684                                         goto INIT_ERROR;
6685                                 }
6686                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6687
6688                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6689                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6690                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6691                         }
6692                 } else if (player->a_stream_caps) {
6693                         /* Only audio stream, no video */
6694                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6695                         if (!es_audio_queue) {
6696                                 LOGE("create es_audio_queue for es player failed\n");
6697                                 goto INIT_ERROR;
6698                         }
6699                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6700                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6701                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6702                 }
6703
6704                 if (player->s_stream_caps && elem_src_subtitle) {
6705                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6706                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6707                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6708
6709                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6710                         if (!es_subtitle_queue) {
6711                                 LOGE("create es_subtitle_queue for es player failed\n");
6712                                 goto INIT_ERROR;
6713                         }
6714                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6716                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6717                 }
6718         }
6719
6720         /* create autoplugging element if src element is not a rtsp src */
6721         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6722                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6723                 element = NULL;
6724                 enum MainElementID elemId = MMPLAYER_M_NUM;
6725
6726                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6727                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6728                         elemId = MMPLAYER_M_AUTOPLUG;
6729                         element = __mmplayer_create_decodebin(player);
6730                         if (element) {
6731                                 /* default size of mq in decodebin is 2M
6732                                  * but it can cause blocking issue during seeking depends on content. */
6733                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6734                         }
6735                         need_state_holder = FALSE;
6736                 } else {
6737                         elemId = MMPLAYER_M_TYPEFIND;
6738                         element = gst_element_factory_make("typefind", "typefinder");
6739                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6740                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6741                 }
6742
6743
6744                 /* check autoplug element is OK */
6745                 if (!element) {
6746                         LOGE("can not create element(%d)\n", elemId);
6747                         goto INIT_ERROR;
6748                 }
6749
6750                 mainbin[elemId].id = elemId;
6751                 mainbin[elemId].gst = element;
6752
6753                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6754         }
6755
6756         /* add elements to pipeline */
6757         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6758                 LOGE("Failed to add elements to pipeline\n");
6759                 goto INIT_ERROR;
6760         }
6761
6762
6763         /* linking elements in the bucket by added order. */
6764         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6765                 LOGE("Failed to link some elements\n");
6766                 goto INIT_ERROR;
6767         }
6768
6769
6770         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6771         if (need_state_holder) {
6772                 /* create */
6773                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6774                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6775
6776                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6777                         LOGE("fakesink element could not be created\n");
6778                         goto INIT_ERROR;
6779                 }
6780                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6781
6782                 /* take ownership of fakesink. we are reusing it */
6783                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6784
6785                 /* add */
6786                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6787                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6788                         LOGE("failed to add fakesink to bin\n");
6789                         goto INIT_ERROR;
6790                 }
6791         }
6792
6793         /* now we have completed mainbin. take it */
6794         player->pipeline->mainbin = mainbin;
6795
6796         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6797                 GstPad *srcpad = NULL;
6798
6799                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6800                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6801                         if (srcpad) {
6802                                 __mmplayer_gst_create_decoder(player,
6803                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6804                                                                                                 srcpad,
6805                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6806                                                                                                 "video_decodebin");
6807
6808                                 gst_object_unref(GST_OBJECT(srcpad));
6809                                 srcpad = NULL;
6810                         }
6811                 }
6812
6813                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6814                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6815                         if (srcpad) {
6816                                 __mmplayer_gst_create_decoder(player,
6817                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6818                                                                                                 srcpad,
6819                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6820                                                                                                 "audio_decodebin");
6821
6822                                 gst_object_unref(GST_OBJECT(srcpad));
6823                                 srcpad = NULL;
6824                         } // else error
6825                 } //  else error
6826
6827                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6828                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6829         }
6830
6831         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6832         if (__mmplayer_check_subtitle(player)) {
6833                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6834                         LOGE("fail to create text pipeline");
6835         }
6836
6837         /* connect bus callback */
6838         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6839         if (!bus) {
6840                 LOGE("cannot get bus from pipeline.\n");
6841                 goto INIT_ERROR;
6842         }
6843
6844         /* set sync handler to get tag synchronously */
6845         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6846
6847         /* finished */
6848         gst_object_unref(GST_OBJECT(bus));
6849         g_list_free(element_bucket);
6850
6851         /* create gst bus_msb_cb thread */
6852         g_mutex_init(&player->bus_msg_thread_mutex);
6853         g_cond_init(&player->bus_msg_thread_cond);
6854         player->bus_msg_thread_exit = FALSE;
6855         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6856         player->bus_msg_thread =
6857                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6858         if (!player->bus_msg_thread) {
6859                 LOGE("failed to create gst BUS msg thread");
6860                 g_mutex_clear(&player->bus_msg_thread_mutex);
6861                 g_cond_clear(&player->bus_msg_thread_cond);
6862                 goto INIT_ERROR;
6863         }
6864
6865         MMPLAYER_FLEAVE();
6866
6867         return MM_ERROR_NONE;
6868
6869 INIT_ERROR:
6870         __mmplayer_gst_destroy_pipeline(player);
6871         g_list_free(element_bucket);
6872
6873         if (mainbin) {
6874                 /* release element which are not added to bin */
6875                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6876                         /* NOTE : skip pipeline */
6877                         if (mainbin[i].gst) {
6878                                 GstObject* parent = NULL;
6879                                 parent = gst_element_get_parent(mainbin[i].gst);
6880
6881                                 if (!parent) {
6882                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6883                                         mainbin[i].gst = NULL;
6884                                 } else
6885                                         gst_object_unref(GST_OBJECT(parent));
6886                         }
6887                 }
6888
6889                 /* release pipeline with it's childs */
6890                 if (mainbin[MMPLAYER_M_PIPE].gst)
6891                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6892
6893                 MMPLAYER_FREEIF(mainbin);
6894         }
6895
6896         MMPLAYER_FREEIF(player->pipeline);
6897         return MM_ERROR_PLAYER_INTERNAL;
6898 }
6899
6900 static void
6901 __mmplayer_reset_gapless_state(mm_player_t* player)
6902 {
6903         MMPLAYER_FENTER();
6904         MMPLAYER_RETURN_IF_FAIL(player
6905                 && player->pipeline
6906                 && player->pipeline->audiobin
6907                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6908
6909         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6910
6911         MMPLAYER_FLEAVE();
6912         return;
6913 }
6914
6915 static int
6916 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6917 {
6918         gint timeout = 0;
6919         int ret = MM_ERROR_NONE;
6920
6921         MMPLAYER_FENTER();
6922
6923         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6924
6925         /* cleanup stuffs */
6926         MMPLAYER_FREEIF(player->type);
6927         player->have_dynamic_pad = FALSE;
6928         player->no_more_pad = FALSE;
6929         player->num_dynamic_pad = 0;
6930         player->demux_pad_index = 0;
6931         player->use_deinterleave = FALSE;
6932         player->max_audio_channels = 0;
6933         player->video_share_api_delta = 0;
6934         player->video_share_clock_delta = 0;
6935         player->video_hub_download_mode = 0;
6936
6937         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6938         player->subtitle_language_list = NULL;
6939         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6940
6941         __mmplayer_reset_gapless_state(player);
6942
6943         if (player->streamer) {
6944                 __mm_player_streaming_deinitialize(player->streamer);
6945                 __mm_player_streaming_destroy(player->streamer);
6946                 player->streamer = NULL;
6947         }
6948
6949         /* cleanup unlinked mime type */
6950         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6951         MMPLAYER_FREEIF(player->unlinked_video_mime);
6952         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6953
6954         /* cleanup running stuffs */
6955         __mmplayer_cancel_eos_timer(player);
6956
6957         /* cleanup gst stuffs */
6958         if (player->pipeline) {
6959                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6960                 GstTagList* tag_list = player->pipeline->tag_list;
6961
6962                 /* first we need to disconnect all signal hander */
6963                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6964
6965                 if (mainbin) {
6966                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6967                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6968                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6969                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6970                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6971                         gst_object_unref(bus);
6972
6973                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6974                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6975                         if (ret != MM_ERROR_NONE) {
6976                                 LOGE("fail to change state to NULL\n");
6977                                 return MM_ERROR_PLAYER_INTERNAL;
6978                         }
6979
6980                         LOGW("succeeded in chaning state to NULL\n");
6981
6982                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6983
6984                         /* free fakesink */
6985                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6986                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6987
6988                         /* free avsysaudiosink
6989                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6990                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6991                         */
6992                         MMPLAYER_FREEIF(audiobin);
6993                         MMPLAYER_FREEIF(videobin);
6994                         MMPLAYER_FREEIF(textbin);
6995                         MMPLAYER_FREEIF(mainbin);
6996                 }
6997
6998                 if (tag_list)
6999                         gst_tag_list_free(tag_list);
7000
7001                 MMPLAYER_FREEIF(player->pipeline);
7002         }
7003         MMPLAYER_FREEIF(player->album_art);
7004
7005         if (player->v_stream_caps) {
7006                 gst_caps_unref(player->v_stream_caps);
7007                 player->v_stream_caps = NULL;
7008         }
7009         if (player->a_stream_caps) {
7010                 gst_caps_unref(player->a_stream_caps);
7011                 player->a_stream_caps = NULL;
7012         }
7013
7014         if (player->s_stream_caps) {
7015                 gst_caps_unref(player->s_stream_caps);
7016                 player->s_stream_caps = NULL;
7017         }
7018         _mmplayer_track_destroy(player);
7019
7020         if (player->sink_elements)
7021                 g_list_free(player->sink_elements);
7022         player->sink_elements = NULL;
7023
7024         if (player->bufmgr) {
7025                 tbm_bufmgr_deinit(player->bufmgr);
7026                 player->bufmgr = NULL;
7027         }
7028
7029         LOGW("finished destroy pipeline\n");
7030
7031         MMPLAYER_FLEAVE();
7032
7033         return ret;
7034 }
7035
7036 static int __gst_realize(mm_player_t* player)
7037 {
7038         gint timeout = 0;
7039         int ret = MM_ERROR_NONE;
7040
7041         MMPLAYER_FENTER();
7042
7043         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7044
7045         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7046
7047         ret = __mmplayer_gst_create_pipeline(player);
7048         if (ret) {
7049                 LOGE("failed to create pipeline\n");
7050                 return ret;
7051         }
7052
7053         /* set pipeline state to READY */
7054         /* NOTE : state change to READY must be performed sync. */
7055         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7056         ret = __mmplayer_gst_set_state(player,
7057                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7058
7059         if (ret != MM_ERROR_NONE) {
7060                 /* return error if failed to set state */
7061                 LOGE("failed to set READY state");
7062                 return ret;
7063         }
7064
7065         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7066
7067         /* create dot before error-return. for debugging */
7068         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7069
7070         MMPLAYER_FLEAVE();
7071
7072         return ret;
7073 }
7074
7075 static int __gst_unrealize(mm_player_t* player)
7076 {
7077         int ret = MM_ERROR_NONE;
7078
7079         MMPLAYER_FENTER();
7080
7081         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7082
7083         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7084         MMPLAYER_PRINT_STATE(player);
7085
7086         /* release miscellaneous information */
7087         __mmplayer_release_misc(player);
7088
7089         /* destroy pipeline */
7090         ret = __mmplayer_gst_destroy_pipeline(player);
7091         if (ret != MM_ERROR_NONE) {
7092                 LOGE("failed to destory pipeline\n");
7093                 return ret;
7094         }
7095
7096         /* release miscellaneous information.
7097            these info needs to be released after pipeline is destroyed. */
7098         __mmplayer_release_misc_post(player);
7099
7100         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7101
7102         MMPLAYER_FLEAVE();
7103
7104         return ret;
7105 }
7106
7107 static int __gst_pending_seek(mm_player_t* player)
7108 {
7109         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7110         int ret = MM_ERROR_NONE;
7111
7112         MMPLAYER_FENTER();
7113
7114         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7115
7116         if (!player->pending_seek.is_pending) {
7117                 LOGD("pending seek is not reserved. nothing to do.\n");
7118                 return ret;
7119         }
7120
7121         /* check player state if player could pending seek or not. */
7122         current_state = MMPLAYER_CURRENT_STATE(player);
7123
7124         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7125                 LOGW("try to pending seek in %s state, try next time. \n",
7126                         MMPLAYER_STATE_GET_NAME(current_state));
7127                 return ret;
7128         }
7129
7130         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7131
7132         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7133
7134         if (MM_ERROR_NONE != ret)
7135                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7136
7137         player->pending_seek.is_pending = FALSE;
7138
7139         MMPLAYER_FLEAVE();
7140
7141         return ret;
7142 }
7143
7144 static int __gst_start(mm_player_t* player)
7145 {
7146         gboolean sound_extraction = 0;
7147         int ret = MM_ERROR_NONE;
7148         gboolean async = FALSE;
7149
7150         MMPLAYER_FENTER();
7151
7152         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7153
7154         /* get sound_extraction property */
7155         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7156
7157         /* NOTE : if SetPosition was called before Start. do it now */
7158         /* streaming doesn't support it. so it should be always sync */
7159         /* !!create one more api to check if there is pending seek rather than checking variables */
7160         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7161                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7162                 ret = __gst_pause(player, FALSE);
7163                 if (ret != MM_ERROR_NONE) {
7164                         LOGE("failed to set state to PAUSED for pending seek\n");
7165                         return ret;
7166                 }
7167
7168                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7169
7170                 if (sound_extraction) {
7171                         LOGD("setting pcm extraction\n");
7172
7173                         ret = __mmplayer_set_pcm_extraction(player);
7174                         if (MM_ERROR_NONE != ret) {
7175                                 LOGW("failed to set pcm extraction\n");
7176                                 return ret;
7177                         }
7178                 } else {
7179                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7180                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7181                 }
7182         }
7183
7184         LOGD("current state before doing transition");
7185         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7186         MMPLAYER_PRINT_STATE(player);
7187
7188         /* set pipeline state to PLAYING  */
7189         if (player->es_player_push_mode)
7190                 async = TRUE;
7191         /* set pipeline state to PLAYING  */
7192         ret = __mmplayer_gst_set_state(player,
7193                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7194
7195         if (ret == MM_ERROR_NONE) {
7196                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7197         } else {
7198                 LOGE("failed to set state to PLAYING");
7199                 return ret;
7200         }
7201
7202         /* generating debug info before returning error */
7203         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7204
7205         MMPLAYER_FLEAVE();
7206
7207         return ret;
7208 }
7209
7210 static int __gst_stop(mm_player_t* player)
7211 {
7212         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7213         MMHandleType attrs = 0;
7214         gboolean rewind = FALSE;
7215         gint timeout = 0;
7216         int ret = MM_ERROR_NONE;
7217         gboolean async = FALSE;
7218
7219         MMPLAYER_FENTER();
7220
7221         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7222         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7223
7224         LOGD("current state before doing transition");
7225         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7226         MMPLAYER_PRINT_STATE(player);
7227
7228         attrs = MMPLAYER_GET_ATTRS(player);
7229         if (!attrs) {
7230                 LOGE("cannot get content attribute\n");
7231                 return MM_ERROR_PLAYER_INTERNAL;
7232         }
7233
7234         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7235         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7236
7237         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7238                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7239                 rewind = TRUE;
7240
7241         if (player->es_player_push_mode)
7242                 async = TRUE;
7243         /* set gst state */
7244         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7245
7246         /* return if set_state has failed */
7247         if (ret != MM_ERROR_NONE) {
7248                 LOGE("failed to set state.\n");
7249                 return ret;
7250         }
7251
7252         /* rewind */
7253         if (rewind) {
7254                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7255                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7256                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7257                         LOGW("failed to rewind\n");
7258                         ret = MM_ERROR_PLAYER_SEEK;
7259                 }
7260         }
7261
7262         /* initialize */
7263         player->sent_bos = FALSE;
7264
7265         if (player->es_player_push_mode) //for cloudgame
7266                 timeout = 0;
7267
7268         /* wait for seek to complete */
7269         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7270         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7271                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7272         } else {
7273                 LOGE("fail to stop player.\n");
7274                 ret = MM_ERROR_PLAYER_INTERNAL;
7275                 __mmplayer_dump_pipeline_state(player);
7276         }
7277
7278         /* generate dot file if enabled */
7279         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7280
7281         MMPLAYER_FLEAVE();
7282
7283         return ret;
7284 }
7285
7286 int __gst_pause(mm_player_t* player, gboolean async)
7287 {
7288         int ret = MM_ERROR_NONE;
7289
7290         MMPLAYER_FENTER();
7291
7292         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7293         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7294
7295         LOGD("current state before doing transition");
7296         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7297         MMPLAYER_PRINT_STATE(player);
7298
7299         /* set pipeline status to PAUSED */
7300         ret = __mmplayer_gst_set_state(player,
7301                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7302
7303         if (FALSE == async) {
7304                 if (ret != MM_ERROR_NONE) {
7305                         GstMessage *msg = NULL;
7306                         GTimer *timer = NULL;
7307                         gdouble MAX_TIMEOUT_SEC = 3;
7308
7309                         LOGE("failed to set state to PAUSED");
7310
7311                         if (player->msg_posted) {
7312                                 LOGE("error msg is already posted.");
7313                                 return ret;
7314                         }
7315
7316                         timer = g_timer_new();
7317                         g_timer_start(timer);
7318
7319                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7320
7321                         do {
7322                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7323                                 if (msg) {
7324                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7325                                                 GError *error = NULL;
7326
7327                                                 /* parse error code */
7328                                                 gst_message_parse_error(msg, &error, NULL);
7329
7330                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7331                                                         /* Note : the streaming error from the streaming source is handled
7332                                                          *   using __mmplayer_handle_streaming_error.
7333                                                          */
7334                                                         __mmplayer_handle_streaming_error(player, msg);
7335
7336                                                 } else if (error) {
7337                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7338
7339                                                         if (error->domain == GST_STREAM_ERROR)
7340                                                                 ret = __gst_handle_stream_error(player, error, msg);
7341                                                         else if (error->domain == GST_RESOURCE_ERROR)
7342                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7343                                                         else if (error->domain == GST_LIBRARY_ERROR)
7344                                                                 ret = __gst_handle_library_error(player, error->code);
7345                                                         else if (error->domain == GST_CORE_ERROR)
7346                                                                 ret = __gst_handle_core_error(player, error->code);
7347
7348                                                         g_error_free(error);
7349                                                 }
7350                                                 player->msg_posted = TRUE;
7351                                         }
7352                                         gst_message_unref(msg);
7353                                 }
7354                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7355                         /* clean */
7356                         gst_object_unref(bus);
7357                         g_timer_stop(timer);
7358                         g_timer_destroy(timer);
7359
7360                         return ret;
7361
7362                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7363                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7364
7365                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7366
7367                 } else if (ret == MM_ERROR_NONE) {
7368
7369                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7370                 }
7371         }
7372
7373         /* generate dot file before returning error */
7374         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7375
7376         MMPLAYER_FLEAVE();
7377
7378         return ret;
7379 }
7380
7381 int __gst_resume(mm_player_t* player, gboolean async)
7382 {
7383         int ret = MM_ERROR_NONE;
7384         gint timeout = 0;
7385
7386         MMPLAYER_FENTER();
7387
7388         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7389                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7390
7391         LOGD("current state before doing transition");
7392         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7393         MMPLAYER_PRINT_STATE(player);
7394
7395         /* generate dot file before returning error */
7396         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7397
7398         if (async)
7399                 LOGD("do async state transition to PLAYING.\n");
7400
7401         /* set pipeline state to PLAYING */
7402         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7403
7404         ret = __mmplayer_gst_set_state(player,
7405                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7406         if (ret != MM_ERROR_NONE) {
7407                 LOGE("failed to set state to PLAYING\n");
7408                 return ret;
7409         } else {
7410                 if (async == FALSE) {
7411                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7412                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7413                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7414                 }
7415         }
7416
7417         /* generate dot file before returning error */
7418         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7419
7420         MMPLAYER_FLEAVE();
7421
7422         return ret;
7423 }
7424
7425 static int
7426 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7427 {
7428         unsigned long dur_msec = 0;
7429         gint64 dur_nsec = 0;
7430         gint64 pos_nsec = 0;
7431         gboolean ret = TRUE;
7432         gboolean accurated = FALSE;
7433         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7434
7435         MMPLAYER_FENTER();
7436         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7437         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7438
7439         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7440                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7441                 goto PENDING;
7442
7443         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7444                 /* check duration */
7445                 /* NOTE : duration cannot be zero except live streaming.
7446                  *              Since some element could have some timing problemn with quering duration, try again.
7447                  */
7448                 if (!player->duration) {
7449                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7450                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7451                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7452                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7453                                         player->pending_seek.is_pending = TRUE;
7454                                         player->pending_seek.format = format;
7455                                         player->pending_seek.pos = position;
7456                                         player->doing_seek = FALSE;
7457                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7458                                         return MM_ERROR_NONE;
7459                                 } else {
7460                                         goto SEEK_ERROR;
7461                                 }
7462                         }
7463                         player->duration = dur_nsec;
7464                 }
7465
7466                 if (player->duration) {
7467                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7468                 } else {
7469                         LOGE("could not get the duration. fail to seek.\n");
7470                         goto SEEK_ERROR;
7471                 }
7472         }
7473         LOGD("playback rate: %f\n", player->playback_rate);
7474
7475         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7476         if (accurated)
7477                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7478         else
7479                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7480
7481         /* do seek */
7482         switch (format) {
7483         case MM_PLAYER_POS_FORMAT_TIME:
7484         {
7485                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7486                         GstQuery *query = NULL;
7487                         gboolean seekable = FALSE;
7488
7489                         /* check position is valid or not */
7490                         if (position > dur_msec)
7491                                 goto INVALID_ARGS;
7492
7493                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7494                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7495                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7496                                 gst_query_unref(query);
7497
7498                                 if (!seekable) {
7499                                         LOGW("non-seekable content");
7500                                         player->doing_seek = FALSE;
7501                                         return MM_ERROR_PLAYER_NO_OP;
7502                                 }
7503                         } else {
7504                                 LOGW("failed to get seeking query");
7505                                 gst_query_unref(query); /* keep seeking operation */
7506                         }
7507
7508                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7509
7510                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7511                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7512                            This causes problem is position calculation during normal pause resume scenarios also.
7513                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7514                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7515                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7516                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7517                                         LOGW("getting current position failed in seek\n");
7518
7519                                 player->last_position = pos_nsec;
7520                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7521                         }
7522
7523                         if (player->doing_seek) {
7524                                 LOGD("not completed seek");
7525                                 return MM_ERROR_PLAYER_DOING_SEEK;
7526                         }
7527                 }
7528
7529                 if (!internal_called)
7530                         player->doing_seek = TRUE;
7531
7532                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7533
7534                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7535                         gint64 cur_time = 0;
7536
7537                         /* get current position */
7538                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7539
7540                         /* flush */
7541                         GstEvent *event = gst_event_new_seek(1.0,
7542                                                         GST_FORMAT_TIME,
7543                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7544                                                         GST_SEEK_TYPE_SET, cur_time,
7545                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7546                         if (event)
7547                                 __gst_send_event_to_sink(player, event);
7548
7549                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7550                                 __gst_pause(player, FALSE);
7551                 }
7552
7553                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7554                         that's why set position through property. */
7555                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7556                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7557                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7558                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7559
7560                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7561                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7562                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7563                         player->doing_seek = FALSE;
7564                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7565                 } else {
7566                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7567                                                         GST_FORMAT_TIME, seek_flags,
7568                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7569                 }
7570
7571                 if (!ret) {
7572                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7573                         goto SEEK_ERROR;
7574                 }
7575         }
7576         break;
7577
7578         case MM_PLAYER_POS_FORMAT_PERCENT:
7579         {
7580                 LOGD("seeking to(%lu)%% \n", position);
7581
7582                 if (player->doing_seek) {
7583                         LOGD("not completed seek");
7584                         return MM_ERROR_PLAYER_DOING_SEEK;
7585                 }
7586
7587                 if (!internal_called)
7588                         player->doing_seek = TRUE;
7589
7590                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7591                 pos_nsec = (gint64)((position * player->duration) / 100);
7592                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7593                                                 GST_FORMAT_TIME, seek_flags,
7594                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7595                 if (!ret) {
7596                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7597                         goto SEEK_ERROR;
7598                 }
7599         }
7600         break;
7601
7602         default:
7603                 goto INVALID_ARGS;
7604         }
7605
7606         /* NOTE : store last seeking point to overcome some bad operation
7607           *     (returning zero when getting current position) of some elements
7608           */
7609         player->last_position = pos_nsec;
7610
7611         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7612         if (player->playback_rate > 1.0)
7613                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7614
7615         MMPLAYER_FLEAVE();
7616         return MM_ERROR_NONE;
7617
7618 PENDING:
7619         player->pending_seek.is_pending = TRUE;
7620         player->pending_seek.format = format;
7621         player->pending_seek.pos = position;
7622
7623         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7624                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7625
7626         return MM_ERROR_NONE;
7627
7628 INVALID_ARGS:
7629         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7630         return MM_ERROR_INVALID_ARGUMENT;
7631
7632 SEEK_ERROR:
7633         player->doing_seek = FALSE;
7634         return MM_ERROR_PLAYER_SEEK;
7635 }
7636
7637 #define TRICKPLAY_OFFSET GST_MSECOND
7638
7639 static int
7640 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7641 {
7642         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7643         gint64 pos_msec = 0;
7644         gboolean ret = TRUE;
7645
7646         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7647                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7648
7649         current_state = MMPLAYER_CURRENT_STATE(player);
7650
7651         /* NOTE : query position except paused state to overcome some bad operation
7652          * please refer to below comments in details
7653          */
7654         if (current_state != MM_PLAYER_STATE_PAUSED)
7655                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7656
7657         /* NOTE : get last point to overcome some bad operation of some elements
7658          *(returning zero when getting current position in paused state
7659          * and when failed to get postion during seeking
7660          */
7661         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7662                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7663
7664                 if (player->playback_rate < 0.0)
7665                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7666                 else
7667                         pos_msec = player->last_position;
7668
7669                 if (!ret)
7670                         pos_msec = player->last_position;
7671                 else
7672                         player->last_position = pos_msec;
7673
7674                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7675
7676         } else {
7677                 if (player->duration > 0 && pos_msec > player->duration)
7678                         pos_msec = player->duration;
7679
7680                 player->last_position = pos_msec;
7681         }
7682
7683         switch (format) {
7684         case MM_PLAYER_POS_FORMAT_TIME:
7685                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7686                 break;
7687
7688         case MM_PLAYER_POS_FORMAT_PERCENT:
7689         {
7690                 if (player->duration <= 0) {
7691                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7692                         *position = 0;
7693                 } else {
7694                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7695                         *position = pos_msec * 100 / player->duration;
7696                 }
7697                 break;
7698         }
7699         default:
7700                 return MM_ERROR_PLAYER_INTERNAL;
7701         }
7702
7703         return MM_ERROR_NONE;
7704 }
7705
7706
7707 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7708 {
7709 #define STREAMING_IS_FINISHED   0
7710 #define BUFFERING_MAX_PER       100
7711 #define DEFAULT_PER_VALUE       -1
7712 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7713
7714         MMPlayerGstElement *mainbin = NULL;
7715         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7716         gint64 buffered_total = 0;
7717         unsigned long position = 0;
7718         gint buffered_sec = -1;
7719         GstBufferingMode mode = GST_BUFFERING_STREAM;
7720         gint64 content_size_time = player->duration;
7721         guint64 content_size_bytes = player->http_content_size;
7722
7723         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7724                                                 player->pipeline &&
7725                                                 player->pipeline->mainbin,
7726                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7727
7728         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7729
7730         *start_pos = 0;
7731         *stop_pos = 0;
7732
7733         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7734                 /* and rtsp is not ready yet. */
7735                 LOGW("it's only used for http streaming case.\n");
7736                 return MM_ERROR_PLAYER_NO_OP;
7737         }
7738
7739         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7740                 LOGW("Time format is not supported yet.\n");
7741                 return MM_ERROR_INVALID_ARGUMENT;
7742         }
7743
7744         if (content_size_time <= 0 || content_size_bytes <= 0) {
7745                 LOGW("there is no content size.");
7746                 return MM_ERROR_NONE;
7747         }
7748
7749         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7750                 LOGW("fail to get current position.");
7751                 return MM_ERROR_NONE;
7752         }
7753
7754         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7755                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7756
7757         mainbin = player->pipeline->mainbin;
7758         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7759
7760         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7761                 GstQuery *query = NULL;
7762                 gint byte_in_rate = 0, byte_out_rate = 0;
7763                 gint64 estimated_total = 0;
7764
7765                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7766                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7767                         LOGW("fail to get buffering query from queue2");
7768                         if (query)
7769                                 gst_query_unref(query);
7770                         return MM_ERROR_NONE;
7771                 }
7772
7773                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7774                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7775
7776                 if (mode == GST_BUFFERING_STREAM) {
7777                         /* using only queue in case of push mode(ts / mp3) */
7778                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7779                                 GST_FORMAT_BYTES, &buffered_total)) {
7780                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7781                                 stop_per = 100 * buffered_total / content_size_bytes;
7782                         }
7783                 } else {
7784                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7785                         guint idx = 0;
7786                         guint num_of_ranges = 0;
7787                         gint64 start_byte = 0, stop_byte = 0;
7788
7789                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7790                         if (estimated_total != STREAMING_IS_FINISHED) {
7791                                 /* buffered size info from queue2 */
7792                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7793                                 for (idx = 0; idx < num_of_ranges; idx++) {
7794                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7795                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7796
7797                                         buffered_total += (stop_byte - start_byte);
7798                                 }
7799                         } else
7800                                 stop_per = BUFFERING_MAX_PER;
7801                 }
7802                 gst_query_unref(query);
7803         }
7804
7805         if (stop_per == DEFAULT_PER_VALUE) {
7806                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7807                 if (dur_sec > 0) {
7808                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7809
7810                         /* buffered size info from multiqueue */
7811                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7812                                 guint curr_size_bytes = 0;
7813                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7814                                         "curr-size-bytes", &curr_size_bytes, NULL);
7815                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7816                                 buffered_total += curr_size_bytes;
7817                         }
7818
7819                         if (avg_byterate > 0)
7820                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7821                         else if (player->total_maximum_bitrate > 0)
7822                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7823                         else if (player->total_bitrate > 0)
7824                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7825
7826                         if (buffered_sec >= 0)
7827                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7828                 }
7829         }
7830
7831         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7832         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7833
7834         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7835                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7836
7837         return MM_ERROR_NONE;
7838 }
7839
7840 static int
7841 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7842 {
7843         MMPLAYER_FENTER();
7844
7845         if (!player) {
7846                 LOGW("set_message_callback is called with invalid player handle\n");
7847                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7848         }
7849
7850         player->msg_cb = callback;
7851         player->msg_cb_param = user_param;
7852
7853         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7854
7855         MMPLAYER_FLEAVE();
7856
7857         return MM_ERROR_NONE;
7858 }
7859
7860 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7861 {
7862         int ret = MM_ERROR_PLAYER_INVALID_URI;
7863         char *path = NULL;
7864
7865         MMPLAYER_FENTER();
7866
7867         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7868         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7869         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7870
7871         memset(data, 0, sizeof(MMPlayerParseProfile));
7872
7873         if ((path = strstr(uri, "es_buff://"))) {
7874                 if (strlen(path)) {
7875                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7876                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7877                         ret = MM_ERROR_NONE;
7878                 }
7879         } else if ((path = strstr(uri, "rtsp://"))) {
7880                 if (strlen(path)) {
7881                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7883                         ret = MM_ERROR_NONE;
7884                 }
7885         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7886                 if (strlen(path)) {
7887                         gchar *tmp = NULL;
7888                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7889                         tmp = g_ascii_strdown(uri, strlen(uri));
7890
7891                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7892                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7893                         else
7894                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7895
7896                         ret = MM_ERROR_NONE;
7897                         g_free(tmp);
7898                 }
7899         } else if ((path = strstr(uri, "rtspu://"))) {
7900                 if (strlen(path)) {
7901                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7902                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7903                         ret = MM_ERROR_NONE;
7904                 }
7905         } else if ((path = strstr(uri, "rtspr://"))) {
7906                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7907                 char *separater = strstr(path, "*");
7908
7909                 if (separater) {
7910                         int urgent_len = 0;
7911                         char *urgent = separater + strlen("*");
7912
7913                         if ((urgent_len = strlen(urgent))) {
7914                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7915                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7916                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7917                                 ret = MM_ERROR_NONE;
7918                         }
7919                 }
7920         } else if ((path = strstr(uri, "mms://"))) {
7921                 if (strlen(path)) {
7922                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7923                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7924                         ret = MM_ERROR_NONE;
7925                 }
7926         } else if ((path = strstr(uri, "mem://"))) {
7927                 if (strlen(path)) {
7928                         int mem_size = 0;
7929                         char *buffer = NULL;
7930                         char *seperator = strchr(path, ',');
7931                         char ext[100] = {0,}, size[100] = {0,};
7932
7933                         if (seperator) {
7934                                 if ((buffer = strstr(path, "ext="))) {
7935                                         buffer += strlen("ext=");
7936
7937                                         if (strlen(buffer)) {
7938                                                 strncpy(ext, buffer, 99);
7939
7940                                                 if ((seperator = strchr(ext, ','))
7941                                                         || (seperator = strchr(ext, ' '))
7942                                                         || (seperator = strchr(ext, '\0'))) {
7943                                                         seperator[0] = '\0';
7944                                                 }
7945                                         }
7946                                 }
7947
7948                                 if ((buffer = strstr(path, "size="))) {
7949                                         buffer += strlen("size=");
7950
7951                                         if (strlen(buffer) > 0) {
7952                                                 strncpy(size, buffer, 99);
7953
7954                                                 if ((seperator = strchr(size, ','))
7955                                                         || (seperator = strchr(size, ' '))
7956                                                         || (seperator = strchr(size, '\0'))) {
7957                                                         seperator[0] = '\0';
7958                                                 }
7959
7960                                                 mem_size = atoi(size);
7961                                         }
7962                                 }
7963                         }
7964
7965                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7966                         if (mem_size && param) {
7967                                 if (data->input_mem.buf)
7968                                         free(data->input_mem.buf);
7969                                 data->input_mem.buf = malloc(mem_size);
7970
7971                                 if (data->input_mem.buf) {
7972                                         memcpy(data->input_mem.buf, param, mem_size);
7973                                         data->input_mem.len = mem_size;
7974                                         ret = MM_ERROR_NONE;
7975                                 } else {
7976                                         LOGE("failed to alloc mem %d", mem_size);
7977                                         ret = MM_ERROR_PLAYER_INTERNAL;
7978                                 }
7979
7980                                 data->input_mem.offset = 0;
7981                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7982                         }
7983                 }
7984         } else {
7985                 gchar *location = NULL;
7986                 GError *err = NULL;
7987
7988                 if ((path = strstr(uri, "file://"))) {
7989
7990                         location = g_filename_from_uri(uri, NULL, &err);
7991
7992                         if (!location || (err != NULL)) {
7993                           LOGE("Invalid URI '%s' for filesrc: %s", path,
7994                                  (err != NULL) ? err->message : "unknown error");
7995
7996                           if (err) g_error_free(err);
7997                           if (location) g_free(location);
7998
7999                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8000                           goto exit;
8001                         }
8002
8003                         LOGD("path from uri: %s", location);
8004                 }
8005
8006                 path = (location != NULL) ? (location) : ((char*)uri);
8007                 int file_stat = MM_ERROR_NONE;
8008
8009                 file_stat = util_exist_file_path(path);
8010
8011                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8012                 if (file_stat == MM_ERROR_NONE) {
8013                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8014
8015                         if (util_is_sdp_file(path)) {
8016                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8017                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8018                         } else {
8019                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8020                         }
8021                         ret = MM_ERROR_NONE;
8022                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8023                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8024                 } else {
8025                         LOGE("invalid uri, could not play..\n");
8026                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8027                 }
8028
8029                 if (location) g_free(location);
8030         }
8031
8032 exit:
8033         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8034                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8035         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8036                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8037
8038         /* dump parse result */
8039         SECURE_LOGW("incomming uri : %s\n", uri);
8040         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8041                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8042
8043         MMPLAYER_FLEAVE();
8044
8045         return ret;
8046 }
8047
8048 gboolean
8049 __mmplayer_can_do_interrupt(mm_player_t *player)
8050 {
8051         if (!player || !player->pipeline || !player->attrs) {
8052                 LOGW("not initialized");
8053                 goto FAILED;
8054         }
8055
8056         if (player->set_mode.pcm_extraction) {
8057                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8058                 goto FAILED;
8059         }
8060
8061         /* check if seeking */
8062         if (player->doing_seek) {
8063                 MMMessageParamType msg_param;
8064                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8065                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8066                 player->doing_seek = FALSE;
8067                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8068                 goto FAILED;
8069         }
8070
8071         /* check other thread */
8072         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8073                 LOGW("locked already, cmd state : %d", player->cmd);
8074
8075                 /* check application command */
8076                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8077                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8078
8079                         /* lock will be released at mrp_resource_release_cb() */
8080                         MMPLAYER_CMD_LOCK(player);
8081                         goto INTERRUPT;
8082                 }
8083                 LOGW("nothing to do");
8084                 goto FAILED;
8085         } else {
8086                 LOGW("can interrupt immediately");
8087                 goto INTERRUPT;
8088         }
8089
8090 FAILED:    /* with CMD UNLOCKED */
8091         return FALSE;
8092
8093 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8094         return TRUE;
8095 }
8096
8097 static int
8098 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8099                 void *user_data)
8100 {
8101         mm_player_t *player = NULL;
8102
8103         MMPLAYER_FENTER();
8104
8105         if (user_data == NULL) {
8106                 LOGE("- user_data is null\n");
8107                 return FALSE;
8108         }
8109         player = (mm_player_t *)user_data;
8110
8111         /* do something to release resource here.
8112          * player stop and interrupt forwarding */
8113         if (!__mmplayer_can_do_interrupt(player)) {
8114                 LOGW("no need to interrupt, so leave");
8115         } else {
8116                 MMMessageParamType msg = {0, };
8117                 unsigned long pos = 0;
8118
8119                 player->interrupted_by_resource = TRUE;
8120
8121                 /* get last play position */
8122                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8123                         LOGW("failed to get play position.");
8124                 } else {
8125                         msg.union_type = MM_MSG_UNION_TIME;
8126                         msg.time.elapsed = (unsigned int)pos;
8127                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8128                 }
8129                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8130                 if (_mmplayer_unrealize((MMHandleType)player))
8131                         LOGW("failed to unrealize");
8132
8133                 /* lock is called in __mmplayer_can_do_interrupt() */
8134                 MMPLAYER_CMD_UNLOCK(player);
8135         }
8136
8137         if (res == player->video_overlay_resource)
8138                 player->video_overlay_resource = FALSE;
8139         else
8140                 player->video_decoder_resource = FALSE;
8141
8142         MMPLAYER_FLEAVE();
8143
8144         return FALSE;
8145 }
8146
8147 int
8148 _mmplayer_create_player(MMHandleType handle)
8149 {
8150         int ret = MM_ERROR_PLAYER_INTERNAL;
8151         mm_player_t* player = MM_PLAYER_CAST(handle);
8152
8153         MMPLAYER_FENTER();
8154
8155         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8156
8157         /* initialize player state */
8158         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8159         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8160         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8161         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8162
8163         /* check current state */
8164         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8165
8166         /* construct attributes */
8167         player->attrs = _mmplayer_construct_attribute(handle);
8168
8169         if (!player->attrs) {
8170                 LOGE("Failed to construct attributes\n");
8171                 return ret;
8172         }
8173
8174         /* initialize gstreamer with configured parameter */
8175         if (!__mmplayer_init_gstreamer(player)) {
8176                 LOGE("Initializing gstreamer failed\n");
8177                 _mmplayer_deconstruct_attribute(handle);
8178                 return ret;
8179         }
8180
8181         /* create lock. note that g_tread_init() has already called in gst_init() */
8182         g_mutex_init(&player->fsink_lock);
8183
8184         /* create update tag lock */
8185         g_mutex_init(&player->update_tag_lock);
8186
8187         /* create next play mutex */
8188         g_mutex_init(&player->next_play_thread_mutex);
8189
8190         /* create next play cond */
8191         g_cond_init(&player->next_play_thread_cond);
8192
8193         /* create next play thread */
8194         player->next_play_thread =
8195                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8196         if (!player->next_play_thread) {
8197                 LOGE("failed to create next play thread");
8198                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8199                 g_mutex_clear(&player->next_play_thread_mutex);
8200                 g_cond_clear(&player->next_play_thread_cond);
8201                 goto ERROR;
8202         }
8203
8204         ret = _mmplayer_initialize_video_capture(player);
8205         if (ret != MM_ERROR_NONE) {
8206                 LOGE("failed to initialize video capture\n");
8207                 goto ERROR;
8208         }
8209
8210         /* initialize resource manager */
8211         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8212                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8213                         &player->resource_manager)) {
8214                 LOGE("failed to initialize resource manager\n");
8215                 goto ERROR;
8216         }
8217
8218         if (MMPLAYER_IS_HTTP_PD(player)) {
8219                 player->pd_downloader = NULL;
8220                 player->pd_file_save_path = NULL;
8221         }
8222
8223         /* create video bo lock and cond */
8224         g_mutex_init(&player->video_bo_mutex);
8225         g_cond_init(&player->video_bo_cond);
8226
8227         /* create media stream callback mutex */
8228         g_mutex_init(&player->media_stream_cb_lock);
8229
8230         /* create subtitle info lock and cond */
8231         g_mutex_init(&player->subtitle_info_mutex);
8232         g_cond_init(&player->subtitle_info_cond);
8233
8234         player->streaming_type = STREAMING_SERVICE_NONE;
8235
8236         /* give default value of audio effect setting */
8237         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8238         player->sound.rg_enable = false;
8239         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8240
8241         player->play_subtitle = FALSE;
8242         player->use_deinterleave = FALSE;
8243         player->max_audio_channels = 0;
8244         player->video_share_api_delta = 0;
8245         player->video_share_clock_delta = 0;
8246         player->has_closed_caption = FALSE;
8247         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8248         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8249         player->pending_resume = FALSE;
8250         if (player->ini.dump_element_keyword[0][0] == '\0')
8251                 player->ini.set_dump_element_flag = FALSE;
8252         else
8253                 player->ini.set_dump_element_flag = TRUE;
8254
8255         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8256         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8257         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8258
8259         /* Set video360 settings to their defaults for just-created player.
8260          * */
8261         player->is_content_spherical = FALSE;
8262         player->is_video360_enabled = TRUE;
8263         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8264         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8265         player->video360_yaw_radians = 4;
8266         player->video360_pitch_radians = 4;
8267         player->video360_zoom = 1.0f;
8268         player->video360_horizontal_fov = 0;
8269         player->video360_vertical_fov = 0;
8270
8271         /* set player state to null */
8272         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8273         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8274
8275         return MM_ERROR_NONE;
8276
8277 ERROR:
8278         /* free lock */
8279         g_mutex_clear(&player->fsink_lock);
8280
8281         /* free update tag lock */
8282         g_mutex_clear(&player->update_tag_lock);
8283
8284         /* free next play thread */
8285         if (player->next_play_thread) {
8286                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8287                 player->next_play_thread_exit = TRUE;
8288                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8289                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8290
8291                 g_thread_join(player->next_play_thread);
8292                 player->next_play_thread = NULL;
8293
8294                 g_mutex_clear(&player->next_play_thread_mutex);
8295                 g_cond_clear(&player->next_play_thread_cond);
8296         }
8297
8298         /* release attributes */
8299         _mmplayer_deconstruct_attribute(handle);
8300
8301         MMPLAYER_FLEAVE();
8302
8303         return ret;
8304 }
8305
8306 static gboolean
8307 __mmplayer_init_gstreamer(mm_player_t* player)
8308 {
8309         static gboolean initialized = FALSE;
8310         static const int max_argc = 50;
8311         gint* argc = NULL;
8312         gchar** argv = NULL;
8313         gchar** argv2 = NULL;
8314         GError *err = NULL;
8315         int i = 0;
8316         int arg_count = 0;
8317
8318         if (initialized) {
8319                 LOGD("gstreamer already initialized.\n");
8320                 return TRUE;
8321         }
8322
8323         /* alloc */
8324         argc = malloc(sizeof(int));
8325         argv = malloc(sizeof(gchar*) * max_argc);
8326         argv2 = malloc(sizeof(gchar*) * max_argc);
8327
8328         if (!argc || !argv || !argv2)
8329                 goto ERROR;
8330
8331         memset(argv, 0, sizeof(gchar*) * max_argc);
8332         memset(argv2, 0, sizeof(gchar*) * max_argc);
8333
8334         /* add initial */
8335         *argc = 1;
8336         argv[0] = g_strdup("mmplayer");
8337
8338         /* add gst_param */
8339         for (i = 0; i < 5; i++) {
8340                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8341                 if (strlen(player->ini.gst_param[i]) > 0) {
8342                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8343                         (*argc)++;
8344                 }
8345         }
8346
8347         /* we would not do fork for scanning plugins */
8348         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8349         (*argc)++;
8350
8351         /* check disable registry scan */
8352         if (player->ini.skip_rescan) {
8353                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8354                 (*argc)++;
8355         }
8356
8357         /* check disable segtrap */
8358         if (player->ini.disable_segtrap) {
8359                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8360                 (*argc)++;
8361         }
8362
8363         LOGD("initializing gstreamer with following parameter\n");
8364         LOGD("argc : %d\n", *argc);
8365         arg_count = *argc;
8366
8367         for (i = 0; i < arg_count; i++) {
8368                 argv2[i] = argv[i];
8369                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8370         }
8371
8372         /* initializing gstreamer */
8373         if (!gst_init_check(argc, &argv, &err)) {
8374                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8375                 if (err)
8376                         g_error_free(err);
8377
8378                 goto ERROR;
8379         }
8380         /* release */
8381         for (i = 0; i < arg_count; i++) {
8382                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8383                 MMPLAYER_FREEIF(argv2[i]);
8384         }
8385
8386         MMPLAYER_FREEIF(argv);
8387         MMPLAYER_FREEIF(argv2);
8388         MMPLAYER_FREEIF(argc);
8389
8390         /* done */
8391         initialized = TRUE;
8392
8393         return TRUE;
8394
8395 ERROR:
8396
8397         /* release */
8398         for (i = 0; i < arg_count; i++) {
8399                 LOGD("free[%d] : %s\n", i, argv2[i]);
8400                 MMPLAYER_FREEIF(argv2[i]);
8401         }
8402
8403         MMPLAYER_FREEIF(argv);
8404         MMPLAYER_FREEIF(argv2);
8405         MMPLAYER_FREEIF(argc);
8406
8407         return FALSE;
8408 }
8409
8410 int
8411 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8412 {
8413         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8414
8415         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8416                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8417                 MMPLAYER_FREEIF(player->pd_file_save_path);
8418         }
8419
8420         return MM_ERROR_NONE;
8421 }
8422
8423 static void
8424 __mmplayer_check_async_state_transition(mm_player_t* player)
8425 {
8426         GstState element_state = GST_STATE_VOID_PENDING;
8427         GstState element_pending_state = GST_STATE_VOID_PENDING;
8428         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8429         GstElement * element = NULL;
8430         gboolean async = FALSE;
8431
8432         /* check player handle */
8433         MMPLAYER_RETURN_IF_FAIL(player &&
8434                                                 player->pipeline &&
8435                                                 player->pipeline->mainbin &&
8436                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8437
8438         if (player->attrs)
8439                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8440
8441         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8442                 LOGD("don't need to check the pipeline state");
8443                 return;
8444         }
8445
8446         MMPLAYER_PRINT_STATE(player);
8447
8448         /* wait for state transition */
8449         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8450         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8451
8452         if (ret == GST_STATE_CHANGE_FAILURE) {
8453                 LOGE(" [%s] state : %s   pending : %s \n",
8454                         GST_ELEMENT_NAME(element),
8455                         gst_element_state_get_name(element_state),
8456                         gst_element_state_get_name(element_pending_state));
8457
8458                 /* dump state of all element */
8459                 __mmplayer_dump_pipeline_state(player);
8460
8461                 return;
8462         }
8463
8464         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8465         return;
8466 }
8467
8468 int
8469 _mmplayer_destroy(MMHandleType handle)
8470 {
8471         mm_player_t* player = MM_PLAYER_CAST(handle);
8472
8473         MMPLAYER_FENTER();
8474
8475         /* check player handle */
8476         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8477
8478         /* destroy can called at anytime */
8479         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8480
8481         /* check async state transition */
8482         __mmplayer_check_async_state_transition(player);
8483
8484         __mmplayer_destroy_streaming_ext(player);
8485
8486         /* release next play thread */
8487         if (player->next_play_thread) {
8488                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8489                 player->next_play_thread_exit = TRUE;
8490                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8491                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8492
8493                 LOGD("waitting for next play thread exit\n");
8494                 g_thread_join(player->next_play_thread);
8495                 g_mutex_clear(&player->next_play_thread_mutex);
8496                 g_cond_clear(&player->next_play_thread_cond);
8497                 LOGD("next play thread released\n");
8498         }
8499
8500         _mmplayer_release_video_capture(player);
8501
8502         /* de-initialize resource manager */
8503         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8504                         player->resource_manager))
8505                 LOGE("failed to deinitialize resource manager\n");
8506
8507         /* release pipeline */
8508         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8509                 LOGE("failed to destory pipeline\n");
8510                 return MM_ERROR_PLAYER_INTERNAL;
8511         }
8512
8513         /* release subtitle info lock and cond */
8514         g_mutex_clear(&player->subtitle_info_mutex);
8515         g_cond_clear(&player->subtitle_info_cond);
8516
8517         __mmplayer_release_dump_list(player->dump_list);
8518
8519         /* release miscellaneous information */
8520         __mmplayer_release_misc(player);
8521
8522         /* release miscellaneous information.
8523            these info needs to be released after pipeline is destroyed. */
8524         __mmplayer_release_misc_post(player);
8525
8526         /* release attributes */
8527         _mmplayer_deconstruct_attribute(handle);
8528
8529         /* release lock */
8530         g_mutex_clear(&player->fsink_lock);
8531
8532         /* release lock */
8533         g_mutex_clear(&player->update_tag_lock);
8534
8535         /* release video bo lock and cond */
8536         g_mutex_clear(&player->video_bo_mutex);
8537         g_cond_clear(&player->video_bo_cond);
8538
8539         /* release media stream callback lock */
8540         g_mutex_clear(&player->media_stream_cb_lock);
8541
8542         MMPLAYER_FLEAVE();
8543
8544         return MM_ERROR_NONE;
8545 }
8546
8547 int
8548 __mmplayer_realize_streaming_ext(mm_player_t* player)
8549 {
8550         int ret = MM_ERROR_NONE;
8551
8552         MMPLAYER_FENTER();
8553         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554
8555         if (MMPLAYER_IS_HTTP_PD(player)) {
8556                 gboolean bret = FALSE;
8557
8558                 player->pd_downloader = _mmplayer_create_pd_downloader();
8559                 if (!player->pd_downloader) {
8560                         LOGE("Unable to create PD Downloader...");
8561                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8562                 }
8563
8564                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8565
8566                 if (FALSE == bret) {
8567                         LOGE("Unable to create PD Downloader...");
8568                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8569                 }
8570         }
8571
8572         MMPLAYER_FLEAVE();
8573         return ret;
8574 }
8575
8576 int
8577 _mmplayer_realize(MMHandleType hplayer)
8578 {
8579         mm_player_t* player = (mm_player_t*)hplayer;
8580         char *uri = NULL;
8581         void *param = NULL;
8582         MMHandleType attrs = 0;
8583         int ret = MM_ERROR_NONE;
8584
8585         MMPLAYER_FENTER();
8586
8587         /* check player handle */
8588         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8589
8590         /* check current state */
8591         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8592
8593         attrs = MMPLAYER_GET_ATTRS(player);
8594         if (!attrs) {
8595                 LOGE("fail to get attributes.\n");
8596                 return MM_ERROR_PLAYER_INTERNAL;
8597         }
8598         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8599         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8600
8601         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8602                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8603
8604                 if (ret != MM_ERROR_NONE) {
8605                         LOGE("failed to parse profile\n");
8606                         return ret;
8607                 }
8608         }
8609
8610         if (uri && (strstr(uri, "es_buff://"))) {
8611                 if (strstr(uri, "es_buff://push_mode"))
8612                         player->es_player_push_mode = TRUE;
8613                 else
8614                         player->es_player_push_mode = FALSE;
8615         }
8616
8617         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8618                 LOGW("mms protocol is not supported format.\n");
8619                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8620         }
8621
8622         if (MMPLAYER_IS_STREAMING(player))
8623                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8624         else
8625                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8626
8627         player->smooth_streaming = FALSE;
8628         player->videodec_linked  = 0;
8629         player->videosink_linked = 0;
8630         player->audiodec_linked  = 0;
8631         player->audiosink_linked = 0;
8632         player->textsink_linked = 0;
8633         player->is_external_subtitle_present = FALSE;
8634         player->is_external_subtitle_added_now = FALSE;
8635         /* set the subtitle ON default */
8636         player->is_subtitle_off = FALSE;
8637
8638         /* realize pipeline */
8639         ret = __gst_realize(player);
8640         if (ret != MM_ERROR_NONE)
8641                 LOGE("fail to realize the player.\n");
8642         else
8643                 ret = __mmplayer_realize_streaming_ext(player);
8644
8645         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8646         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8647
8648         MMPLAYER_FLEAVE();
8649
8650         return ret;
8651 }
8652
8653 int
8654 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8655 {
8656         MMPLAYER_FENTER();
8657         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658
8659         /* destroy can called at anytime */
8660         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8661                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8662
8663         MMPLAYER_FLEAVE();
8664         return MM_ERROR_NONE;
8665 }
8666
8667 int
8668 _mmplayer_unrealize(MMHandleType hplayer)
8669 {
8670         mm_player_t* player = (mm_player_t*)hplayer;
8671         int ret = MM_ERROR_NONE;
8672
8673         MMPLAYER_FENTER();
8674
8675         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676
8677         MMPLAYER_CMD_UNLOCK(player);
8678         /* destroy the gst bus msg thread which is created during realize.
8679            this funct have to be called before getting cmd lock. */
8680         _mmplayer_bus_msg_thread_destroy(player);
8681         MMPLAYER_CMD_LOCK(player);
8682
8683         /* check current state */
8684         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8685
8686         /* check async state transition */
8687         __mmplayer_check_async_state_transition(player);
8688
8689         __mmplayer_unrealize_streaming_ext(player);
8690
8691         /* unrealize pipeline */
8692         ret = __gst_unrealize(player);
8693
8694         /* set asm stop if success */
8695         if (MM_ERROR_NONE == ret) {
8696                 if (!player->interrupted_by_resource) {
8697                         if (player->video_decoder_resource != NULL) {
8698                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8699                                                 player->video_decoder_resource);
8700                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8701                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8702                                 else
8703                                         player->video_decoder_resource = NULL;
8704                         }
8705
8706                         if (player->video_overlay_resource != NULL) {
8707                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8708                                                 player->video_overlay_resource);
8709                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8710                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8711                                 else
8712                                         player->video_overlay_resource = NULL;
8713                         }
8714
8715                         ret = mm_resource_manager_commit(player->resource_manager);
8716                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8717                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8718                 }
8719         } else
8720                 LOGE("failed and don't change asm state to stop");
8721
8722         MMPLAYER_FLEAVE();
8723
8724         return ret;
8725 }
8726
8727 int
8728 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8729 {
8730         mm_player_t* player = (mm_player_t*)hplayer;
8731
8732         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733
8734         return __gst_set_message_callback(player, callback, user_param);
8735 }
8736
8737 int
8738 _mmplayer_get_state(MMHandleType hplayer, int* state)
8739 {
8740         mm_player_t *player = (mm_player_t*)hplayer;
8741
8742         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8743
8744         *state = MMPLAYER_CURRENT_STATE(player);
8745
8746         return MM_ERROR_NONE;
8747 }
8748
8749
8750 int
8751 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8752 {
8753         mm_player_t* player = (mm_player_t*) hplayer;
8754         GstElement* vol_element = NULL;
8755         int i = 0;
8756
8757         MMPLAYER_FENTER();
8758
8759         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8760
8761         LOGD("volume [L]=%f:[R]=%f\n",
8762                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8763
8764         /* invalid factor range or not */
8765         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8766                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8767                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8768                         return MM_ERROR_INVALID_ARGUMENT;
8769                 }
8770         }
8771
8772         /* not support to set other value into each channel */
8773         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8774                 return MM_ERROR_INVALID_ARGUMENT;
8775
8776         /* Save volume to handle. Currently the first array element will be saved. */
8777         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8778
8779         /* check pipeline handle */
8780         if (!player->pipeline || !player->pipeline->audiobin) {
8781                 LOGD("audiobin is not created yet\n");
8782                 LOGD("but, current stored volume will be set when it's created.\n");
8783
8784                 /* NOTE : stored volume will be used in create_audiobin
8785                  * returning MM_ERROR_NONE here makes application to able to
8786                  * set volume at anytime.
8787                  */
8788                 return MM_ERROR_NONE;
8789         }
8790
8791         /* setting volume to volume element */
8792         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8793
8794         if (vol_element) {
8795                 LOGD("volume is set [%f]\n", player->sound.volume);
8796                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8797         }
8798
8799         MMPLAYER_FLEAVE();
8800
8801         return MM_ERROR_NONE;
8802 }
8803
8804
8805 int
8806 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8807 {
8808         mm_player_t* player = (mm_player_t*) hplayer;
8809         int i = 0;
8810
8811         MMPLAYER_FENTER();
8812
8813         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8814         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8815
8816         /* returning stored volume */
8817         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8818                 volume->level[i] = player->sound.volume;
8819
8820         MMPLAYER_FLEAVE();
8821
8822         return MM_ERROR_NONE;
8823 }
8824
8825 int
8826 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8827 {
8828         mm_player_t* player = (mm_player_t*) hplayer;
8829         GstElement* vol_element = NULL;
8830
8831         MMPLAYER_FENTER();
8832
8833         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834
8835         /* mute value shoud 0 or 1 */
8836         if (mute != 0 && mute != 1) {
8837                 LOGE("bad mute value\n");
8838
8839                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8840                 return MM_ERROR_INVALID_ARGUMENT;
8841         }
8842
8843         player->sound.mute = mute;
8844
8845         /* just hold mute value if pipeline is not ready */
8846         if (!player->pipeline || !player->pipeline->audiobin) {
8847                 LOGD("pipeline is not ready. holding mute value\n");
8848                 return MM_ERROR_NONE;
8849         }
8850
8851         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8852
8853         /* NOTE : volume will only created when the bt is enabled */
8854         if (vol_element) {
8855                 LOGD("mute : %d\n", mute);
8856                 g_object_set(vol_element, "mute", mute, NULL);
8857         } else
8858                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8859
8860         MMPLAYER_FLEAVE();
8861
8862         return MM_ERROR_NONE;
8863 }
8864
8865 int
8866 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8867 {
8868         mm_player_t* player = (mm_player_t*) hplayer;
8869
8870         MMPLAYER_FENTER();
8871
8872         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8873         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8874
8875         /* just hold mute value if pipeline is not ready */
8876         if (!player->pipeline || !player->pipeline->audiobin) {
8877                 LOGD("pipeline is not ready. returning stored value\n");
8878                 *pmute = player->sound.mute;
8879                 return MM_ERROR_NONE;
8880         }
8881
8882         *pmute = player->sound.mute;
8883
8884         MMPLAYER_FLEAVE();
8885
8886         return MM_ERROR_NONE;
8887 }
8888
8889 int
8890 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8891 {
8892         mm_player_t* player = (mm_player_t*) hplayer;
8893
8894         MMPLAYER_FENTER();
8895
8896         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8897
8898         player->video_stream_changed_cb = callback;
8899         player->video_stream_changed_cb_user_param = user_param;
8900         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8901
8902         MMPLAYER_FLEAVE();
8903
8904         return MM_ERROR_NONE;
8905 }
8906
8907 int
8908 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8909 {
8910         mm_player_t* player = (mm_player_t*) hplayer;
8911
8912         MMPLAYER_FENTER();
8913
8914         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8915
8916         player->audio_stream_changed_cb = callback;
8917         player->audio_stream_changed_cb_user_param = user_param;
8918         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8919
8920         MMPLAYER_FLEAVE();
8921
8922         return MM_ERROR_NONE;
8923 }
8924
8925 int
8926 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8927 {
8928         mm_player_t* player = (mm_player_t*) hplayer;
8929
8930         MMPLAYER_FENTER();
8931
8932         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8933
8934         player->audio_stream_render_cb_ex = callback;
8935         player->audio_stream_cb_user_param = user_param;
8936         player->audio_stream_sink_sync = sync;
8937         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);
8938
8939         MMPLAYER_FLEAVE();
8940
8941         return MM_ERROR_NONE;
8942 }
8943
8944 int
8945 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8946 {
8947         mm_player_t* player = (mm_player_t*) hplayer;
8948
8949         MMPLAYER_FENTER();
8950
8951         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8952
8953         if (callback && !player->bufmgr)
8954                 player->bufmgr = tbm_bufmgr_init(-1);
8955
8956         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8957         player->video_stream_cb = callback;
8958         player->video_stream_cb_user_param = user_param;
8959
8960         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8961
8962         MMPLAYER_FLEAVE();
8963
8964         return MM_ERROR_NONE;
8965 }
8966
8967 int
8968 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8969 {
8970         mm_player_t* player = (mm_player_t*) hplayer;
8971
8972         MMPLAYER_FENTER();
8973
8974         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8975
8976         player->audio_stream_cb = callback;
8977         player->audio_stream_cb_user_param = user_param;
8978         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8979
8980         MMPLAYER_FLEAVE();
8981
8982         return MM_ERROR_NONE;
8983 }
8984
8985 static int
8986 __mmplayer_start_streaming_ext(mm_player_t *player)
8987 {
8988         gint ret = MM_ERROR_NONE;
8989
8990         MMPLAYER_FENTER();
8991         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8992
8993         if (MMPLAYER_IS_HTTP_PD(player)) {
8994                 if (!player->pd_downloader) {
8995                         ret = __mmplayer_realize_streaming_ext(player);
8996
8997                         if (ret != MM_ERROR_NONE) {
8998                                 LOGE("failed to realize streaming ext\n");
8999                                 return ret;
9000                         }
9001                 }
9002
9003                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9004                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9005                         if (!ret) {
9006                                 LOGE("ERROR while starting PD...\n");
9007                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9008                         }
9009                         ret = MM_ERROR_NONE;
9010                 }
9011         }
9012
9013         MMPLAYER_FLEAVE();
9014         return ret;
9015 }
9016
9017 int
9018 _mmplayer_start(MMHandleType hplayer)
9019 {
9020         mm_player_t* player = (mm_player_t*) hplayer;
9021         gint ret = MM_ERROR_NONE;
9022
9023         MMPLAYER_FENTER();
9024
9025         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9026
9027         /* check current state */
9028         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9029
9030         /* NOTE : we should check and create pipeline again if not created as we destroy
9031          * whole pipeline when stopping in streamming playback
9032          */
9033         if (!player->pipeline) {
9034                 ret = __gst_realize(player);
9035                 if (MM_ERROR_NONE != ret) {
9036                         LOGE("failed to realize before starting. only in streamming\n");
9037                         /* unlock */
9038                         return ret;
9039                 }
9040         }
9041
9042         ret = __mmplayer_start_streaming_ext(player);
9043         if (ret != MM_ERROR_NONE) {
9044                 LOGE("failed to start streaming ext 0x%X", ret);
9045                 return ret;
9046         }
9047
9048         /* start pipeline */
9049         ret = __gst_start(player);
9050         if (ret != MM_ERROR_NONE)
9051                 LOGE("failed to start player.\n");
9052
9053         MMPLAYER_FLEAVE();
9054
9055         return ret;
9056 }
9057
9058 /* NOTE: post "not supported codec message" to application
9059  * when one codec is not found during AUTOPLUGGING in MSL.
9060  * So, it's separated with error of __mmplayer_gst_callback().
9061  * And, if any codec is not found, don't send message here.
9062  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9063  */
9064 int
9065 __mmplayer_handle_missed_plugin(mm_player_t* player)
9066 {
9067         MMMessageParamType msg_param;
9068         memset(&msg_param, 0, sizeof(MMMessageParamType));
9069         gboolean post_msg_direct = FALSE;
9070
9071         MMPLAYER_FENTER();
9072
9073         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9074
9075         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9076                         player->not_supported_codec, player->can_support_codec);
9077
9078         if (player->not_found_demuxer) {
9079                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9080                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9081
9082                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9083                 MMPLAYER_FREEIF(msg_param.data);
9084
9085                 return MM_ERROR_NONE;
9086         }
9087
9088         if (player->not_supported_codec) {
9089                 if (player->can_support_codec) {
9090                         // There is one codec to play
9091                         post_msg_direct = TRUE;
9092                 } else {
9093                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9094                                 post_msg_direct = TRUE;
9095                 }
9096
9097                 if (post_msg_direct) {
9098                         MMMessageParamType msg_param;
9099                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9100
9101                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9102                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9103
9104                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9105                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9106                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9107                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9108
9109                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9110                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9111                         }
9112
9113                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9114
9115                         MMPLAYER_FREEIF(msg_param.data);
9116
9117                         return MM_ERROR_NONE;
9118                 } else {
9119                         // no any supported codec case
9120                         LOGW("not found any codec, posting error code to application.\n");
9121
9122                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9123                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9124                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9125                         } else {
9126                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9127                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9128                         }
9129
9130                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9131
9132                         MMPLAYER_FREEIF(msg_param.data);
9133                 }
9134         }
9135
9136         MMPLAYER_FLEAVE();
9137
9138         return MM_ERROR_NONE;
9139 }
9140
9141 static void __mmplayer_check_pipeline(mm_player_t* player)
9142 {
9143         GstState element_state = GST_STATE_VOID_PENDING;
9144         GstState element_pending_state = GST_STATE_VOID_PENDING;
9145         gint timeout = 0;
9146         int ret = MM_ERROR_NONE;
9147
9148         if (player->gapless.reconfigure) {
9149                 LOGW("pipeline is under construction.\n");
9150
9151                 MMPLAYER_PLAYBACK_LOCK(player);
9152                 MMPLAYER_PLAYBACK_UNLOCK(player);
9153
9154                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9155
9156                 /* wait for state transition */
9157                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9158
9159                 if (ret == GST_STATE_CHANGE_FAILURE)
9160                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9161         }
9162 }
9163
9164 /* NOTE : it should be able to call 'stop' anytime*/
9165 int
9166 _mmplayer_stop(MMHandleType hplayer)
9167 {
9168         mm_player_t* player = (mm_player_t*)hplayer;
9169         int ret = MM_ERROR_NONE;
9170
9171         MMPLAYER_FENTER();
9172
9173         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9174
9175         /* check current state */
9176         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9177
9178         /* check pipline building state */
9179         __mmplayer_check_pipeline(player);
9180         __mmplayer_reset_gapless_state(player);
9181
9182         /* NOTE : application should not wait for EOS after calling STOP */
9183         __mmplayer_cancel_eos_timer(player);
9184
9185         __mmplayer_unrealize_streaming_ext(player);
9186
9187         /* reset */
9188         player->doing_seek = FALSE;
9189
9190         /* stop pipeline */
9191         ret = __gst_stop(player);
9192
9193         if (ret != MM_ERROR_NONE)
9194                 LOGE("failed to stop player.\n");
9195
9196         MMPLAYER_FLEAVE();
9197
9198         return ret;
9199 }
9200
9201 int
9202 _mmplayer_pause(MMHandleType hplayer)
9203 {
9204         mm_player_t* player = (mm_player_t*)hplayer;
9205         gint64 pos_msec = 0;
9206         gboolean async = FALSE;
9207         gint ret = MM_ERROR_NONE;
9208
9209         MMPLAYER_FENTER();
9210
9211         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9212
9213         /* check current state */
9214         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9215
9216         /* check pipline building state */
9217         __mmplayer_check_pipeline(player);
9218
9219         switch (MMPLAYER_CURRENT_STATE(player)) {
9220         case MM_PLAYER_STATE_READY:
9221                 {
9222                         /* check prepare async or not.
9223                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9224                          */
9225                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9226                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9227
9228                         /* Changing back sync of rtspsrc to async */
9229                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9230                                 LOGD("async prepare working mode for rtsp");
9231                                 async = TRUE;
9232                         }
9233                 }
9234                 break;
9235
9236         case MM_PLAYER_STATE_PLAYING:
9237                 {
9238                         /* NOTE : store current point to overcome some bad operation
9239                         *(returning zero when getting current position in paused state) of some
9240                         * elements
9241                         */
9242                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9243                                 LOGW("getting current position failed in paused\n");
9244
9245                         player->last_position = pos_msec;
9246
9247                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9248                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9249                            This causes problem is position calculation during normal pause resume scenarios also.
9250                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9251                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9252                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9253                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9254                         }
9255                 }
9256                 break;
9257         }
9258
9259         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9260                 LOGD("doing async pause in case of ms buff src");
9261                 async = TRUE;
9262         }
9263
9264         /* pause pipeline */
9265         ret = __gst_pause(player, async);
9266
9267         if (ret != MM_ERROR_NONE)
9268                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9269
9270         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9271                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9272                         LOGE("failed to update display_rotation");
9273         }
9274
9275         MMPLAYER_FLEAVE();
9276
9277         return ret;
9278 }
9279
9280 int
9281 _mmplayer_resume(MMHandleType hplayer)
9282 {
9283         mm_player_t* player = (mm_player_t*)hplayer;
9284         int ret = MM_ERROR_NONE;
9285         gboolean async = FALSE;
9286
9287         MMPLAYER_FENTER();
9288
9289         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9290
9291         /* Changing back sync mode rtspsrc to async */
9292         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9293                 LOGD("async resume for rtsp case");
9294                 async = TRUE;
9295         }
9296
9297         /* check current state */
9298         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9299
9300         ret = __gst_resume(player, async);
9301
9302         if (ret != MM_ERROR_NONE)
9303                 LOGE("failed to resume player.\n");
9304
9305         MMPLAYER_FLEAVE();
9306
9307         return ret;
9308 }
9309
9310 static int
9311 __mmplayer_set_pcm_extraction(mm_player_t* player)
9312 {
9313         gint64 start_nsec = 0;
9314         gint64 end_nsec = 0;
9315         gint64 dur_nsec = 0;
9316         gint64 dur_msec = 0;
9317         int required_start = 0;
9318         int required_end = 0;
9319         int ret = 0;
9320
9321         MMPLAYER_FENTER();
9322
9323         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9324
9325         mm_attrs_multiple_get(player->attrs,
9326                 NULL,
9327                 "pcm_extraction_start_msec", &required_start,
9328                 "pcm_extraction_end_msec", &required_end,
9329                 NULL);
9330
9331         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9332
9333         if (required_start == 0 && required_end == 0) {
9334                 LOGD("extracting entire stream");
9335                 return MM_ERROR_NONE;
9336         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9337                 LOGD("invalid range for pcm extraction");
9338                 return MM_ERROR_INVALID_ARGUMENT;
9339         }
9340
9341         /* get duration */
9342         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9343         if (!ret) {
9344                 LOGE("failed to get duration");
9345                 return MM_ERROR_PLAYER_INTERNAL;
9346         }
9347         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9348
9349         if (dur_msec < required_end) {
9350                 // FIXME
9351                 LOGD("invalid end pos for pcm extraction");
9352                 return MM_ERROR_INVALID_ARGUMENT;
9353         }
9354
9355         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9356         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9357
9358         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9359                                         1.0,
9360                                         GST_FORMAT_TIME,
9361                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9362                                         GST_SEEK_TYPE_SET, start_nsec,
9363                                         GST_SEEK_TYPE_SET, end_nsec))) {
9364                 LOGE("failed to seek for pcm extraction\n");
9365
9366                 return MM_ERROR_PLAYER_SEEK;
9367         }
9368
9369         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9370
9371         MMPLAYER_FLEAVE();
9372
9373         return MM_ERROR_NONE;
9374 }
9375
9376 int
9377 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9378 {
9379         mm_player_t* player = (mm_player_t*)hplayer;
9380         gint64 pos_msec = 0;
9381         int ret = MM_ERROR_NONE;
9382         int mute = FALSE;
9383         signed long long start = 0, stop = 0;
9384         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9385         MMPLAYER_FENTER();
9386
9387         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9388         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9389
9390         /* The sound of video is not supported under 0.0 and over 2.0. */
9391         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9392                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9393                         mute = TRUE;
9394         }
9395         _mmplayer_set_mute(hplayer, mute);
9396
9397         if (player->playback_rate == rate)
9398                 return MM_ERROR_NONE;
9399
9400         /* If the position is reached at start potion during fast backward, EOS is posted.
9401          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9402          * */
9403         player->playback_rate = rate;
9404
9405         current_state = MMPLAYER_CURRENT_STATE(player);
9406
9407         if (current_state != MM_PLAYER_STATE_PAUSED)
9408                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9409
9410         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9411
9412         if ((current_state == MM_PLAYER_STATE_PAUSED)
9413                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9414                 LOGW("returning last point : %lld\n", player->last_position);
9415                 pos_msec = player->last_position;
9416         }
9417
9418         if (rate >= 0) {
9419                 start = pos_msec;
9420                 stop = GST_CLOCK_TIME_NONE;
9421         } else {
9422                 start = GST_CLOCK_TIME_NONE;
9423                 stop = pos_msec;
9424         }
9425
9426         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9427                                 player->playback_rate,
9428                                 GST_FORMAT_TIME,
9429                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9430                                 GST_SEEK_TYPE_SET, start,
9431                                 GST_SEEK_TYPE_SET, stop)) {
9432                 LOGE("failed to set speed playback\n");
9433                 return MM_ERROR_PLAYER_SEEK;
9434         }
9435
9436         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9437
9438         MMPLAYER_FLEAVE();
9439
9440         return MM_ERROR_NONE;;
9441 }
9442
9443 int
9444 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9445 {
9446         mm_player_t* player = (mm_player_t*)hplayer;
9447         int ret = MM_ERROR_NONE;
9448
9449         MMPLAYER_FENTER();
9450
9451         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9452
9453         /* check pipline building state */
9454         __mmplayer_check_pipeline(player);
9455
9456         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9457
9458         MMPLAYER_FLEAVE();
9459
9460         return ret;
9461 }
9462
9463 int
9464 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9465 {
9466         mm_player_t* player = (mm_player_t*)hplayer;
9467         int ret = MM_ERROR_NONE;
9468
9469         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9470
9471         ret = __gst_get_position(player, format, position);
9472
9473         return ret;
9474 }
9475
9476 int
9477 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9478 {
9479         mm_player_t* player = (mm_player_t*)hplayer;
9480         int ret = MM_ERROR_NONE;
9481
9482         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9483
9484         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9485
9486         return ret;
9487 }
9488
9489 int
9490 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9491 {
9492         mm_player_t* player = (mm_player_t*)hplayer;
9493         int ret = MM_ERROR_NONE;
9494
9495         MMPLAYER_FENTER();
9496
9497         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9498
9499         ret = __gst_adjust_subtitle_position(player, format, position);
9500
9501         MMPLAYER_FLEAVE();
9502
9503         return ret;
9504 }
9505 int
9506 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9507 {
9508         mm_player_t* player = (mm_player_t*)hplayer;
9509         int ret = MM_ERROR_NONE;
9510
9511         MMPLAYER_FENTER();
9512
9513         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9514
9515         ret = __gst_adjust_video_position(player, offset);
9516
9517         MMPLAYER_FLEAVE();
9518
9519         return ret;
9520 }
9521
9522 static gboolean
9523 __mmplayer_is_midi_type(gchar* str_caps)
9524 {
9525         if ((g_strrstr(str_caps, "audio/midi")) ||
9526                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9527                 (g_strrstr(str_caps, "application/x-smaf")) ||
9528                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9529                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9530                 (g_strrstr(str_caps, "audio/xmf")) ||
9531                 (g_strrstr(str_caps, "audio/mxmf"))) {
9532                 LOGD("midi\n");
9533                 return TRUE;
9534         }
9535
9536         return FALSE;
9537 }
9538
9539 static gboolean
9540 __mmplayer_is_only_mp3_type(gchar *str_caps)
9541 {
9542         if (g_strrstr(str_caps, "application/x-id3") ||
9543                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9544                 return TRUE;
9545         return FALSE;
9546 }
9547
9548 static void
9549 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9550 {
9551         GstStructure* caps_structure = NULL;
9552         gint samplerate = 0;
9553         gint channels = 0;
9554
9555         MMPLAYER_FENTER();
9556         MMPLAYER_RETURN_IF_FAIL(player && caps);
9557
9558         caps_structure = gst_caps_get_structure(caps, 0);
9559
9560         /* set stream information */
9561         gst_structure_get_int(caps_structure, "rate", &samplerate);
9562         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9563
9564         gst_structure_get_int(caps_structure, "channels", &channels);
9565         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9566
9567         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9568 }
9569
9570 static void
9571 __mmplayer_update_content_type_info(mm_player_t* player)
9572 {
9573         MMPLAYER_FENTER();
9574         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9575
9576         if (__mmplayer_is_midi_type(player->type)) {
9577                 player->bypass_audio_effect = TRUE;
9578         } else if (g_strrstr(player->type, "application/x-hls")) {
9579                 /* If it can't know exact type when it parses uri because of redirection case,
9580                  * it will be fixed by typefinder or when doing autoplugging.
9581                  */
9582                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9583                 if (player->streamer) {
9584                         player->streamer->is_adaptive_streaming = TRUE;
9585                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9586                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9587                 }
9588         } else if (g_strrstr(player->type, "application/dash+xml")) {
9589                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9590         }
9591
9592         MMPLAYER_FLEAVE();
9593 }
9594
9595 static void
9596 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9597 GstCaps *caps, gpointer data)
9598 {
9599         mm_player_t* player = (mm_player_t*)data;
9600         GstPad* pad = NULL;
9601
9602         MMPLAYER_FENTER();
9603
9604         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9605
9606         /* store type string */
9607         MMPLAYER_FREEIF(player->type);
9608         player->type = gst_caps_to_string(caps);
9609         if (player->type) {
9610                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9611                                 player, player->type, probability, gst_caps_get_size(caps));
9612         }
9613
9614         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9615                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9616                 LOGE("not support media format\n");
9617
9618                 if (player->msg_posted == FALSE) {
9619                         MMMessageParamType msg_param;
9620                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9621
9622                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9623                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9624
9625                         /* don't post more if one was sent already */
9626                         player->msg_posted = TRUE;
9627                 }
9628                 return;
9629         }
9630
9631         __mmplayer_update_content_type_info(player);
9632
9633         pad = gst_element_get_static_pad(tf, "src");
9634         if (!pad) {
9635                 LOGE("fail to get typefind src pad.\n");
9636                 return;
9637         }
9638
9639         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9640                 gboolean async = FALSE;
9641                 LOGE("failed to autoplug %s\n", player->type);
9642
9643                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9644
9645                 if (async && player->msg_posted == FALSE)
9646                         __mmplayer_handle_missed_plugin(player);
9647
9648                 goto DONE;
9649         }
9650
9651 DONE:
9652         gst_object_unref(GST_OBJECT(pad));
9653
9654         MMPLAYER_FLEAVE();
9655
9656         return;
9657 }
9658
9659 static GstElement *
9660 __mmplayer_create_decodebin(mm_player_t* player)
9661 {
9662         GstElement *decodebin = NULL;
9663
9664         MMPLAYER_FENTER();
9665
9666         /* create decodebin */
9667         decodebin = gst_element_factory_make("decodebin", NULL);
9668
9669         if (!decodebin) {
9670                 LOGE("fail to create decodebin\n");
9671                 goto ERROR;
9672         }
9673
9674         /* raw pad handling signal */
9675         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9676                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9677
9678         /* no-more-pad pad handling signal */
9679         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9680                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9681
9682         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9683                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9684
9685         /* This signal is emitted when a pad for which there is no further possible
9686            decoding is added to the decodebin.*/
9687         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9688                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9689
9690         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9691            before looking for any elements that can handle that stream.*/
9692         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9693                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9694
9695         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9696            before looking for any elements that can handle that stream.*/
9697         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9698                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9699
9700         /* This signal is emitted once decodebin has finished decoding all the data.*/
9701         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9702                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9703
9704         /* This signal is emitted when a element is added to the bin.*/
9705         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9706                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9707
9708 ERROR:
9709         return decodebin;
9710 }
9711
9712 static gboolean
9713 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9714 {
9715         MMPlayerGstElement* mainbin = NULL;
9716         GstElement* decodebin = NULL;
9717         GstElement* queue2 = NULL;
9718         GstPad* sinkpad = NULL;
9719         GstPad* qsrcpad = NULL;
9720         gint64 dur_bytes = 0L;
9721
9722         guint max_buffer_size_bytes = 0;
9723         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9724
9725         MMPLAYER_FENTER();
9726         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9727
9728         mainbin = player->pipeline->mainbin;
9729
9730         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9731                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9732                 LOGD("creating http streaming buffering queue(queue2)\n");
9733
9734                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9735                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9736                 } else {
9737                         queue2 = gst_element_factory_make("queue2", "queue2");
9738                         if (!queue2) {
9739                                 LOGE("failed to create buffering queue element\n");
9740                                 goto ERROR;
9741                         }
9742
9743                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9744                                 LOGE("failed to add buffering queue\n");
9745                                 goto ERROR;
9746                         }
9747
9748                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9749                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9750
9751                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9752                                 LOGE("failed to link buffering queue\n");
9753                                 goto ERROR;
9754                         }
9755
9756                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9757                                 LOGE("fail to get duration.\n");
9758
9759                         LOGD("dur_bytes = %lld\n", dur_bytes);
9760
9761                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9762
9763                         if (dur_bytes > 0) {
9764                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9765                                         type = MUXED_BUFFER_TYPE_FILE;
9766                                 } else {
9767                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9768                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9769                                 }
9770                         } else {
9771                                 dur_bytes = 0;
9772                         }
9773
9774                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9775                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9776                         if (!g_strrstr(player->type, "video/mpegts")) {
9777                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9778                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9779
9780                                 // FIXME : pass ini setting directly. is this ok?
9781                                 __mm_player_streaming_set_queue2(player->streamer,
9782                                                                                                 queue2,
9783                                                                                                 FALSE,
9784                                                                                                 max_buffer_size_bytes,
9785                                                                                                 player->ini.http_buffering_time,
9786                                                                                                 1.0,                                                            // no meaning
9787                                                                                                 player->ini.http_buffering_limit,       // no meaning
9788                                                                                                 type,
9789                                                                                                 player->http_file_buffering_path,
9790                                                                                                 (guint64)dur_bytes);
9791                         }
9792
9793                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9794                                 LOGE("failed to sync queue2 state with parent\n");
9795                                 goto ERROR;
9796                         }
9797
9798                         srcpad = qsrcpad;
9799
9800                         gst_object_unref(GST_OBJECT(sinkpad));
9801
9802                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9803                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9804                 }
9805         }
9806
9807         /* create decodebin */
9808         decodebin = __mmplayer_create_decodebin(player);
9809
9810         if (!decodebin) {
9811                 LOGE("can not create autoplug element\n");
9812                 goto ERROR;
9813         }
9814
9815         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9816                 LOGE("failed to add decodebin\n");
9817                 goto ERROR;
9818         }
9819
9820         /* to force caps on the decodebin element and avoid reparsing stuff by
9821         * typefind. It also avoids a deadlock in the way typefind activates pads in
9822         * the state change */
9823         g_object_set(decodebin, "sink-caps", caps, NULL);
9824
9825         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9826
9827         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9828                 LOGE("failed to link decodebin\n");
9829                 goto ERROR;
9830         }
9831
9832         gst_object_unref(GST_OBJECT(sinkpad));
9833
9834         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9835         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9836
9837         /* set decodebin property about buffer in streaming playback. *
9838          * in case of HLS/DASH, it does not need to have big buffer        *
9839          * because it is kind of adaptive streaming.                  */
9840         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9841                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9842                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9843                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9844
9845                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9846                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9847                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9848                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9849                 }
9850
9851                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9852                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9853                                                                                         "low-percent", 1,   // 1%
9854                                                                                         "max-size-bytes", max_size_bytes,
9855                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9856                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9857         }
9858
9859         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9860                 LOGE("failed to sync decodebin state with parent\n");
9861                 goto ERROR;
9862         }
9863
9864         MMPLAYER_FLEAVE();
9865
9866         return TRUE;
9867
9868 ERROR:
9869
9870         if (sinkpad)
9871                 gst_object_unref(GST_OBJECT(sinkpad));
9872
9873         if (queue2) {
9874                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9875                  * You need to explicitly set elements to the NULL state before
9876                  * dropping the final reference, to allow them to clean up.
9877                  */
9878                 gst_element_set_state(queue2, GST_STATE_NULL);
9879
9880                 /* And, it still has a parent "player".
9881                  * You need to let the parent manage the object instead of unreffing the object directly.
9882                  */
9883                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9884                 gst_object_unref(queue2);
9885                 queue2 = NULL;
9886         }
9887
9888         if (decodebin) {
9889                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9890                  * You need to explicitly set elements to the NULL state before
9891                  * dropping the final reference, to allow them to clean up.
9892                  */
9893                 gst_element_set_state(decodebin, GST_STATE_NULL);
9894
9895                 /* And, it still has a parent "player".
9896                  * You need to let the parent manage the object instead of unreffing the object directly.
9897                  */
9898
9899                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9900                 gst_object_unref(decodebin);
9901                 decodebin = NULL;
9902         }
9903
9904         return FALSE;
9905 }
9906
9907 static int
9908 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9909 {
9910         MMPLAYER_FENTER();
9911
9912         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9913         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9914
9915         LOGD("class : %s, mime : %s \n", factory_class, mime);
9916
9917         /* add missing plugin */
9918         /* NOTE : msl should check missing plugin for image mime type.
9919          * Some motion jpeg clips can have playable audio track.
9920          * So, msl have to play audio after displaying popup written video format not supported.
9921          */
9922         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9923                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9924                         LOGD("not found demuxer\n");
9925                         player->not_found_demuxer = TRUE;
9926                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9927
9928                         goto DONE;
9929                 }
9930         }
9931
9932         if (!g_strrstr(factory_class, "Demuxer")) {
9933                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9934                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9935                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9936
9937                         /* check that clip have multi tracks or not */
9938                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9939                                 LOGD("video plugin is already linked\n");
9940                         } else {
9941                                 LOGW("add VIDEO to missing plugin\n");
9942                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9943                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9944                         }
9945                 } else if (g_str_has_prefix(mime, "audio")) {
9946                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9947                                 LOGD("audio plugin is already linked\n");
9948                         } else {
9949                                 LOGW("add AUDIO to missing plugin\n");
9950                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9951                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9952                         }
9953                 }
9954         }
9955
9956 DONE:
9957         MMPLAYER_FLEAVE();
9958
9959         return MM_ERROR_NONE;
9960 }
9961
9962
9963 static void
9964 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
9965 {
9966         mm_player_t* player = (mm_player_t*)data;
9967
9968         MMPLAYER_FENTER();
9969
9970         MMPLAYER_RETURN_IF_FAIL(player);
9971
9972         /* remove fakesink. */
9973         if (!__mmplayer_gst_remove_fakesink(player,
9974                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9975                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9976                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9977                  * source element are not same. To overcome this situation, this function will called
9978                  * several places and several times. Therefore, this is not an error case.
9979                  */
9980                 return;
9981         }
9982
9983         LOGD("[handle: %p] pipeline has completely constructed", player);
9984
9985         if ((player->ini.async_start) &&
9986                 (player->msg_posted == FALSE) &&
9987                 (player->cmd >= MMPLAYER_COMMAND_START))
9988                 __mmplayer_handle_missed_plugin(player);
9989
9990         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
9991 }
9992
9993 static gboolean
9994 __mmplayer_verify_next_play_path(mm_player_t *player)
9995 {
9996         MMHandleType attrs = 0;
9997         MMPlayerParseProfile profile;
9998         gint uri_idx = 0, check_cnt = 0;
9999         char *uri = NULL;
10000         gint mode = MM_PLAYER_PD_MODE_NONE;
10001         gint video = 0;
10002         gint count = 0;
10003         gint gapless = 0;
10004         guint num_of_list = 0;
10005         static int profile_tv = -1;
10006
10007         MMPLAYER_FENTER();
10008
10009         LOGD("checking for gapless play");
10010
10011         if (player->pipeline->textbin) {
10012                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10013                 goto ERROR;
10014         }
10015
10016         attrs = MMPLAYER_GET_ATTRS(player);
10017         if (!attrs) {
10018                 LOGE("fail to get attributes.\n");
10019                 goto ERROR;
10020         }
10021
10022         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10023
10024         if (__builtin_expect(profile_tv == -1, 0)) {
10025                 char *profileName;
10026                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10027                 switch (*profileName) {
10028                 case 't':
10029                 case 'T':
10030                         profile_tv = 1;
10031                         break;
10032                 default:
10033                         profile_tv = 0;
10034                 }
10035                 free(profileName);
10036         }
10037         /* gapless playback is not supported in case of video at TV profile. */
10038         if (profile_tv && video) {
10039                 LOGW("not support video gapless playback");
10040                 goto ERROR;
10041         }
10042
10043         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10044                 if (mode == TRUE) {
10045                         LOGW("pd mode\n");
10046                         goto ERROR;
10047                 }
10048         }
10049
10050         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10051                 LOGE("can not get play count\n");
10052
10053         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10054                 LOGE("can not get gapless mode\n");
10055
10056         if (video && !gapless) {
10057                 LOGW("not enabled video gapless playback");
10058                 goto ERROR;
10059         }
10060
10061         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10062                 gapless = 1;
10063
10064         if (!gapless) {
10065                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10066                 goto ERROR;
10067         }
10068
10069         num_of_list = g_list_length(player->uri_info.uri_list);
10070
10071         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10072
10073         if (num_of_list == 0) {
10074                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10075                         LOGE("can not get profile_uri\n");
10076                         goto ERROR;
10077                 }
10078
10079                 if (!uri) {
10080                         LOGE("uri list is empty.\n");
10081                         goto ERROR;
10082                 }
10083
10084                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10085                 LOGD("add original path : %s ", uri);
10086
10087                 num_of_list = 1;
10088                 uri = NULL;
10089         }
10090
10091         uri_idx = player->uri_info.uri_idx;
10092
10093         while (TRUE) {
10094                 check_cnt++;
10095
10096                 if (check_cnt > num_of_list) {
10097                         LOGE("there is no valid uri.");
10098                         goto ERROR;
10099                 }
10100
10101                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10102
10103                 if (uri_idx < num_of_list-1) {
10104                         uri_idx++;
10105                 } else {
10106                         if ((count <= 1) && (count != -1)) {
10107                                 LOGD("no repeat.");
10108                                 goto ERROR;
10109                         } else if (count > 1) {
10110                                 /* decrease play count */
10111                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10112                                 count--;
10113
10114                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10115
10116                                 /* commit attribute */
10117                                 if (mmf_attrs_commit(attrs))
10118                                         LOGE("failed to commit attribute\n");
10119                         }
10120
10121                         /* count < 0 : repeat continually */
10122                         uri_idx = 0;
10123                 }
10124
10125                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10126                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10127
10128                 if (uri == NULL) {
10129                         LOGW("next uri does not exist\n");
10130                         continue;
10131                 }
10132
10133                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10134                         LOGE("failed to parse profile\n");
10135                         continue;
10136                 }
10137
10138                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10139                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10140                         LOGW("uri type is not supported(%d).", profile.uri_type);
10141                         continue;
10142                 }
10143
10144                 break;
10145         }
10146
10147         player->uri_info.uri_idx = uri_idx;
10148         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10149
10150         if (mmf_attrs_commit(player->attrs)) {
10151                 LOGE("failed to commit.\n");
10152                 goto ERROR;
10153         }
10154
10155         LOGD("next uri %s(%d)\n", uri, uri_idx);
10156
10157         return TRUE;
10158
10159 ERROR:
10160
10161         LOGE("unable to play next path. EOS will be posted soon.\n");
10162         return FALSE;
10163 }
10164
10165 static void
10166 __mmplayer_initialize_next_play(mm_player_t *player)
10167 {
10168         int i;
10169
10170         MMPLAYER_FENTER();
10171
10172         player->smooth_streaming = FALSE;
10173         player->videodec_linked = 0;
10174         player->audiodec_linked = 0;
10175         player->videosink_linked = 0;
10176         player->audiosink_linked = 0;
10177         player->textsink_linked = 0;
10178         player->is_external_subtitle_present = FALSE;
10179         player->is_external_subtitle_added_now = FALSE;
10180         player->not_supported_codec = MISSING_PLUGIN_NONE;
10181         player->can_support_codec = FOUND_PLUGIN_NONE;
10182         player->pending_seek.is_pending = FALSE;
10183         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10184         player->pending_seek.pos = 0;
10185         player->msg_posted = FALSE;
10186         player->has_many_types = FALSE;
10187         player->no_more_pad = FALSE;
10188         player->not_found_demuxer = 0;
10189         player->doing_seek = FALSE;
10190         player->max_audio_channels = 0;
10191         player->is_subtitle_force_drop = FALSE;
10192         player->play_subtitle = FALSE;
10193         player->adjust_subtitle_pos = 0;
10194
10195         player->total_bitrate = 0;
10196         player->total_maximum_bitrate = 0;
10197
10198         _mmplayer_track_initialize(player);
10199         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10200
10201         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10202                 player->bitrate[i] = 0;
10203                 player->maximum_bitrate[i] = 0;
10204         }
10205
10206         if (player->v_stream_caps) {
10207                 gst_caps_unref(player->v_stream_caps);
10208                 player->v_stream_caps = NULL;
10209         }
10210
10211         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10212
10213         /* clean found parsers */
10214         if (player->parsers) {
10215                 GList *parsers = player->parsers;
10216                 for (; parsers; parsers = g_list_next(parsers)) {
10217                         gchar *name = parsers->data;
10218                         MMPLAYER_FREEIF(name);
10219                 }
10220                 g_list_free(player->parsers);
10221                 player->parsers = NULL;
10222         }
10223
10224         /* clean found audio decoders */
10225         if (player->audio_decoders) {
10226                 GList *a_dec = player->audio_decoders;
10227                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10228                         gchar *name = a_dec->data;
10229                         MMPLAYER_FREEIF(name);
10230                 }
10231                 g_list_free(player->audio_decoders);
10232                 player->audio_decoders = NULL;
10233         }
10234
10235         MMPLAYER_FLEAVE();
10236 }
10237
10238 static void
10239 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10240 {
10241         MMPlayerGstElement *mainbin = NULL;
10242         MMMessageParamType msg_param = {0,};
10243         GstElement *element = NULL;
10244         MMHandleType attrs = 0;
10245         char *uri = NULL;
10246         enum MainElementID elemId = MMPLAYER_M_NUM;
10247
10248         MMPLAYER_FENTER();
10249
10250         if ((player == NULL) ||
10251                 (player->pipeline == NULL) ||
10252                 (player->pipeline->mainbin == NULL)) {
10253                 LOGE("player is null.\n");
10254                 goto ERROR;
10255         }
10256
10257         mainbin = player->pipeline->mainbin;
10258         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10259
10260         attrs = MMPLAYER_GET_ATTRS(player);
10261         if (!attrs) {
10262                 LOGE("fail to get attributes.\n");
10263                 goto ERROR;
10264         }
10265
10266         /* Initialize Player values */
10267         __mmplayer_initialize_next_play(player);
10268
10269         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10270
10271         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10272                 LOGE("failed to parse profile\n");
10273                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10274                 goto ERROR;
10275         }
10276
10277         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10278                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10279                 LOGE("it's dash or hls. not support.");
10280                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10281                 goto ERROR;
10282         }
10283
10284         /* setup source */
10285         switch (player->profile.uri_type) {
10286         /* file source */
10287         case MM_PLAYER_URI_TYPE_FILE:
10288         {
10289                 LOGD("using filesrc for 'file://' handler.\n");
10290                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10291                         LOGE("failed to get storage info");
10292                         break;
10293                 }
10294
10295                 element = gst_element_factory_make("filesrc", "source");
10296
10297                 if (!element) {
10298                         LOGE("failed to create filesrc\n");
10299                         break;
10300                 }
10301
10302                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10303                 break;
10304         }
10305         case MM_PLAYER_URI_TYPE_URL_HTTP:
10306         {
10307                 gchar *user_agent, *cookies, **cookie_list;
10308                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10309                 user_agent = cookies = NULL;
10310                 cookie_list = NULL;
10311
10312                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10313                 if (!element) {
10314                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10315                         break;
10316                 }
10317                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10318
10319                 /* get attribute */
10320                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10321                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10322
10323                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10324                         LOGD("get timeout from ini\n");
10325                         http_timeout = player->ini.http_timeout;
10326                 }
10327
10328                 /* get attribute */
10329                 SECURE_LOGD("location : %s\n", player->profile.uri);
10330                 SECURE_LOGD("cookies : %s\n", cookies);
10331                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10332                 LOGD("timeout : %d\n", http_timeout);
10333
10334                 /* setting property to streaming source */
10335                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10336                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10337                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10338
10339                 /* parsing cookies */
10340                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10341                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10342                 if (user_agent)
10343                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10344                 break;
10345         }
10346         default:
10347                 LOGE("not support uri type %d\n", player->profile.uri_type);
10348                 break;
10349         }
10350
10351         if (!element) {
10352                 LOGE("no source element was created.\n");
10353                 goto ERROR;
10354         }
10355
10356         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10357                 LOGE("failed to add source element to pipeline\n");
10358                 gst_object_unref(GST_OBJECT(element));
10359                 element = NULL;
10360                 goto ERROR;
10361         }
10362
10363         /* take source element */
10364         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10365         mainbin[MMPLAYER_M_SRC].gst = element;
10366
10367         element = NULL;
10368
10369         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10370                 if (player->streamer == NULL) {
10371                         player->streamer = __mm_player_streaming_create();
10372                         __mm_player_streaming_initialize(player->streamer);
10373                 }
10374
10375                 elemId = MMPLAYER_M_TYPEFIND;
10376                 element = gst_element_factory_make("typefind", "typefinder");
10377                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10378                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10379         } else {
10380                 elemId = MMPLAYER_M_AUTOPLUG;
10381                 element = __mmplayer_create_decodebin(player);
10382         }
10383
10384         /* check autoplug element is OK */
10385         if (!element) {
10386                 LOGE("can not create element(%d)\n", elemId);
10387                 goto ERROR;
10388         }
10389
10390         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10391                 LOGE("failed to add sinkbin to pipeline\n");
10392                 gst_object_unref(GST_OBJECT(element));
10393                 element = NULL;
10394                 goto ERROR;
10395         }
10396
10397         mainbin[elemId].id = elemId;
10398         mainbin[elemId].gst = element;
10399
10400         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10401                 LOGE("Failed to link src - autoplug(or typefind)\n");
10402                 goto ERROR;
10403         }
10404
10405         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10406                 LOGE("Failed to change state of src element\n");
10407                 goto ERROR;
10408         }
10409
10410         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10411                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10412                         LOGE("Failed to change state of decodebin\n");
10413                         goto ERROR;
10414                 }
10415         } else {
10416                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10417                         LOGE("Failed to change state of src element\n");
10418                         goto ERROR;
10419                 }
10420         }
10421
10422         player->gapless.stream_changed = TRUE;
10423         player->gapless.running = TRUE;
10424         MMPLAYER_FLEAVE();
10425         return;
10426
10427 ERROR:
10428         if (player) {
10429                 MMPLAYER_PLAYBACK_UNLOCK(player);
10430
10431                 if (!player->msg_posted) {
10432                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10433                         player->msg_posted = TRUE;
10434                 }
10435         }
10436         return;
10437 }
10438
10439 static gboolean
10440 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10441 {
10442         mm_player_selector_t *selector = &player->selector[type];
10443         MMPlayerGstElement *sinkbin = NULL;
10444         enum MainElementID selectorId = MMPLAYER_M_NUM;
10445         enum MainElementID sinkId = MMPLAYER_M_NUM;
10446         GstPad *srcpad = NULL;
10447         GstPad *sinkpad = NULL;
10448         gboolean send_notice = FALSE;
10449
10450         MMPLAYER_FENTER();
10451         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10452
10453         LOGD("type %d", type);
10454
10455         switch (type) {
10456         case MM_PLAYER_TRACK_TYPE_AUDIO:
10457                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10458                 sinkId = MMPLAYER_A_BIN;
10459                 sinkbin = player->pipeline->audiobin;
10460                 break;
10461         case MM_PLAYER_TRACK_TYPE_VIDEO:
10462                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10463                 sinkId = MMPLAYER_V_BIN;
10464                 sinkbin = player->pipeline->videobin;
10465                 send_notice = TRUE;
10466                 break;
10467         case MM_PLAYER_TRACK_TYPE_TEXT:
10468                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10469                 sinkId = MMPLAYER_T_BIN;
10470                 sinkbin = player->pipeline->textbin;
10471                 break;
10472         default:
10473                 LOGE("requested type is not supportable");
10474                 return FALSE;
10475                 break;
10476         }
10477
10478         if (player->pipeline->mainbin[selectorId].gst) {
10479                 gint n;
10480
10481                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10482
10483                 if (selector->event_probe_id != 0)
10484                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10485                 selector->event_probe_id = 0;
10486
10487                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10488                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10489
10490                         if (srcpad && sinkpad) {
10491                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10492                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10493                                 gst_pad_unlink(srcpad, sinkpad);
10494
10495                                 /* send custom event to sink pad to handle it at video sink */
10496                                 if (send_notice) {
10497                                         LOGD("send custom event to sinkpad");
10498                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10499                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10500                                         gst_pad_send_event(sinkpad, event);
10501                                 }
10502                         }
10503
10504                         gst_object_unref(sinkpad);
10505                         sinkpad = NULL;
10506                 }
10507                 gst_object_unref(srcpad);
10508                 srcpad = NULL;
10509
10510                 LOGD("selector release");
10511
10512                 /* release and unref requests pad from the selector */
10513                 for (n = 0; n < selector->channels->len; n++) {
10514                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10515                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10516                 }
10517                 g_ptr_array_set_size(selector->channels, 0);
10518
10519                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10520                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10521
10522                 player->pipeline->mainbin[selectorId].gst = NULL;
10523                 selector = NULL;
10524         }
10525
10526         return TRUE;
10527 }
10528
10529 static void
10530 __mmplayer_deactivate_old_path(mm_player_t *player)
10531 {
10532         MMPLAYER_FENTER();
10533         MMPLAYER_RETURN_IF_FAIL(player);
10534
10535         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10536                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10537                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10538                 LOGE("deactivate selector error");
10539                 goto ERROR;
10540         }
10541
10542         _mmplayer_track_destroy(player);
10543         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10544
10545         if (player->streamer) {
10546                 __mm_player_streaming_deinitialize(player->streamer);
10547                 __mm_player_streaming_destroy(player->streamer);
10548                 player->streamer = NULL;
10549         }
10550
10551         MMPLAYER_PLAYBACK_LOCK(player);
10552         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10553
10554         MMPLAYER_FLEAVE();
10555         return;
10556
10557 ERROR:
10558
10559         if (!player->msg_posted) {
10560                 MMMessageParamType msg = {0,};
10561
10562                 /*post error*/
10563                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10564                 LOGE("next_uri_play> deactivate error");
10565
10566                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10567                 player->msg_posted = TRUE;
10568         }
10569         return;
10570 }
10571
10572 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10573 {
10574         int result = MM_ERROR_NONE;
10575         mm_player_t* player = (mm_player_t*) hplayer;
10576         MMPLAYER_FENTER();
10577
10578         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10579
10580         if (file_path) {
10581                 player->http_file_buffering_path = (gchar*)file_path;
10582                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10583         }
10584         MMPLAYER_FLEAVE();
10585         return result;
10586 }
10587
10588 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10589 {
10590         int result = MM_ERROR_NONE;
10591         mm_player_t* player = (mm_player_t*) hplayer;
10592         MMPLAYER_FENTER();
10593
10594         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10595
10596         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10597         if (mmf_attrs_commit(player->attrs)) {
10598                 LOGE("failed to commit the original uri.\n");
10599                 result = MM_ERROR_PLAYER_INTERNAL;
10600         } else {
10601                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10602                         LOGE("failed to add the original uri in the uri list.\n");
10603         }
10604
10605         MMPLAYER_FLEAVE();
10606         return result;
10607 }
10608
10609 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10610 {
10611         mm_player_t* player = (mm_player_t*) hplayer;
10612         guint num_of_list = 0;
10613
10614         MMPLAYER_FENTER();
10615
10616         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10617         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10618
10619         if (player->pipeline && player->pipeline->textbin) {
10620                 LOGE("subtitle path is enabled.\n");
10621                 return MM_ERROR_PLAYER_INVALID_STATE;
10622         }
10623
10624         num_of_list = g_list_length(player->uri_info.uri_list);
10625
10626         if (is_first_path == TRUE) {
10627                 if (num_of_list == 0) {
10628                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10629                         LOGD("add original path : %s", uri);
10630                 } else {
10631                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10632                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10633
10634                         LOGD("change original path : %s", uri);
10635                 }
10636         } else {
10637                 MMHandleType attrs = 0;
10638                 attrs = MMPLAYER_GET_ATTRS(player);
10639
10640                 if (num_of_list == 0) {
10641                         char *original_uri = NULL;
10642
10643                         if (attrs) {
10644                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10645
10646                                 if (!original_uri) {
10647                                         LOGE("there is no original uri.");
10648                                         return MM_ERROR_PLAYER_INVALID_STATE;
10649                                 }
10650
10651                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10652                                 player->uri_info.uri_idx = 0;
10653
10654                                 LOGD("add original path at first : %s(%d)", original_uri);
10655                         }
10656                 }
10657
10658                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10659                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10660         }
10661
10662         MMPLAYER_FLEAVE();
10663         return MM_ERROR_NONE;
10664 }
10665
10666 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10667 {
10668         mm_player_t* player = (mm_player_t*) hplayer;
10669         char *next_uri = NULL;
10670         guint num_of_list = 0;
10671
10672         MMPLAYER_FENTER();
10673         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10674
10675         num_of_list = g_list_length(player->uri_info.uri_list);
10676
10677         if (num_of_list > 0) {
10678                 gint uri_idx = player->uri_info.uri_idx;
10679
10680                 if (uri_idx < num_of_list-1)
10681                         uri_idx++;
10682                 else
10683                         uri_idx = 0;
10684
10685                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10686                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10687
10688                 *uri = g_strdup(next_uri);
10689         }
10690
10691         MMPLAYER_FLEAVE();
10692         return MM_ERROR_NONE;
10693 }
10694
10695 static void
10696 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10697 GstCaps *caps, gpointer data)
10698 {
10699         mm_player_t* player = (mm_player_t*)data;
10700         const gchar* klass = NULL;
10701         const gchar* mime = NULL;
10702         gchar* caps_str = NULL;
10703
10704         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10705         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10706         caps_str = gst_caps_to_string(caps);
10707
10708         LOGW("unknown type of caps : %s from %s",
10709                                         caps_str, GST_ELEMENT_NAME(elem));
10710
10711         MMPLAYER_FREEIF(caps_str);
10712
10713         /* There is no available codec. */
10714         __mmplayer_check_not_supported_codec(player, klass, mime);
10715 }
10716
10717 static gboolean
10718 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10719 GstCaps * caps,  gpointer data)
10720 {
10721         mm_player_t* player = (mm_player_t*)data;
10722         const char* mime = NULL;
10723         gboolean ret = TRUE;
10724
10725         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10726         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10727
10728         if (g_str_has_prefix(mime, "audio")) {
10729                 GstStructure* caps_structure = NULL;
10730                 gint samplerate = 0;
10731                 gint channels = 0;
10732                 gchar *caps_str = NULL;
10733
10734                 caps_structure = gst_caps_get_structure(caps, 0);
10735                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10736                 gst_structure_get_int(caps_structure, "channels", &channels);
10737
10738                 if ((channels > 0 && samplerate == 0)) {
10739                         LOGD("exclude audio...");
10740                         ret = FALSE;
10741                 }
10742
10743                 caps_str = gst_caps_to_string(caps);
10744                 /* set it directly because not sent by TAG */
10745                 if (g_strrstr(caps_str, "mobile-xmf"))
10746                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10747                 MMPLAYER_FREEIF(caps_str);
10748         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10749                 MMMessageParamType msg_param;
10750                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10751                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10752                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10753                 LOGD("video file is not supported on this device");
10754                 ret = FALSE;
10755         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10756                 LOGD("already video linked");
10757                 ret = FALSE;
10758         } else {
10759                 LOGD("found new stream");
10760         }
10761
10762         return ret;
10763 }
10764
10765 static int
10766 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10767 {
10768         int ret = MM_ERROR_NONE;
10769         int idx = 0;
10770         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10771
10772         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10773                 GstStructure* str = NULL;
10774                 gint channels = 0;
10775                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10776
10777                 LOGD("audio codec type: %d", codec_type);
10778                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10779                         /* sw codec will be skipped */
10780                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10781                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10782                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10783                                         ret = MM_ERROR_PLAYER_INTERNAL;
10784                                         goto DONE;
10785                                 }
10786                         }
10787                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10788                         /* hw codec will be skipped */
10789                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10790                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10791                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10792                                 ret = MM_ERROR_PLAYER_INTERNAL;
10793                                 goto DONE;
10794                         }
10795                 }
10796
10797                 str = gst_caps_get_structure(caps, 0);
10798                 if (str) {
10799                         gst_structure_get_int(str, "channels", &channels);
10800
10801                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10802                         if (player->max_audio_channels < channels)
10803                                 player->max_audio_channels = channels;
10804                 }
10805                 /* set stream information */
10806                 if (!player->audiodec_linked)
10807                         __mmplayer_set_audio_attrs(player, caps);
10808
10809                 /* update codec info */
10810                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10811                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10812                 player->audiodec_linked = 1;
10813
10814         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10815
10816                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10817
10818                 LOGD("video codec type: %d", codec_type);
10819                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10820                         /* sw codec is skipped */
10821                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10822                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10823                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10824                                         ret = MM_ERROR_PLAYER_INTERNAL;
10825                                         goto DONE;
10826                                 }
10827                         }
10828                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10829                         /* hw codec is skipped */
10830                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10831                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10832                                 ret = MM_ERROR_PLAYER_INTERNAL;
10833                                 goto DONE;
10834                         }
10835                 }
10836
10837                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10838                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10839
10840                         /* mark video decoder for acquire */
10841                         if (player->video_decoder_resource == NULL) {
10842                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10843                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10844                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10845                                                 &player->video_decoder_resource)
10846                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10847                                         LOGE("could not mark video_decoder resource for acquire");
10848                                         ret = MM_ERROR_PLAYER_INTERNAL;
10849                                         goto DONE;
10850                                 }
10851                         } else {
10852                                 LOGW("video decoder resource is already acquired, skip it.");
10853                                 ret = MM_ERROR_PLAYER_INTERNAL;
10854                                 goto DONE;
10855                         }
10856
10857                         player->interrupted_by_resource = FALSE;
10858                         /* acquire resources for video playing */
10859                         if (mm_resource_manager_commit(player->resource_manager)
10860                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10861                                 LOGE("could not acquire resources for video decoding\n");
10862                                 ret = MM_ERROR_PLAYER_INTERNAL;
10863                                 goto DONE;
10864                         }
10865                 }
10866
10867                 /* update codec info */
10868                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10869                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10870                 player->videodec_linked = 1;
10871         }
10872
10873 DONE:
10874         return ret;
10875 }
10876
10877 static gint
10878 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10879 GstCaps* caps, GstElementFactory* factory, gpointer data)
10880 {
10881         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10882          We are defining our own and will be removed when it actually exposed */
10883         typedef enum {
10884                 GST_AUTOPLUG_SELECT_TRY,
10885                 GST_AUTOPLUG_SELECT_EXPOSE,
10886                 GST_AUTOPLUG_SELECT_SKIP
10887         } GstAutoplugSelectResult;
10888
10889         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10890         mm_player_t* player = (mm_player_t*)data;
10891
10892         gchar* factory_name = NULL;
10893         gchar* caps_str = NULL;
10894         const gchar* klass = NULL;
10895         gint idx = 0;
10896
10897         factory_name = GST_OBJECT_NAME(factory);
10898         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10899         caps_str = gst_caps_to_string(caps);
10900
10901         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10902
10903         /* store type string */
10904         if (player->type == NULL) {
10905                 player->type = gst_caps_to_string(caps);
10906                 __mmplayer_update_content_type_info(player);
10907         }
10908
10909         /* filtering exclude keyword */
10910         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10911                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10912                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10913                                         factory_name, player->ini.exclude_element_keyword[idx]);
10914
10915                         result = GST_AUTOPLUG_SELECT_SKIP;
10916                         goto DONE;
10917                 }
10918         }
10919
10920         /* exclude webm format */
10921         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10922          * because webm format is not supportable.
10923          * If webm is disabled in "autoplug-continue", there is no state change
10924          * failure or error because the decodebin will expose the pad directly.
10925          * It make MSL invoke _prepare_async_callback.
10926          * So, we need to disable webm format in "autoplug-select" */
10927         if (caps_str && strstr(caps_str, "webm")) {
10928                 LOGW("webm is not supported");
10929                 result = GST_AUTOPLUG_SELECT_SKIP;
10930                 goto DONE;
10931         }
10932
10933         /* check factory class for filtering */
10934         /* NOTE : msl don't need to use image plugins.
10935          * So, those plugins should be skipped for error handling.
10936          */
10937         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10938                 LOGD("skipping [%s] by not required\n", factory_name);
10939                 result = GST_AUTOPLUG_SELECT_SKIP;
10940                 goto DONE;
10941         }
10942
10943         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10944                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10945                 // TO CHECK : subtitle if needed, add subparse exception.
10946                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10947                 result = GST_AUTOPLUG_SELECT_SKIP;
10948                 goto DONE;
10949         }
10950
10951         if (g_strrstr(factory_name, "mpegpsdemux")) {
10952                 LOGD("skipping PS container - not support\n");
10953                 result = GST_AUTOPLUG_SELECT_SKIP;
10954                 goto DONE;
10955         }
10956
10957         if (g_strrstr(factory_name, "mssdemux"))
10958                 player->smooth_streaming = TRUE;
10959
10960         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10961                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10962                 gint stype = 0;
10963                 gint width = 0;
10964                 GstStructure *str = NULL;
10965                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10966
10967                 /* don't make video because of not required */
10968                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10969                         (player->set_mode.media_packet_video_stream == FALSE)) {
10970                         LOGD("no video because it's not required. -> return expose");
10971                         result = GST_AUTOPLUG_SELECT_EXPOSE;
10972                         goto DONE;
10973                 }
10974
10975                 /* get w/h for omx state-tune */
10976                 /* FIXME: deprecated? */
10977                 str = gst_caps_get_structure(caps, 0);
10978                 gst_structure_get_int(str, "width", &width);
10979
10980                 if (width != 0) {
10981                         if (player->v_stream_caps) {
10982                                 gst_caps_unref(player->v_stream_caps);
10983                                 player->v_stream_caps = NULL;
10984                         }
10985
10986                         player->v_stream_caps = gst_caps_copy(caps);
10987                         LOGD("take caps for video state tune");
10988                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
10989                 }
10990         }
10991
10992         if (g_strrstr(klass, "Codec/Decoder")) {
10993                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
10994                         LOGD("skipping %s codec", factory_name);
10995                         result = GST_AUTOPLUG_SELECT_SKIP;
10996                         goto DONE;
10997                 }
10998         }
10999
11000 DONE:
11001         MMPLAYER_FREEIF(caps_str);
11002
11003         return result;
11004 }
11005
11006 static void
11007 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11008 gpointer data)
11009 {
11010         //mm_player_t* player = (mm_player_t*)data;
11011         GstCaps* caps = NULL;
11012
11013         LOGD("[Decodebin2] pad-removed signal\n");
11014
11015         caps = gst_pad_query_caps(new_pad, NULL);
11016         if (caps) {
11017                 gchar* caps_str = NULL;
11018                 caps_str = gst_caps_to_string(caps);
11019
11020                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11021
11022                 MMPLAYER_FREEIF(caps_str);
11023                 gst_caps_unref(caps);
11024         }
11025 }
11026
11027 static void
11028 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11029 {
11030         mm_player_t* player = (mm_player_t*)data;
11031         GstIterator *iter = NULL;
11032         GValue item = { 0, };
11033         GstPad *pad = NULL;
11034         gboolean done = FALSE;
11035         gboolean is_all_drained = TRUE;
11036
11037         MMPLAYER_FENTER();
11038         MMPLAYER_RETURN_IF_FAIL(player);
11039
11040         LOGD("__mmplayer_gst_decode_drained");
11041
11042         if (player->use_deinterleave == TRUE) {
11043                 LOGD("group playing mode.");
11044                 return;
11045         }
11046
11047         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11048                 LOGW("Fail to get cmd lock");
11049                 return;
11050         }
11051
11052         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11053                 !__mmplayer_verify_next_play_path(player)) {
11054                 LOGD("decoding is finished.");
11055                 __mmplayer_reset_gapless_state(player);
11056                 MMPLAYER_CMD_UNLOCK(player);
11057                 return;
11058         }
11059
11060         player->gapless.reconfigure = TRUE;
11061
11062         /* check decodebin src pads whether they received EOS or not */
11063         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11064
11065         while (!done) {
11066                 switch (gst_iterator_next(iter, &item)) {
11067                 case GST_ITERATOR_OK:
11068                         pad = g_value_get_object(&item);
11069                         if (pad && !GST_PAD_IS_EOS(pad)) {
11070                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11071                                 is_all_drained = FALSE;
11072                                 break;
11073                         }
11074                         g_value_reset(&item);
11075                         break;
11076                 case GST_ITERATOR_RESYNC:
11077                         gst_iterator_resync(iter);
11078                         break;
11079                 case GST_ITERATOR_ERROR:
11080                 case GST_ITERATOR_DONE:
11081                         done = TRUE;
11082                         break;
11083                 }
11084         }
11085         g_value_unset(&item);
11086         gst_iterator_free(iter);
11087
11088         if (!is_all_drained) {
11089                 LOGD("Wait util the all pads get EOS.");
11090                 MMPLAYER_CMD_UNLOCK(player);
11091                 MMPLAYER_FLEAVE();
11092                 return;
11093         }
11094
11095         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11096         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11097
11098         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11099         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11100         __mmplayer_deactivate_old_path(player);
11101         MMPLAYER_CMD_UNLOCK(player);
11102
11103         MMPLAYER_FLEAVE();
11104 }
11105
11106 static void
11107 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11108 {
11109         mm_player_t* player = (mm_player_t*)data;
11110         const gchar* klass = NULL;
11111         gchar* factory_name = NULL;
11112
11113         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11114         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11115
11116         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11117
11118         if (__mmplayer_add_dump_buffer_probe(player, element))
11119                 LOGD("add buffer probe");
11120
11121         //<-
11122         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11123                 gchar* selected = NULL;
11124                 selected = g_strdup(GST_ELEMENT_NAME(element));
11125                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11126         }
11127         //-> temp code
11128
11129         if (g_strrstr(klass, "Parser")) {
11130                 gchar* selected = NULL;
11131
11132                 selected = g_strdup(factory_name);
11133                 player->parsers = g_list_append(player->parsers, selected);
11134         }
11135
11136         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11137                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11138                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11139
11140                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11141                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11142
11143                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11144                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11145                                                 "max-video-width", player->adaptive_info.limit.width,
11146                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11147
11148         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11149                 /* FIXIT : first value will be overwritten if there's more
11150                  * than 1 demuxer/parser
11151                  */
11152
11153                 //LOGD("plugged element is demuxer. take it\n");
11154                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11155                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11156
11157                 /*Added for multi audio support */ // Q. del?
11158                 if (g_strrstr(klass, "Demux")) {
11159                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11160                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11161                 }
11162         }
11163
11164         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11165                 int surface_type = 0;
11166
11167                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11168         }
11169
11170         // to support trust-zone only
11171         if (g_strrstr(factory_name, "asfdemux")) {
11172                 LOGD("set file-location %s\n", player->profile.uri);
11173                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11174
11175                 if (player->video_hub_download_mode == TRUE)
11176                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11177         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11178                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11179                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11180         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11181                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11182                         (__mmplayer_is_only_mp3_type(player->type))) {
11183                         LOGD("[mpegaudioparse] set streaming pull mode.");
11184                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11185                 }
11186         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11187                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11188         }
11189
11190         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11191                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11192                 LOGD("plugged element is multiqueue. take it\n");
11193
11194                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11195                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11196
11197                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11198                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11199                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11200                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11201                         __mm_player_streaming_set_multiqueue(player->streamer,
11202                                 element,
11203                                 TRUE,
11204                                 player->ini.http_buffering_time,
11205                                 1.0,
11206                                 player->ini.http_buffering_limit);
11207
11208                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11209                 }
11210         }
11211
11212         return;
11213 }
11214
11215 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11216 {
11217         MMPLAYER_FENTER();
11218         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11219
11220         if (MMPLAYER_IS_STREAMING(player))
11221                 return FALSE;
11222
11223         /* This callback can be set to music player only. */
11224         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11225                 LOGW("audio callback is not supported for video");
11226                 return FALSE;
11227         }
11228
11229         if (player->audio_stream_cb) {
11230                 GstPad *pad = NULL;
11231
11232                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11233
11234                 if (!pad) {
11235                         LOGE("failed to get sink pad from audiosink to probe data\n");
11236                         return FALSE;
11237                 }
11238                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11239                         __mmplayer_audio_stream_probe, player, NULL);
11240
11241                 gst_object_unref(pad);
11242
11243                 pad = NULL;
11244         } else {
11245                 LOGE("There is no audio callback to configure.\n");
11246                 return FALSE;
11247         }
11248
11249         MMPLAYER_FLEAVE();
11250
11251         return TRUE;
11252 }
11253
11254 static void
11255 __mmplayer_release_misc(mm_player_t* player)
11256 {
11257         int i;
11258         bool cur_mode = player->set_mode.rich_audio;
11259         MMPLAYER_FENTER();
11260
11261         MMPLAYER_RETURN_IF_FAIL(player);
11262
11263         player->video_stream_cb = NULL;
11264         player->video_stream_cb_user_param = NULL;
11265         player->video_stream_prerolled = FALSE;
11266
11267         player->audio_stream_cb = NULL;
11268         player->audio_stream_render_cb_ex = NULL;
11269         player->audio_stream_cb_user_param = NULL;
11270         player->audio_stream_sink_sync = false;
11271
11272         player->video_stream_changed_cb = NULL;
11273         player->video_stream_changed_cb_user_param = NULL;
11274
11275         player->audio_stream_changed_cb = NULL;
11276         player->audio_stream_changed_cb_user_param = NULL;
11277
11278         player->sent_bos = FALSE;
11279         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11280
11281         player->doing_seek = FALSE;
11282
11283         player->total_bitrate = 0;
11284         player->total_maximum_bitrate = 0;
11285
11286         player->not_found_demuxer = 0;
11287
11288         player->last_position = 0;
11289         player->duration = 0;
11290         player->http_content_size = 0;
11291         player->not_supported_codec = MISSING_PLUGIN_NONE;
11292         player->can_support_codec = FOUND_PLUGIN_NONE;
11293         player->pending_seek.is_pending = FALSE;
11294         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11295         player->pending_seek.pos = 0;
11296         player->msg_posted = FALSE;
11297         player->has_many_types = FALSE;
11298         player->max_audio_channels = 0;
11299         player->video_share_api_delta = 0;
11300         player->video_share_clock_delta = 0;
11301         player->is_subtitle_force_drop = FALSE;
11302         player->play_subtitle = FALSE;
11303         player->adjust_subtitle_pos = 0;
11304         player->last_multiwin_status = FALSE;
11305         player->has_closed_caption = FALSE;
11306         player->set_mode.media_packet_video_stream = FALSE;
11307         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11308         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11309         /* recover mode */
11310         player->set_mode.rich_audio = cur_mode;
11311
11312         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11313                 player->bitrate[i] = 0;
11314                 player->maximum_bitrate[i] = 0;
11315         }
11316
11317         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11318
11319         /* remove media stream cb(appsrc cb) */
11320         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11321                 player->media_stream_buffer_status_cb[i] = NULL;
11322                 player->media_stream_seek_data_cb[i] = NULL;
11323                 player->buffer_cb_user_param[i] = NULL;
11324                 player->seek_cb_user_param[i] = NULL;
11325         }
11326         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11327
11328         /* free memory related to audio effect */
11329         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11330
11331         if (player->adaptive_info.var_list) {
11332                 g_list_free_full(player->adaptive_info.var_list, g_free);
11333                 player->adaptive_info.var_list = NULL;
11334         }
11335
11336         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11337         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11338         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11339
11340         /* Reset video360 settings to their defaults in case if the pipeline is to be
11341          * re-created.
11342          * */
11343         player->video360_metadata.is_spherical = -1;
11344         player->is_openal_plugin_used = FALSE;
11345
11346         player->is_content_spherical = FALSE;
11347         player->is_video360_enabled = TRUE;
11348         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11349         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11350         player->video360_yaw_radians = 4;
11351         player->video360_pitch_radians = 4;
11352         player->video360_zoom = 1.0f;
11353         player->video360_horizontal_fov = 0;
11354         player->video360_vertical_fov = 0;
11355
11356         player->sound.rg_enable = false;
11357
11358         MMPLAYER_FLEAVE();
11359 }
11360
11361 static void
11362 __mmplayer_release_misc_post(mm_player_t* player)
11363 {
11364         char *original_uri = NULL;
11365         MMPLAYER_FENTER();
11366
11367         /* player->pipeline is already released before. */
11368
11369         MMPLAYER_RETURN_IF_FAIL(player);
11370
11371         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11372
11373         /* clean found parsers */
11374         if (player->parsers) {
11375                 GList *parsers = player->parsers;
11376                 for (; parsers; parsers = g_list_next(parsers)) {
11377                         gchar *name = parsers->data;
11378                         MMPLAYER_FREEIF(name);
11379                 }
11380                 g_list_free(player->parsers);
11381                 player->parsers = NULL;
11382         }
11383
11384         /* clean found audio decoders */
11385         if (player->audio_decoders) {
11386                 GList *a_dec = player->audio_decoders;
11387                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11388                         gchar *name = a_dec->data;
11389                         MMPLAYER_FREEIF(name);
11390                 }
11391                 g_list_free(player->audio_decoders);
11392                 player->audio_decoders = NULL;
11393         }
11394
11395         /* clean the uri list except original uri */
11396         if (player->uri_info.uri_list) {
11397                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11398
11399                 if (player->attrs) {
11400                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11401                         LOGD("restore original uri = %s\n", original_uri);
11402
11403                         if (mmf_attrs_commit(player->attrs))
11404                                 LOGE("failed to commit the original uri.\n");
11405                 }
11406
11407                 GList *uri_list = player->uri_info.uri_list;
11408                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11409                         gchar *uri = uri_list->data;
11410                         MMPLAYER_FREEIF(uri);
11411                 }
11412                 g_list_free(player->uri_info.uri_list);
11413                 player->uri_info.uri_list = NULL;
11414         }
11415
11416         /* clear the audio stream buffer list */
11417         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11418
11419         /* clear the video stream bo list */
11420         __mmplayer_video_stream_destroy_bo_list(player);
11421         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11422
11423         if (player->profile.input_mem.buf) {
11424                 free(player->profile.input_mem.buf);
11425                 player->profile.input_mem.buf = NULL;
11426         }
11427         player->profile.input_mem.len = 0;
11428         player->profile.input_mem.offset = 0;
11429
11430         player->uri_info.uri_idx = 0;
11431         MMPLAYER_FLEAVE();
11432 }
11433
11434 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11435 {
11436         GstElement *element = NULL;
11437         GstPad *sinkpad;
11438
11439         LOGD("creating %s to plug\n", name);
11440
11441         element = gst_element_factory_make(name, NULL);
11442         if (!element) {
11443                 LOGE("failed to create queue\n");
11444                 return NULL;
11445         }
11446
11447         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11448                 LOGE("failed to set state READY to %s\n", name);
11449                 gst_object_unref(element);
11450                 return NULL;
11451         }
11452
11453         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11454                 LOGE("failed to add %s\n", name);
11455                 gst_object_unref(element);
11456                 return NULL;
11457         }
11458
11459         sinkpad = gst_element_get_static_pad(element, "sink");
11460
11461         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11462                 LOGE("failed to link %s\n", name);
11463                 gst_object_unref(sinkpad);
11464                 gst_object_unref(element);
11465                 return NULL;
11466         }
11467
11468         LOGD("linked %s to pipeline successfully\n", name);
11469
11470         gst_object_unref(sinkpad);
11471
11472         return element;
11473 }
11474
11475 gboolean
11476 __mmplayer_check_subtitle(mm_player_t* player)
11477 {
11478         MMHandleType attrs = 0;
11479         char *subtitle_uri = NULL;
11480
11481         MMPLAYER_FENTER();
11482
11483         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11484
11485         /* get subtitle attribute */
11486         attrs = MMPLAYER_GET_ATTRS(player);
11487         if (!attrs)
11488                 return FALSE;
11489
11490         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11491         if (!subtitle_uri || !strlen(subtitle_uri))
11492                 return FALSE;
11493
11494         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11495         player->is_external_subtitle_present = TRUE;
11496
11497         MMPLAYER_FLEAVE();
11498
11499         return TRUE;
11500 }
11501
11502 static gboolean
11503 __mmplayer_can_extract_pcm(mm_player_t* player)
11504 {
11505         MMHandleType attrs = 0;
11506         gboolean sound_extraction = FALSE;
11507
11508         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11509
11510         attrs = MMPLAYER_GET_ATTRS(player);
11511         if (!attrs) {
11512                 LOGE("fail to get attributes.");
11513                 return FALSE;
11514         }
11515
11516         /* get sound_extraction property */
11517         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11518
11519         if (!sound_extraction) {
11520                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11521                 return FALSE;
11522         }
11523
11524         return TRUE;
11525 }
11526
11527 static gboolean
11528 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11529 {
11530         LOGD("\n");
11531         MMMessageParamType msg_param;
11532         gchar *msg_src_element = NULL;
11533         GstStructure *s = NULL;
11534         guint error_id = 0;
11535         gchar *error_string = NULL;
11536
11537         MMPLAYER_FENTER();
11538
11539         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11540         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11541
11542         s = gst_structure_copy(gst_message_get_structure(message));
11543
11544
11545         if (!gst_structure_get_uint(s, "error_id", &error_id))
11546                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11547
11548         switch (error_id) {
11549         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11550                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11551                 break;
11552         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11553                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11554                 break;
11555         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11556                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11557                 break;
11558         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11559                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11560                 break;
11561         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11562                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11563                 break;
11564         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11565                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11566                 break;
11567         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11568                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11569                 break;
11570         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11571                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11572                 break;
11573         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11574                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11575                 break;
11576         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11577                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11578                 break;
11579         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11580                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11581                 break;
11582         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11583                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11584                 break;
11585         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11586                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11587                 break;
11588         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11589                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11590                 break;
11591         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11592                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11593                 break;
11594         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11595                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11596                 break;
11597         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11598                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11599                 break;
11600         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11601                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11602                 break;
11603         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11604                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11605                 break;
11606         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11607                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11608                 break;
11609         case MMPLAYER_STREAMING_ERROR_GONE:
11610                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11611                 break;
11612         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11613                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11614                 break;
11615         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11616                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11617                 break;
11618         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11619                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11620                 break;
11621         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11622                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11623                 break;
11624         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11625                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11626                 break;
11627         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11628                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11629                 break;
11630         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11631                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11632                 break;
11633         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11634                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11635                 break;
11636         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11637                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11638                 break;
11639         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11640                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11641                 break;
11642         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11643                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11644                 break;
11645         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11646                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11647                 break;
11648         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11649                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11650                 break;
11651         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11652                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11653                 break;
11654         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11655                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11656                 break;
11657         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11658                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11659                 break;
11660         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11661                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11662                 break;
11663         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11664                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11665                 break;
11666         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11667                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11668                 break;
11669         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11670                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11671                 break;
11672         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11673                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11674                 break;
11675         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11676                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11677                 break;
11678         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11679                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11680                 break;
11681         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11682                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11683                 break;
11684         default:
11685                 {
11686                         gst_structure_free(s);
11687                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11688                 }
11689         }
11690
11691         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11692         if (error_string)
11693                 msg_param.data = (void *) error_string;
11694
11695         if (message->src) {
11696                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11697
11698                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11699                         msg_src_element, msg_param.code, (char*)msg_param.data);
11700         }
11701
11702         /* post error to application */
11703         if (!player->msg_posted) {
11704                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11705
11706                 /* don't post more if one was sent already */
11707                 player->msg_posted = TRUE;
11708         } else
11709                 LOGD("skip error post because it's sent already.\n");
11710
11711         gst_structure_free(s);
11712         MMPLAYER_FLEAVE();
11713         g_free(error_string);
11714
11715         return TRUE;
11716
11717 }
11718
11719 static void
11720 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11721 {
11722         MMPLAYER_RETURN_IF_FAIL(player);
11723
11724         /* post now if delay is zero */
11725         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11726                 LOGD("eos delay is zero. posting EOS now\n");
11727                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11728
11729                 if (player->set_mode.pcm_extraction)
11730                         __mmplayer_cancel_eos_timer(player);
11731
11732                 return;
11733         }
11734
11735         /* cancel if existing */
11736         __mmplayer_cancel_eos_timer(player);
11737
11738         /* init new timeout */
11739         /* NOTE : consider give high priority to this timer */
11740         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11741
11742         player->eos_timer = g_timeout_add(delay_in_ms,
11743                 __mmplayer_eos_timer_cb, player);
11744
11745         player->global_default = g_main_context_default();
11746         LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11747
11748         /* check timer is valid. if not, send EOS now */
11749         if (player->eos_timer == 0) {
11750                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11751                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11752         }
11753 }
11754
11755 static void
11756 __mmplayer_cancel_eos_timer(mm_player_t* player)
11757 {
11758         MMPLAYER_RETURN_IF_FAIL(player);
11759
11760         if (player->eos_timer) {
11761                 LOGD("cancel eos timer");
11762                 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11763                 player->eos_timer = 0;
11764         }
11765
11766         return;
11767 }
11768
11769 static gboolean
11770 __mmplayer_eos_timer_cb(gpointer u_data)
11771 {
11772         mm_player_t* player = NULL;
11773         MMHandleType attrs = 0;
11774         int count = 0;
11775
11776         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11777
11778         player = (mm_player_t*) u_data;
11779         attrs = MMPLAYER_GET_ATTRS(player);
11780
11781         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11782
11783         if (count == -1) {
11784                 gint ret_value = 0;
11785                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11786                 if (ret_value != MM_ERROR_NONE) {
11787                         LOGE("seeking to 0 failed in repeat play");
11788                 }
11789         } else {
11790                 /* posting eos */
11791                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11792         }
11793
11794         /* we are returning FALSE as we need only one posting */
11795         return FALSE;
11796 }
11797
11798 /* sending event to one of sinkelements */
11799 static gboolean
11800 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11801 {
11802         GstEvent * event2 = NULL;
11803         GList *sinks = NULL;
11804         gboolean res = FALSE;
11805         MMPLAYER_FENTER();
11806
11807         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11808         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11809
11810         /* While adding subtitles in live feeds seek is getting called.
11811            Adding defensive check in framework layer.*/
11812         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11813                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11814                         LOGE("Should not send seek event during live playback");
11815                         return TRUE;
11816                 }
11817         }
11818
11819         if (player->play_subtitle)
11820                 event2 = gst_event_copy((const GstEvent *)event);
11821
11822         sinks = player->sink_elements;
11823         while (sinks) {
11824                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11825
11826                 if (GST_IS_ELEMENT(sink)) {
11827                         /* keep ref to the event */
11828                         gst_event_ref(event);
11829
11830                         if ((res = gst_element_send_event(sink, event))) {
11831                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11832                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11833
11834                                 /* rtsp case, asyn_done is not called after seek during pause state */
11835                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11836                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11837                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11838                                                         LOGD("RTSP seek completed, after pause state..\n");
11839                                                         player->doing_seek = FALSE;
11840                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11841                                                 }
11842
11843                                         }
11844                                 }
11845
11846                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11847                                         sinks = g_list_next(sinks);
11848                                         continue;
11849                                 } else {
11850                                         break;
11851                                 }
11852                         }
11853
11854                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11855                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11856                 }
11857
11858                 sinks = g_list_next(sinks);
11859         }
11860
11861         /* Note : Textbin is not linked to the video or audio bin.
11862          * It needs to send the event to the text sink seperatelly.
11863          */
11864          if (player->play_subtitle && player->pipeline) {
11865                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11866
11867                 if (GST_IS_ELEMENT(text_sink)) {
11868                         /* keep ref to the event */
11869                         gst_event_ref(event2);
11870
11871                         if ((res = gst_element_send_event(text_sink, event2)))
11872                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11873                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11874                         else
11875                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11876                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11877
11878                         gst_event_unref(event2);
11879                 }
11880          }
11881
11882         gst_event_unref(event);
11883
11884         MMPLAYER_FLEAVE();
11885
11886         return res;
11887 }
11888
11889 static void
11890 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11891 {
11892         MMPLAYER_FENTER();
11893
11894         MMPLAYER_RETURN_IF_FAIL(player);
11895         MMPLAYER_RETURN_IF_FAIL(sink);
11896
11897         player->sink_elements =
11898                 g_list_append(player->sink_elements, sink);
11899
11900         MMPLAYER_FLEAVE();
11901 }
11902
11903 static void
11904 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11905 {
11906         MMPLAYER_FENTER();
11907
11908         MMPLAYER_RETURN_IF_FAIL(player);
11909         MMPLAYER_RETURN_IF_FAIL(sink);
11910
11911         player->sink_elements =
11912                         g_list_remove(player->sink_elements, sink);
11913
11914         MMPLAYER_FLEAVE();
11915 }
11916
11917 static gboolean
11918 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11919                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11920                         gint64 cur, GstSeekType stop_type, gint64 stop)
11921 {
11922         GstEvent* event = NULL;
11923         gboolean result = FALSE;
11924
11925         MMPLAYER_FENTER();
11926
11927         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11928
11929         if (player->pipeline && player->pipeline->textbin)
11930                 __mmplayer_drop_subtitle(player, FALSE);
11931
11932         event = gst_event_new_seek(rate, format, flags, cur_type,
11933                 cur, stop_type, stop);
11934
11935         result = __gst_send_event_to_sink(player, event);
11936
11937         MMPLAYER_FLEAVE();
11938
11939         return result;
11940 }
11941
11942 /* NOTE : be careful with calling this api. please refer to below glib comment
11943  * glib comment : Note that there is a bug in GObject that makes this function much
11944  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11945  * will no longer be called, but, the signal handler is not currently disconnected.
11946  * If the instance is itself being freed at the same time than this doesn't matter,
11947  * since the signal will automatically be removed, but if instance persists,
11948  * then the signal handler will leak. You should not remove the signal yourself
11949  * because in a future versions of GObject, the handler will automatically be
11950  * disconnected.
11951  *
11952  * It's possible to work around this problem in a way that will continue to work
11953  * with future versions of GObject by checking that the signal handler is still
11954  * connected before disconnected it:
11955  *
11956  *  if (g_signal_handler_is_connected(instance, id))
11957  *    g_signal_handler_disconnect(instance, id);
11958  */
11959 static void
11960 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11961 {
11962         GList* sig_list = NULL;
11963         MMPlayerSignalItem* item = NULL;
11964
11965         MMPLAYER_FENTER();
11966
11967         MMPLAYER_RETURN_IF_FAIL(player);
11968
11969         LOGD("release signals type : %d", type);
11970
11971         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11972                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11973                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11974                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11975                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11976                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11977                 return;
11978         }
11979
11980         sig_list = player->signals[type];
11981
11982         for (; sig_list; sig_list = sig_list->next) {
11983                 item = sig_list->data;
11984
11985                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11986                         if (g_signal_handler_is_connected(item->obj, item->sig))
11987                                 g_signal_handler_disconnect(item->obj, item->sig);
11988                 }
11989
11990                 MMPLAYER_FREEIF(item);
11991         }
11992
11993         g_list_free(player->signals[type]);
11994         player->signals[type] = NULL;
11995
11996         MMPLAYER_FLEAVE();
11997
11998         return;
11999 }
12000
12001 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12002 {
12003         mm_player_t* player = 0;
12004         int prev_display_surface_type = 0;
12005         void *prev_display_overlay = NULL;
12006         const gchar *klass = NULL;
12007         gchar *cur_videosink_name = NULL;
12008         int ret = 0;
12009         int i = 0;
12010         int num_of_dec = 2; /* DEC1, DEC2 */
12011
12012         MMPLAYER_FENTER();
12013
12014         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12015         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12016
12017         player = MM_PLAYER_CAST(handle);
12018
12019         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12020                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12021                 MMPLAYER_FLEAVE();
12022                 return MM_ERROR_INVALID_ARGUMENT;
12023         }
12024
12025         /* load previous attributes */
12026         if (player->attrs) {
12027                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12028                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12029                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12030                 if (prev_display_surface_type == surface_type) {
12031                         LOGD("incoming display surface type is same as previous one, do nothing..");
12032                         MMPLAYER_FLEAVE();
12033                         return MM_ERROR_NONE;
12034                 }
12035         } else {
12036                 LOGE("failed to load attributes");
12037                 MMPLAYER_FLEAVE();
12038                 return MM_ERROR_PLAYER_INTERNAL;
12039         }
12040
12041         /* check videosink element is created */
12042         if (!player->pipeline || !player->pipeline->videobin ||
12043                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12044                 LOGD("videosink element is not yet ready");
12045
12046                 /* videobin is not created yet, so we just set attributes related to display surface */
12047                 LOGD("store display attribute for given surface type(%d)", surface_type);
12048                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12049                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12050                 if (mmf_attrs_commit(player->attrs)) {
12051                         LOGE("failed to commit attribute");
12052                         MMPLAYER_FLEAVE();
12053                         return MM_ERROR_PLAYER_INTERNAL;
12054                 }
12055                 MMPLAYER_FLEAVE();
12056                 return MM_ERROR_NONE;
12057         } else {
12058                 /* get player command status */
12059                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12060                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12061                         MMPLAYER_FLEAVE();
12062                         return MM_ERROR_PLAYER_INVALID_STATE;
12063                 }
12064
12065                 /* surface change */
12066                 for (i = 0 ; i < num_of_dec ; i++) {
12067                         if (player->pipeline->mainbin &&
12068                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12069                                 GstElementFactory *decfactory;
12070                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12071
12072                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12073                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12074                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12075                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12076                                                 if (ret) {
12077                                                         goto ERROR_CASE;
12078                                                 } else {
12079                                                         LOGW("success to changing display surface(%d)", surface_type);
12080                                                         MMPLAYER_FLEAVE();
12081                                                         return MM_ERROR_NONE;
12082                                                 }
12083                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12084                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12085                                                 if (ret) {
12086                                                         goto ERROR_CASE;
12087                                                 } else {
12088                                                         LOGW("success to changing display surface(%d)", surface_type);
12089                                                         MMPLAYER_FLEAVE();
12090                                                         return MM_ERROR_NONE;
12091                                                 }
12092                                         } else {
12093                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12094                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12095                                                 goto ERROR_CASE;
12096                                         }
12097                                 }
12098                         }
12099                 }
12100         }
12101
12102 ERROR_CASE:
12103         /* rollback to previous attributes */
12104         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12105         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12106         if (mmf_attrs_commit(player->attrs)) {
12107                 LOGE("failed to commit attributes to rollback");
12108                 MMPLAYER_FLEAVE();
12109                 return MM_ERROR_PLAYER_INTERNAL;
12110         }
12111         MMPLAYER_FLEAVE();
12112         return ret;
12113 }
12114
12115 /* NOTE : It does not support some use cases, eg using colorspace converter */
12116 int
12117 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12118 {
12119         GstPad *src_pad_dec = NULL;
12120         GstPad *sink_pad_videosink = NULL;
12121         GstPad *sink_pad_videobin = NULL;
12122         GstClock *clock = NULL;
12123         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12124         int ret = MM_ERROR_NONE;
12125         gboolean is_audiobin_created = TRUE;
12126
12127         MMPLAYER_FENTER();
12128
12129         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12130         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12131         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12132
12133         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12134         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12135
12136         /* get information whether if audiobin is created */
12137         if (!player->pipeline->audiobin ||
12138                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12139                 LOGW("audiobin is null, this video content may not have audio data");
12140                 is_audiobin_created = FALSE;
12141         }
12142
12143         /* get current state of player */
12144         previous_state = MMPLAYER_CURRENT_STATE(player);
12145         LOGD("previous state(%d)", previous_state);
12146
12147
12148         /* get src pad of decoder and block it */
12149         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12150         if (!src_pad_dec) {
12151                 LOGE("failed to get src pad from decode in mainbin");
12152                 return MM_ERROR_PLAYER_INTERNAL;
12153         }
12154
12155         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12156                 LOGW("trying to block pad(video)");
12157 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12158                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12159                         NULL, NULL, NULL);
12160                 {
12161                         LOGE("failed to set block pad(video)");
12162                         return MM_ERROR_PLAYER_INTERNAL;
12163                 }
12164                 LOGW("pad is blocked(video)");
12165         } else {
12166                 /* no data flows, so no need to do pad_block */
12167                 if (player->doing_seek)
12168                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12169
12170                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12171         }
12172
12173         /* remove pad */
12174         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12175                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12176                 LOGE("failed to remove previous ghost_pad for videobin");
12177                 return MM_ERROR_PLAYER_INTERNAL;
12178         }
12179
12180         /* change state of videobin to NULL */
12181         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12182         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12183         if (ret != GST_STATE_CHANGE_SUCCESS) {
12184                 LOGE("failed to change state of videobin to NULL");
12185                 return MM_ERROR_PLAYER_INTERNAL;
12186         }
12187
12188         /* unlink between decoder and videobin and remove previous videosink from videobin */
12189         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12190         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12191                 LOGE("failed to remove former videosink from videobin");
12192                 return MM_ERROR_PLAYER_INTERNAL;
12193         }
12194
12195         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12196
12197         /* create a new videosink and add it to videobin */
12198         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
12199         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12200                 LOGE("failed to create videosink element\n");
12201                 MMPLAYER_FLEAVE();
12202                 return MM_ERROR_PLAYER_INTERNAL;
12203         }
12204         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12205         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12206         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12207
12208         /* save attributes */
12209         if (player->attrs) {
12210                 /* set a new display surface type */
12211                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12212                 /* set a new diplay overlay */
12213                 switch (surface_type) {
12214                 case MM_DISPLAY_SURFACE_OVERLAY:
12215                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12216                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12217                         break;
12218                 default:
12219                         LOGE("invalid type(%d) for changing display surface", surface_type);
12220                         MMPLAYER_FLEAVE();
12221                         return MM_ERROR_INVALID_ARGUMENT;
12222                 }
12223                 if (mmf_attrs_commit(player->attrs)) {
12224                         LOGE("failed to commit");
12225                         MMPLAYER_FLEAVE();
12226                         return MM_ERROR_PLAYER_INTERNAL;
12227                 }
12228         } else {
12229                 LOGE("player->attrs is null, failed to save attributes");
12230                 MMPLAYER_FLEAVE();
12231                 return MM_ERROR_PLAYER_INTERNAL;
12232         }
12233
12234         /* update video param */
12235         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12236                 LOGE("failed to update video param");
12237                 return MM_ERROR_PLAYER_INTERNAL;
12238         }
12239
12240         /* change state of videobin to READY */
12241         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12242         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12243         if (ret != GST_STATE_CHANGE_SUCCESS) {
12244                 LOGE("failed to change state of videobin to READY");
12245                 return MM_ERROR_PLAYER_INTERNAL;
12246         }
12247
12248         /* change ghostpad */
12249         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12250         if (!sink_pad_videosink) {
12251                 LOGE("failed to get sink pad from videosink element");
12252                 return MM_ERROR_PLAYER_INTERNAL;
12253         }
12254         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12255         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12256                 LOGE("failed to set active to ghost_pad");
12257                 return MM_ERROR_PLAYER_INTERNAL;
12258         }
12259         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12260                 LOGE("failed to change ghostpad for videobin");
12261                 return MM_ERROR_PLAYER_INTERNAL;
12262         }
12263         gst_object_unref(sink_pad_videosink);
12264
12265         /* link decoder with videobin */
12266         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12267         if (!sink_pad_videobin) {
12268                 LOGE("failed to get sink pad from videobin");
12269                 return MM_ERROR_PLAYER_INTERNAL;
12270         }
12271         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12272                 LOGE("failed to link");
12273                 return MM_ERROR_PLAYER_INTERNAL;
12274         }
12275         gst_object_unref(sink_pad_videobin);
12276
12277         /* clock setting for a new videosink plugin */
12278         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12279                         so we set it from audiosink plugin or pipeline(system clock) */
12280         if (!is_audiobin_created) {
12281                 LOGW("audiobin is not created, get clock from pipeline..");
12282                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12283         } else {
12284                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12285         }
12286         if (clock) {
12287                 GstClockTime now;
12288                 GstClockTime base_time;
12289                 LOGD("set the clock to videosink");
12290                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12291                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12292                 if (clock) {
12293                         LOGD("got clock of videosink");
12294                         now = gst_clock_get_time(clock);
12295                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12296                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12297                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12298                 } else {
12299                         LOGE("failed to get clock of videosink after setting clock");
12300                         return MM_ERROR_PLAYER_INTERNAL;
12301                 }
12302         } else
12303                 LOGW("failed to get clock, maybe it is the time before first playing");
12304
12305         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12306                 /* change state of videobin to PAUSED */
12307                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12308                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12309                 if (ret != GST_STATE_CHANGE_FAILURE) {
12310                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12311                 } else {
12312                         LOGE("failed to change state of videobin to PLAYING");
12313                         return MM_ERROR_PLAYER_INTERNAL;
12314                 }
12315
12316                 /* release blocked and unref src pad of video decoder */
12317                 #if 0
12318                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12319                         LOGE("failed to set pad blocked FALSE(video)");
12320                         return MM_ERROR_PLAYER_INTERNAL;
12321                 }
12322                 #endif
12323                 LOGW("pad is unblocked(video)");
12324         } else {
12325                 if (player->doing_seek)
12326                         LOGW("not completed seek(%d)", player->doing_seek);
12327                 /* change state of videobin to PAUSED */
12328                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12329                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12330                 if (ret != GST_STATE_CHANGE_FAILURE) {
12331                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12332                 } else {
12333                         LOGE("failed to change state of videobin to PLAYING");
12334                         return MM_ERROR_PLAYER_INTERNAL;
12335                 }
12336
12337                 /* already skipped pad block */
12338                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12339         }
12340
12341         /* do get/set position for new videosink plugin */
12342         {
12343                 unsigned long position = 0;
12344                 gint64 pos_msec = 0;
12345
12346                 LOGD("do get/set position for new videosink plugin");
12347                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12348                         LOGE("failed to get position");
12349                         return MM_ERROR_PLAYER_INTERNAL;
12350                 }
12351 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12352                 /* accurate seek */
12353                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12354                         LOGE("failed to set position");
12355                         return MM_ERROR_PLAYER_INTERNAL;
12356                 }
12357 #else
12358                 /* key unit seek */
12359                 pos_msec = position * G_GINT64_CONSTANT(1000000);
12360                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12361                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12362                                                         GST_SEEK_TYPE_SET, pos_msec,
12363                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12364                 if (!ret) {
12365                         LOGE("failed to set position");
12366                         return MM_ERROR_PLAYER_INTERNAL;
12367                 }
12368 #endif
12369         }
12370
12371         if (src_pad_dec)
12372                 gst_object_unref(src_pad_dec);
12373         LOGD("success to change sink");
12374
12375         MMPLAYER_FLEAVE();
12376
12377         return MM_ERROR_NONE;
12378 }
12379
12380
12381 /* Note : if silent is true, then subtitle would not be displayed. :*/
12382 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12383 {
12384         mm_player_t* player = (mm_player_t*) hplayer;
12385
12386         MMPLAYER_FENTER();
12387
12388         /* check player handle */
12389         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12390
12391         player->set_mode.subtitle_off = silent;
12392
12393         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12394
12395         MMPLAYER_FLEAVE();
12396
12397         return MM_ERROR_NONE;
12398 }
12399
12400 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12401 {
12402         MMPlayerGstElement* mainbin = NULL;
12403         MMPlayerGstElement* textbin = NULL;
12404         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12405         GstState current_state = GST_STATE_VOID_PENDING;
12406         GstState element_state = GST_STATE_VOID_PENDING;
12407         GstState element_pending_state = GST_STATE_VOID_PENDING;
12408         gint64 time = 0;
12409         GstEvent *event = NULL;
12410         int result = MM_ERROR_NONE;
12411
12412         GstClock *curr_clock = NULL;
12413         GstClockTime base_time, start_time, curr_time;
12414
12415
12416         MMPLAYER_FENTER();
12417
12418         /* check player handle */
12419         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12420                                                                 player->pipeline &&
12421                                                                 player->pipeline->mainbin &&
12422                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12423
12424         mainbin = player->pipeline->mainbin;
12425         textbin = player->pipeline->textbin;
12426
12427         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12428
12429         // sync clock with current pipeline
12430         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12431         curr_time = gst_clock_get_time(curr_clock);
12432
12433         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12434         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12435
12436         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12437                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12438
12439         if (current_state > GST_STATE_READY) {
12440                 // sync state with current pipeline
12441                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12442                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12443                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12444
12445                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12446                 if (GST_STATE_CHANGE_FAILURE == ret) {
12447                         LOGE("fail to state change.\n");
12448                         result = MM_ERROR_PLAYER_INTERNAL;
12449                         goto ERROR;
12450                 }
12451         }
12452
12453         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12454         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12455
12456         if (curr_clock) {
12457                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12458                 gst_object_unref(curr_clock);
12459         }
12460
12461         // seek to current position
12462         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12463                 result = MM_ERROR_PLAYER_INVALID_STATE;
12464                 LOGE("gst_element_query_position failed, invalid state\n");
12465                 goto ERROR;
12466         }
12467
12468         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12469         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);
12470         if (event) {
12471                 __gst_send_event_to_sink(player, event);
12472         } else {
12473                 result = MM_ERROR_PLAYER_INTERNAL;
12474                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12475                 goto ERROR;
12476         }
12477
12478         /* sync state with current pipeline */
12479         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12480         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12481         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12482
12483         return MM_ERROR_NONE;
12484
12485 ERROR:
12486         /* release text pipeline resource */
12487         player->textsink_linked = 0;
12488
12489         /* release signal */
12490         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12491
12492         /* release textbin with it's childs */
12493         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12494         MMPLAYER_FREEIF(player->pipeline->textbin);
12495         player->pipeline->textbin = NULL;
12496
12497         /* release subtitle elem */
12498         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12499         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12500
12501         return result;
12502 }
12503
12504 static int
12505 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12506 {
12507         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12508         GstState current_state = GST_STATE_VOID_PENDING;
12509
12510         MMHandleType attrs = 0;
12511         MMPlayerGstElement* mainbin = NULL;
12512         MMPlayerGstElement* textbin = NULL;
12513
12514         gchar* subtitle_uri = NULL;
12515         int result = MM_ERROR_NONE;
12516         const gchar *charset = NULL;
12517
12518         MMPLAYER_FENTER();
12519
12520         /* check player handle */
12521         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12522                                                                 player->pipeline &&
12523                                                                 player->pipeline->mainbin &&
12524                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12525         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12526
12527         mainbin = player->pipeline->mainbin;
12528         textbin = player->pipeline->textbin;
12529
12530         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12531         if (current_state < GST_STATE_READY) {
12532                 result = MM_ERROR_PLAYER_INVALID_STATE;
12533                 LOGE("Pipeline is not in proper state\n");
12534                 goto EXIT;
12535         }
12536
12537         attrs = MMPLAYER_GET_ATTRS(player);
12538         if (!attrs) {
12539                 LOGE("cannot get content attribute\n");
12540                 result = MM_ERROR_PLAYER_INTERNAL;
12541                 goto EXIT;
12542         }
12543
12544         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12545         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12546                 LOGE("subtitle uri is not proper filepath\n");
12547                 result = MM_ERROR_PLAYER_INVALID_URI;
12548                 goto EXIT;
12549         }
12550
12551         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12552                 LOGE("failed to get storage info of subtitle path");
12553                 result = MM_ERROR_PLAYER_INVALID_URI;
12554                 goto EXIT;
12555         }
12556
12557         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12558         LOGD("new subtitle file path is [%s]\n", filepath);
12559
12560         if (!strcmp(filepath, subtitle_uri)) {
12561                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12562                 goto EXIT;
12563         } else {
12564                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12565                 if (mmf_attrs_commit(player->attrs)) {
12566                         LOGE("failed to commit.\n");
12567                         goto EXIT;
12568                 }
12569         }
12570
12571         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12572         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12573         player->subtitle_language_list = NULL;
12574         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12575
12576         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12577         if (ret != GST_STATE_CHANGE_SUCCESS) {
12578                 LOGE("failed to change state of textbin to READY");
12579                 result = MM_ERROR_PLAYER_INTERNAL;
12580                 goto EXIT;
12581         }
12582
12583         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12584         if (ret != GST_STATE_CHANGE_SUCCESS) {
12585                 LOGE("failed to change state of subparse to READY");
12586                 result = MM_ERROR_PLAYER_INTERNAL;
12587                 goto EXIT;
12588         }
12589
12590         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12591         if (ret != GST_STATE_CHANGE_SUCCESS) {
12592                 LOGE("failed to change state of filesrc to READY");
12593                 result = MM_ERROR_PLAYER_INTERNAL;
12594                 goto EXIT;
12595         }
12596
12597         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12598
12599         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12600
12601         charset = util_get_charset(filepath);
12602         if (charset) {
12603                 LOGD("detected charset is %s\n", charset);
12604                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12605         }
12606
12607         result = _mmplayer_sync_subtitle_pipeline(player);
12608
12609 EXIT:
12610         MMPLAYER_FLEAVE();
12611         return result;
12612 }
12613
12614 /* API to switch between external subtitles */
12615 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12616 {
12617         int result = MM_ERROR_NONE;
12618         mm_player_t* player = (mm_player_t*)hplayer;
12619         char *path = NULL;
12620
12621         MMPLAYER_FENTER();
12622
12623         /* check player handle */
12624         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12625
12626         /* filepath can be null in idle state */
12627         if (filepath) {
12628                 /* check file path */
12629                 if ((path = strstr(filepath, "file://")))
12630                         result = util_exist_file_path(path + 7);
12631                 else
12632                         result = util_exist_file_path(filepath);
12633
12634                 if (result != MM_ERROR_NONE) {
12635                         LOGE("invalid subtitle path 0x%X", result);
12636                         return result; /* file not found or permission denied */
12637                 }
12638         }
12639
12640         if (!player->pipeline) {
12641                 /* IDLE state */
12642                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12643                 if (mmf_attrs_commit(player->attrs)) {
12644                         LOGE("failed to commit");       /* subtitle path will not be created */
12645                         return MM_ERROR_PLAYER_INTERNAL;
12646                 }
12647         } else {
12648                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12649                 /* check filepath */
12650                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12651
12652                 if (!__mmplayer_check_subtitle(player)) {
12653                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12654                         if (mmf_attrs_commit(player->attrs)) {
12655                                 LOGE("failed to commit");
12656                                 return MM_ERROR_PLAYER_INTERNAL;
12657                         }
12658
12659                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12660                                 LOGE("fail to create text pipeline");
12661                                 return MM_ERROR_PLAYER_INTERNAL;
12662                         }
12663
12664                         result = _mmplayer_sync_subtitle_pipeline(player);
12665                 } else {
12666                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12667                 }
12668
12669                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12670                 player->is_external_subtitle_added_now = TRUE;
12671
12672                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12673                 if (!player->subtitle_language_list) {
12674                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12675                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12676                                 LOGW("subtitle language list is not updated yet");
12677                 }
12678                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12679         }
12680
12681         MMPLAYER_FLEAVE();
12682         return result;
12683 }
12684
12685 static int
12686 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12687 {
12688         int result = MM_ERROR_NONE;
12689         gchar* change_pad_name = NULL;
12690         GstPad* sinkpad = NULL;
12691         MMPlayerGstElement* mainbin = NULL;
12692         enum MainElementID elemId = MMPLAYER_M_NUM;
12693         GstCaps* caps = NULL;
12694         gint total_track_num = 0;
12695
12696         MMPLAYER_FENTER();
12697
12698         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12699                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12700
12701         LOGD("Change Track(%d) to %d\n", type, index);
12702
12703         mainbin = player->pipeline->mainbin;
12704
12705         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12706                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12707         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12708                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12709         } else {
12710                 /* Changing Video Track is not supported. */
12711                 LOGE("Track Type Error\n");
12712                 goto EXIT;
12713         }
12714
12715         if (mainbin[elemId].gst == NULL) {
12716                 result = MM_ERROR_PLAYER_NO_OP;
12717                 LOGD("Req track doesn't exist\n");
12718                 goto EXIT;
12719         }
12720
12721         total_track_num = player->selector[type].total_track_num;
12722         if (total_track_num <= 0) {
12723                 result = MM_ERROR_PLAYER_NO_OP;
12724                 LOGD("Language list is not available \n");
12725                 goto EXIT;
12726         }
12727
12728         if ((index < 0) || (index >= total_track_num)) {
12729                 result = MM_ERROR_INVALID_ARGUMENT;
12730                 LOGD("Not a proper index : %d \n", index);
12731                 goto EXIT;
12732         }
12733
12734         /*To get the new pad from the selector*/
12735         change_pad_name = g_strdup_printf("sink_%u", index);
12736         if (change_pad_name == NULL) {
12737                 result = MM_ERROR_PLAYER_INTERNAL;
12738                 LOGD("Pad does not exists\n");
12739                 goto EXIT;
12740         }
12741
12742         LOGD("new active pad name: %s\n", change_pad_name);
12743
12744         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12745         if (sinkpad == NULL) {
12746                 LOGD("sinkpad is NULL");
12747                 result = MM_ERROR_PLAYER_INTERNAL;
12748                 goto EXIT;
12749         }
12750
12751         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12752         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12753
12754         caps = gst_pad_get_current_caps(sinkpad);
12755         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12756
12757         if (sinkpad)
12758                 gst_object_unref(sinkpad);
12759
12760         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12761                 __mmplayer_set_audio_attrs(player, caps);
12762
12763 EXIT:
12764
12765         MMPLAYER_FREEIF(change_pad_name);
12766         return result;
12767 }
12768
12769 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12770 {
12771         int result = MM_ERROR_NONE;
12772         mm_player_t* player = NULL;
12773         MMPlayerGstElement* mainbin = NULL;
12774
12775         gint current_active_index = 0;
12776
12777         GstState current_state = GST_STATE_VOID_PENDING;
12778         GstEvent* event = NULL;
12779         gint64 time = 0;
12780
12781         MMPLAYER_FENTER();
12782
12783         player = (mm_player_t*)hplayer;
12784         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12785
12786         if (!player->pipeline) {
12787                 LOGE("Track %d pre setting -> %d\n", type, index);
12788
12789                 player->selector[type].active_pad_index = index;
12790                 goto EXIT;
12791         }
12792
12793         mainbin = player->pipeline->mainbin;
12794
12795         current_active_index = player->selector[type].active_pad_index;
12796
12797         /*If index is same as running index no need to change the pad*/
12798         if (current_active_index == index)
12799                 goto EXIT;
12800
12801         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12802                 result = MM_ERROR_PLAYER_INVALID_STATE;
12803                 goto EXIT;
12804         }
12805
12806         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12807         if (current_state < GST_STATE_PAUSED) {
12808                 result = MM_ERROR_PLAYER_INVALID_STATE;
12809                 LOGW("Pipeline not in porper state\n");
12810                 goto EXIT;
12811         }
12812
12813         result = __mmplayer_change_selector_pad(player, type, index);
12814         if (result != MM_ERROR_NONE) {
12815                 LOGE("change selector pad error\n");
12816                 goto EXIT;
12817         }
12818
12819         player->selector[type].active_pad_index = index;
12820
12821         if (current_state == GST_STATE_PLAYING) {
12822                 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);
12823                 if (event) {
12824                         __gst_send_event_to_sink(player, event);
12825                 } else {
12826                         result = MM_ERROR_PLAYER_INTERNAL;
12827                         goto EXIT;
12828                 }
12829         }
12830
12831 EXIT:
12832         return result;
12833 }
12834
12835 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12836 {
12837         mm_player_t* player = (mm_player_t*) hplayer;
12838
12839         MMPLAYER_FENTER();
12840
12841         /* check player handle */
12842         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12843
12844         *silent = player->set_mode.subtitle_off;
12845
12846         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12847
12848         MMPLAYER_FLEAVE();
12849
12850         return MM_ERROR_NONE;
12851 }
12852
12853 gboolean
12854 __is_ms_buff_src(mm_player_t* player)
12855 {
12856         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12857
12858         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12859 }
12860
12861 gboolean
12862 __has_suffix(mm_player_t* player, const gchar* suffix)
12863 {
12864         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12865         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12866
12867         gboolean ret = FALSE;
12868         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12869         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12870
12871         if (g_str_has_suffix(player->profile.uri, suffix))
12872                 ret = TRUE;
12873
12874         MMPLAYER_FREEIF(t_url);
12875         MMPLAYER_FREEIF(t_suffix);
12876
12877         return ret;
12878 }
12879
12880 int
12881 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12882 {
12883         mm_player_t* player = (mm_player_t*) hplayer;
12884
12885         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12886
12887         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12888                 MMPLAYER_PRINT_STATE(player);
12889                 LOGE("wrong-state : can't set the download mode to parse");
12890                 return MM_ERROR_PLAYER_INVALID_STATE;
12891         }
12892
12893         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12894         player->video_hub_download_mode = mode;
12895
12896         return MM_ERROR_NONE;
12897 }
12898
12899 int
12900 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12901 {
12902         mm_player_t* player = (mm_player_t*) hplayer;
12903
12904         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12905
12906         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12907         player->sync_handler = enable;
12908
12909         return MM_ERROR_NONE;
12910 }
12911
12912 int
12913 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12914                                         long long clock,
12915                                         long long clock_delta,
12916                                         long long video_time,
12917                                         long long media_clock,
12918                                         long long audio_time)
12919 {
12920         mm_player_t* player = (mm_player_t*) hplayer;
12921         MMPlayerGstElement* mainbin = NULL;
12922         GstClockTime start_time_audio = 0, start_time_video = 0;
12923         GstClockTimeDiff base_time = 0, new_base_time = 0;
12924         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12925         gint64 api_delta = 0;
12926         gint64 position = 0, position_delta = 0;
12927         gint64 adj_base_time = 0;
12928         GstClock *curr_clock = NULL;
12929         GstClockTime curr_time = 0;
12930         gboolean query_ret = TRUE;
12931         int result = MM_ERROR_NONE;
12932
12933         MMPLAYER_FENTER();
12934
12935         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12936         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12937         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12938
12939         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12940
12941         if ((video_time < 0) || (player->doing_seek)) {
12942                 LOGD("skip setting master clock.  %lld", video_time);
12943                 goto EXIT;
12944         }
12945
12946         mainbin = player->pipeline->mainbin;
12947
12948         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12949         curr_time = gst_clock_get_time(curr_clock);
12950
12951         current_state = MMPLAYER_CURRENT_STATE(player);
12952
12953         if (current_state == MM_PLAYER_STATE_PLAYING)
12954                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12955
12956         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12957                 (!query_ret)) {
12958                 position = player->last_position;
12959                 LOGD("query fail. %lld", position);
12960         }
12961
12962         clock *= GST_USECOND;
12963         clock_delta *= GST_USECOND;
12964
12965         api_delta = clock - curr_time;
12966         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12967                 player->video_share_api_delta = api_delta;
12968         else
12969                 clock_delta += (api_delta - player->video_share_api_delta);
12970
12971         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12972                 player->video_share_clock_delta = (gint64)clock_delta;
12973
12974                 position_delta = (position/GST_USECOND) - video_time;
12975                 position_delta *= GST_USECOND;
12976
12977                 adj_base_time = position_delta;
12978                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12979
12980         } else {
12981                 gint64 new_play_time = 0;
12982                 gint64 network_delay = 0;
12983
12984                 video_time *= GST_USECOND;
12985
12986                 network_delay = clock_delta - player->video_share_clock_delta;
12987                 new_play_time = video_time + network_delay;
12988
12989                 adj_base_time = position - new_play_time;
12990
12991                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
12992                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
12993         }
12994
12995         /* Adjust Current Stream Time with base_time of sink
12996          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
12997          * 2. Set new base time
12998          *    if adj_base_time is positive value, the stream time will be decreased.
12999          * 3. If seek event is occurred, the start time will be reset. */
13000         if ((player->pipeline->audiobin) &&
13001                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13002                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13003
13004                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13005                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13006                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13007                 }
13008
13009                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13010         }
13011
13012         if ((player->pipeline->videobin) &&
13013                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13014                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13015
13016                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13017                         LOGD("video sink : gst_element_set_start_time -> NONE");
13018                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13019                 }
13020
13021                 // if videobin exist, get base_time from videobin.
13022                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13023         }
13024
13025         new_base_time = base_time + adj_base_time;
13026
13027         if ((player->pipeline->audiobin) &&
13028                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13029                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13030
13031         if ((player->pipeline->videobin) &&
13032                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13033                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13034
13035 EXIT:
13036         MMPLAYER_FLEAVE();
13037
13038         return result;
13039 }
13040
13041 int
13042 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13043                                         long long *video_time,
13044                                         long long *media_clock,
13045                                         long long *audio_time)
13046 {
13047         mm_player_t* player = (mm_player_t*) hplayer;
13048         MMPlayerGstElement* mainbin = NULL;
13049         GstClock *curr_clock = NULL;
13050         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13051         gint64 position = 0;
13052         gboolean query_ret = TRUE;
13053
13054         MMPLAYER_FENTER();
13055
13056         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13057         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13058         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13059
13060         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13061         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13062         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13063
13064         mainbin = player->pipeline->mainbin;
13065
13066         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13067
13068         current_state = MMPLAYER_CURRENT_STATE(player);
13069
13070         if (current_state != MM_PLAYER_STATE_PAUSED)
13071                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13072
13073         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13074                 (!query_ret))
13075                 position = player->last_position;
13076
13077         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13078
13079         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13080
13081         if (curr_clock)
13082                 gst_object_unref(curr_clock);
13083
13084         MMPLAYER_FLEAVE();
13085
13086         return MM_ERROR_NONE;
13087 }
13088
13089 static gboolean
13090 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13091 {
13092         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13093         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13094
13095         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13096         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13097
13098         int idx = 0;
13099
13100         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13101                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13102                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13103                         mm_player_dump_t *dump_s;
13104                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13105
13106                         if (dump_s == NULL) {
13107                                 LOGE("malloc fail");
13108                                 return FALSE;
13109                         }
13110
13111                         dump_s->dump_element_file = NULL;
13112                         dump_s->dump_pad = NULL;
13113                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13114
13115                         if (dump_s->dump_pad) {
13116                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13117                                 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]);
13118                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13119                                 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);
13120                                 /* add list for removed buffer probe and close FILE */
13121                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13122                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13123                                 return TRUE;
13124                         } else {
13125                                 g_free(dump_s);
13126                                 dump_s = NULL;
13127                                 LOGE("failed to get %s sink pad added", factory_name);
13128                         }
13129
13130
13131                 }
13132         }
13133         return FALSE;
13134 }
13135
13136 static GstPadProbeReturn
13137 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13138 {
13139         FILE *dump_data = (FILE *) u_data;
13140 //      int written = 0;
13141         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13142         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13143
13144         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13145
13146         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13147
13148 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13149
13150         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13151
13152         return GST_PAD_PROBE_OK;
13153 }
13154
13155 static void
13156 __mmplayer_release_dump_list(GList *dump_list)
13157 {
13158         if (dump_list) {
13159                 GList *d_list = dump_list;
13160                 for (; d_list; d_list = g_list_next(d_list)) {
13161                         mm_player_dump_t *dump_s = d_list->data;
13162                         if (dump_s->dump_pad) {
13163                                 if (dump_s->probe_handle_id)
13164                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13165                         }
13166                         if (dump_s->dump_element_file) {
13167                                 fclose(dump_s->dump_element_file);
13168                                 dump_s->dump_element_file = NULL;
13169                         }
13170                         MMPLAYER_FREEIF(dump_s);
13171                 }
13172                 g_list_free(dump_list);
13173                 dump_list = NULL;
13174         }
13175 }
13176
13177 int
13178 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13179 {
13180         mm_player_t* player = (mm_player_t*) hplayer;
13181
13182         MMPLAYER_FENTER();
13183
13184         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13185         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13186
13187         *exist = player->has_closed_caption;
13188
13189         MMPLAYER_FLEAVE();
13190
13191         return MM_ERROR_NONE;
13192 }
13193
13194 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13195 {
13196         MMPLAYER_FENTER();
13197         if (buffer) {
13198                 // LOGD("unref internal gst buffer %p", buffer);
13199                 gst_buffer_unref((GstBuffer *)buffer);
13200                 buffer = NULL;
13201         }
13202         MMPLAYER_FLEAVE();
13203 }
13204
13205 void
13206 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13207 {
13208         mm_player_t *player  = (mm_player_t*)user_data;
13209         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13210         guint64 current_level_bytes = 0;
13211
13212         MMPLAYER_RETURN_IF_FAIL(player);
13213
13214         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13215
13216         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13217         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13218
13219         if (player->media_stream_buffer_status_cb[type])
13220                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13221         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13222
13223 }
13224
13225 void
13226 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13227 {
13228         mm_player_t *player  = (mm_player_t*)user_data;
13229         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13230         guint64 current_level_bytes = 0;
13231
13232         MMPLAYER_RETURN_IF_FAIL(player);
13233
13234         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13235
13236         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13237
13238         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13239         if (player->media_stream_buffer_status_cb[type])
13240                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13241         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13242 }
13243
13244 void
13245 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13246 {
13247         mm_player_t *player  = (mm_player_t*)user_data;
13248         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13249         guint64 current_level_bytes = 0;
13250
13251         MMPLAYER_RETURN_IF_FAIL(player);
13252
13253         LOGI("app-src: feed subtitle\n");
13254
13255         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13256
13257         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13258         if (player->media_stream_buffer_status_cb[type])
13259                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13260
13261         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13262 }
13263
13264 void
13265 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13266 {
13267         mm_player_t *player  = (mm_player_t*)user_data;
13268         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13269         guint64 current_level_bytes = 0;
13270
13271         MMPLAYER_RETURN_IF_FAIL(player);
13272
13273         LOGI("app-src: audio buffer is full.\n");
13274
13275         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13276
13277         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13278
13279         if (player->media_stream_buffer_status_cb[type])
13280                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13281
13282         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13283 }
13284
13285 void
13286 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13287 {
13288         mm_player_t *player  = (mm_player_t*)user_data;
13289         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13290         guint64 current_level_bytes = 0;
13291
13292         MMPLAYER_RETURN_IF_FAIL(player);
13293
13294         LOGI("app-src: video buffer is full.\n");
13295
13296         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13297
13298         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13299         if (player->media_stream_buffer_status_cb[type])
13300                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13301
13302         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13303 }
13304
13305 gboolean
13306 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13307 {
13308         mm_player_t *player  = (mm_player_t*)user_data;
13309         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13310
13311         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13312
13313         LOGD("app-src: seek audio data %llu\n", position);
13314         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13315
13316         if (player->media_stream_seek_data_cb[type])
13317                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13318         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13319
13320         return TRUE;
13321 }
13322
13323 gboolean
13324 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13325 {
13326         mm_player_t *player  = (mm_player_t*)user_data;
13327         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13328
13329         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13330
13331         LOGD("app-src: seek video data %llu\n", position);
13332         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13333         if (player->media_stream_seek_data_cb[type])
13334                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13335         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13336
13337         return TRUE;
13338 }
13339
13340 gboolean
13341 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13342 {
13343         mm_player_t *player  = (mm_player_t*)user_data;
13344         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13345
13346         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13347
13348         LOGD("app-src: seek subtitle data\n");
13349         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13350
13351         if (player->media_stream_seek_data_cb[type])
13352                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13353         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13354
13355         return TRUE;
13356 }
13357
13358 int
13359 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13360 {
13361         mm_player_t* player = (mm_player_t*) hplayer;
13362
13363         MMPLAYER_FENTER();
13364
13365         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13366
13367         player->pcm_samplerate = samplerate;
13368         player->pcm_channel = channel;
13369
13370         MMPLAYER_FLEAVE();
13371         return MM_ERROR_NONE;
13372 }
13373
13374 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13375 {
13376         mm_player_t* player = (mm_player_t*) hplayer;
13377
13378         MMPLAYER_FENTER();
13379
13380         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13381         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13382
13383         if (MMPLAYER_IS_STREAMING(player))
13384                 *timeout = player->ini.live_state_change_timeout;
13385         else
13386                 *timeout = player->ini.localplayback_state_change_timeout;
13387
13388         LOGD("timeout = %d\n", *timeout);
13389
13390         MMPLAYER_FLEAVE();
13391         return MM_ERROR_NONE;
13392 }
13393
13394 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13395 {
13396         mm_player_t* player = (mm_player_t*) hplayer;
13397
13398         MMPLAYER_FENTER();
13399
13400         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13401         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13402
13403         *num = player->video_num_buffers;
13404         *extra_num = player->video_extra_num_buffers;
13405
13406         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13407
13408         MMPLAYER_FLEAVE();
13409         return MM_ERROR_NONE;
13410 }
13411
13412 static void
13413 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13414 {
13415         int i = 0;
13416         MMPLAYER_FENTER();
13417         MMPLAYER_RETURN_IF_FAIL(player);
13418
13419         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13420
13421                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13422                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13423                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13424                         player->storage_info[i].id = -1;
13425                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13426
13427                         if (path_type != MMPLAYER_PATH_MAX)
13428                                 break;
13429                 }
13430         }
13431
13432         MMPLAYER_FLEAVE();
13433 }
13434
13435 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13436 {
13437         int ret = MM_ERROR_NONE;
13438         mm_player_t* player = (mm_player_t*)hplayer;
13439         MMMessageParamType msg_param = {0, };
13440
13441         MMPLAYER_FENTER();
13442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13443
13444         LOGW("state changed storage %d:%d", id, state);
13445
13446         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13447                 return MM_ERROR_NONE;
13448
13449         /* FIXME: text path should be handled seperately. */
13450         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13451                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13452                 LOGW("external storage is removed");
13453
13454                 if (player->msg_posted == FALSE) {
13455                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13456                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13457                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13458                         player->msg_posted = TRUE;
13459                 }
13460
13461                 /* unrealize the player */
13462                 ret = _mmplayer_unrealize(hplayer);
13463                 if (ret != MM_ERROR_NONE)
13464                         LOGE("failed to unrealize");
13465         }
13466
13467         MMPLAYER_FLEAVE();
13468         return ret;
13469 }
13470
13471 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13472 {
13473         int ret = MM_ERROR_NONE;
13474         mm_player_t* player = (mm_player_t*) hplayer;
13475         int idx = 0, total = 0;
13476         gchar *result = NULL, *tmp = NULL;
13477
13478         MMPLAYER_FENTER();
13479         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13480         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13481
13482         total = *num = g_list_length(player->adaptive_info.var_list);
13483         if (total <= 0) {
13484                 LOGW("There is no stream variant info.");
13485                 return ret;
13486         }
13487
13488         result = g_strdup("");
13489         for (idx = 0 ; idx < total ; idx++) {
13490                 VariantData *v_data = NULL;
13491                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13492
13493                 if (v_data) {
13494                         gchar data[64] = {0};
13495                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13496
13497                         tmp = g_strconcat(result, data, NULL);
13498                         g_free(result);
13499                         result = tmp;
13500                 } else {
13501                         LOGW("There is no variant data in %d", idx);
13502                         (*num)--;
13503                 }
13504         }
13505
13506         *var_info = (char *)result;
13507
13508         LOGD("variant info %d:%s", *num, *var_info);
13509         MMPLAYER_FLEAVE();
13510         return ret;
13511 }
13512
13513 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13514 {
13515         int ret = MM_ERROR_NONE;
13516         mm_player_t* player = (mm_player_t*) hplayer;
13517
13518         MMPLAYER_FENTER();
13519         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13520
13521         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13522
13523         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13524         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13525         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13526
13527         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13528                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13529                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13530                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13531
13532                 /* FIXME: seek to current position for applying new variant limitation */
13533         }
13534
13535         MMPLAYER_FLEAVE();
13536         return ret;
13537
13538 }
13539
13540 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13541 {
13542         int ret = MM_ERROR_NONE;
13543         mm_player_t* player = (mm_player_t*) hplayer;
13544
13545         MMPLAYER_FENTER();
13546         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13547         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13548
13549         *bandwidth = player->adaptive_info.limit.bandwidth;
13550         *width = player->adaptive_info.limit.width;
13551         *height = player->adaptive_info.limit.height;
13552
13553         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13554
13555         MMPLAYER_FLEAVE();
13556         return ret;
13557 }
13558
13559 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13560 {
13561         int ret = MM_ERROR_NONE;
13562         mm_player_t* player = (mm_player_t*) hplayer;
13563
13564         MMPLAYER_FENTER();
13565         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13566
13567         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13568                 LOGW("buffer_ms will not be applied.");
13569
13570
13571         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13572
13573         if (player->streamer == NULL) {
13574                 player->streamer = __mm_player_streaming_create();
13575                 __mm_player_streaming_initialize(player->streamer);
13576         }
13577
13578         if (buffer_ms >= 0)
13579                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13580
13581         if (rebuffer_ms >= 0)
13582                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13583
13584         MMPLAYER_FLEAVE();
13585         return ret;
13586
13587 }
13588
13589 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13590 {
13591         int ret = MM_ERROR_NONE;
13592         mm_player_t* player = (mm_player_t*) hplayer;
13593
13594         MMPLAYER_FENTER();
13595         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13596         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13597
13598         if (player->streamer == NULL) {
13599                 player->streamer = __mm_player_streaming_create();
13600                 __mm_player_streaming_initialize(player->streamer);
13601         }
13602
13603         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13604         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13605
13606         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13607
13608         MMPLAYER_FLEAVE();
13609         return ret;
13610 }
13611
13612 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13613 {
13614 #define IDX_FIRST_SW_CODEC 0
13615         mm_player_t* player = (mm_player_t*) hplayer;
13616         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13617         MMHandleType attrs = 0;
13618
13619         MMPLAYER_FENTER();
13620         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13621
13622         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13623                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13624                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13625
13626         switch (stream_type) {
13627         case MM_PLAYER_STREAM_TYPE_AUDIO:
13628                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13629                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13630                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13631                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13632                         LOGE("There is no a codec for codec_type %d", codec_type);
13633                         return MM_ERROR_PLAYER_NO_OP;
13634                 }
13635         break;
13636         case MM_PLAYER_STREAM_TYPE_VIDEO:
13637                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13638                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13639                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13640                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13641                         LOGE("There is no v codec for codec_type %d", codec_type);
13642                         return MM_ERROR_PLAYER_NO_OP;
13643                 }
13644
13645         break;
13646         default:
13647                 LOGE("Invalid stream type %d", stream_type);
13648                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13649         break;
13650         }
13651
13652         LOGD("update %s codec_type to %d", attr_name, codec_type);
13653
13654         attrs = MMPLAYER_GET_ATTRS(player);
13655         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13656
13657         if (mmf_attrs_commit(player->attrs)) {
13658                 LOGE("failed to commit codec_type attributes");
13659                 return MM_ERROR_PLAYER_INTERNAL;
13660         }
13661
13662         MMPLAYER_FLEAVE();
13663         return MM_ERROR_NONE;
13664 }
13665
13666 int
13667 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13668 {
13669         mm_player_t* player = (mm_player_t*) hplayer;
13670         GstElement* rg_vol_element = NULL;
13671
13672         MMPLAYER_FENTER();
13673
13674         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13675
13676         player->sound.rg_enable = enabled;
13677
13678         /* just hold rgvolume enable value if pipeline is not ready */
13679         if (!player->pipeline || !player->pipeline->audiobin) {
13680                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13681                 return MM_ERROR_NONE;
13682         }
13683
13684         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13685
13686         if (!rg_vol_element) {
13687                 LOGD("rgvolume element is not created");
13688                 return MM_ERROR_PLAYER_INTERNAL;
13689         }
13690
13691         if (enabled)
13692                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13693         else
13694                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13695
13696         MMPLAYER_FLEAVE();
13697
13698         return MM_ERROR_NONE;
13699 }
13700
13701 int
13702 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13703 {
13704         mm_player_t* player = (mm_player_t*) hplayer;
13705         GstElement* rg_vol_element = NULL;
13706         gboolean enable = FALSE;
13707
13708         MMPLAYER_FENTER();
13709
13710         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13711         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13712
13713         /* just hold enable_rg value if pipeline is not ready */
13714         if (!player->pipeline || !player->pipeline->audiobin) {
13715                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13716                 *enabled = player->sound.rg_enable;
13717                 return MM_ERROR_NONE;
13718         }
13719
13720         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13721
13722         if (!rg_vol_element) {
13723                 LOGD("rgvolume element is not created");
13724                 return MM_ERROR_PLAYER_INTERNAL;
13725         }
13726
13727         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13728         *enabled = enable;
13729
13730         MMPLAYER_FLEAVE();
13731
13732         return MM_ERROR_NONE;
13733 }