[0.6.111] sync the video360 default value with plugin
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
58 |                                                                                                                                                                                       |
59 ========================================================================================== */
60
61 /*---------------------------------------------------------------------------
62 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
63 ---------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------
66 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
67 ---------------------------------------------------------------------------*/
68
69 /*---------------------------------------------------------------------------
70 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
71 ---------------------------------------------------------------------------*/
72
73 /*---------------------------------------------------------------------------
74 |    LOCAL #defines:                                                                                                            |
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
78
79 #define MM_VOLUME_FACTOR_DEFAULT                1.0
80 #define MM_VOLUME_FACTOR_MIN                    0
81 #define MM_VOLUME_FACTOR_MAX                    1.0
82
83 /* Don't need to sleep for sound fadeout
84  * fadeout related fucntion will be deleted(Deprecated)
85  */
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
87
88 #define DEFAULT_PLAYBACK_RATE                   1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
90
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93         (player->ini.http_use_file_buffer) && \
94         (player->http_file_buffering_path) && \
95         (strlen(player->http_file_buffering_path) > 0))
96
97 #define PLAYER_DISPLAY_MODE_DST_ROI             5
98
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
100
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
103
104 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
108
109 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
139
140 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
146 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157
158 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
159 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
175
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
189
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
193
194 static int              __gst_realize(mm_player_t* player);
195 static int              __gst_unrealize(mm_player_t* player);
196 static int              __gst_start(mm_player_t* player);
197 static int              __gst_stop(mm_player_t* player);
198 static int              __gst_pause(mm_player_t* player, gboolean async);
199 static int              __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202                                         gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
204
205 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
206 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
207 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
210
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
212
213 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
214 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
215
216 /* util */
217 static gboolean __is_ms_buff_src(mm_player_t* player);
218 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
219
220 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
221 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
222 static int __mmplayer_start_streaming_ext(mm_player_t *player);
223 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
224 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
225
226 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
227 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
228 static void __mmplayer_check_pipeline(mm_player_t* player);
229 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
230 static void __mmplayer_deactivate_old_path(mm_player_t *player);
231
232 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
233 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
234
235 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
236 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
237 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
238 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
239 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
240 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
241 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
242 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
246 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
247 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
248 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
249 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
250 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
251
252 /*===========================================================================================
253 |                                                                                                                                                                                       |
254 |  FUNCTION DEFINITIONS                                                                                                                                         |
255 |                                                                                                                                                                                       |
256 ========================================================================================== */
257
258 #if 0 //debug
259 static void
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
261 {
262         gint i, count;
263
264         count = gst_tag_list_get_tag_size(list, tag);
265
266         LOGD("count = %d", count);
267
268         for (i = 0; i < count; i++) {
269                 gchar *str;
270
271                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
273                                 g_assert_not_reached();
274                 } else
275                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
276
277                 if (i == 0)
278                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
279                 else
280                         g_print("                 : %s\n", str);
281
282                 g_free(str);
283         }
284 }
285 #endif
286
287 /* This function should be called after the pipeline goes PAUSED or higher
288 state. */
289 gboolean
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
291 {
292         static gboolean has_duration = FALSE;
293         static gboolean has_video_attrs = FALSE;
294         static gboolean has_audio_attrs = FALSE;
295         static gboolean has_bitrate = FALSE;
296         gboolean missing_only = FALSE;
297         gboolean all = FALSE;
298         gint64 dur_nsec = 0;
299         GstStructure* p = NULL;
300         MMHandleType attrs = 0;
301         gchar *path = NULL;
302         struct stat sb;
303
304         MMPLAYER_FENTER();
305
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
307
308         /* check player state here */
309         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311                 /* give warning now only */
312                 LOGW("be careful. content attributes may not available in this state ");
313         }
314
315         /* get content attribute first */
316         attrs = MMPLAYER_GET_ATTRS(player);
317         if (!attrs) {
318                 LOGE("cannot get content attribute");
319                 return FALSE;
320         }
321
322         /* get update flag */
323
324         if (flag & ATTR_MISSING_ONLY) {
325                 missing_only = TRUE;
326                 LOGD("updating missed attr only");
327         }
328
329         if (flag & ATTR_ALL) {
330                 all = TRUE;
331                 has_duration = FALSE;
332                 has_video_attrs = FALSE;
333                 has_audio_attrs = FALSE;
334                 has_bitrate = FALSE;
335
336                 LOGD("updating all attrs");
337         }
338
339         if (missing_only && all) {
340                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341                 missing_only = FALSE;
342         }
343
344         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
345                 LOGD("try to update duration");
346                 has_duration = FALSE;
347
348                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
349                         player->duration = dur_nsec;
350                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
351                 }
352
353                 if (player->duration < 0) {
354                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
355                         player->duration = 0;
356                 }
357
358                 /* update streaming service type */
359                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
360
361                 /* check duration is OK */
362                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
363                         /* FIXIT : find another way to get duration here. */
364                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
365                 } else {
366                         /*update duration */
367                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
368                         has_duration = TRUE;
369                 }
370         }
371
372         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
373                 /* update audio params
374                 NOTE : We need original audio params and it can be only obtained from src pad of audio
375                 decoder. Below code only valid when we are not using 'resampler' just before
376                 'audioconverter'. */
377
378                 LOGD("try to update audio attrs");
379                 has_audio_attrs = FALSE;
380
381                 if (player->pipeline->audiobin &&
382                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
383                         GstCaps *caps_a = NULL;
384                         GstPad* pad = NULL;
385                         gint samplerate = 0, channels = 0;
386
387                         pad = gst_element_get_static_pad(
388                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
389
390                         if (pad) {
391                                 caps_a = gst_pad_get_current_caps(pad);
392
393                                 if (caps_a) {
394                                         p = gst_caps_get_structure(caps_a, 0);
395
396                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
397
398                                         gst_structure_get_int(p, "rate", &samplerate);
399                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
400
401                                         gst_structure_get_int(p, "channels", &channels);
402                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
403
404                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
405
406                                         gst_caps_unref(caps_a);
407                                         caps_a = NULL;
408
409                                         has_audio_attrs = TRUE;
410                                 } else
411                                         LOGW("not ready to get audio caps");
412
413                                 gst_object_unref(pad);
414                         } else
415                                 LOGW("failed to get pad from audiosink");
416                 }
417         }
418
419         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
420                 LOGD("try to update video attrs");
421                 has_video_attrs = FALSE;
422
423                 if (player->pipeline->videobin &&
424                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
425                         GstCaps *caps_v = NULL;
426                         GstPad* pad = NULL;
427                         gint tmpNu, tmpDe;
428                         gint width, height;
429
430                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
431                         if (pad) {
432                                 caps_v = gst_pad_get_current_caps(pad);
433
434                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
435                                 if (!caps_v && player->v_stream_caps) {
436                                         caps_v = player->v_stream_caps;
437                                         gst_caps_ref(caps_v);
438                                 }
439
440                                 if (caps_v) {
441                                         p = gst_caps_get_structure(caps_v, 0);
442                                         gst_structure_get_int(p, "width", &width);
443                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
444
445                                         gst_structure_get_int(p, "height", &height);
446                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
447
448                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
449
450                                         SECURE_LOGD("width : %d     height : %d", width, height);
451
452                                         gst_caps_unref(caps_v);
453                                         caps_v = NULL;
454
455                                         if (tmpDe > 0) {
456                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
457                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
458                                         }
459
460                                         has_video_attrs = TRUE;
461                                 } else
462                                         LOGD("no negitiated caps from videosink");
463                                 gst_object_unref(pad);
464                                 pad = NULL;
465                         } else
466                                 LOGD("no videosink sink pad");
467                 }
468         }
469
470
471         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
472                 has_bitrate = FALSE;
473
474                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
475                 if (player->duration) {
476                         guint64 data_size = 0;
477
478                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
479                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
480
481                                 if (stat(path, &sb) == 0)
482                                         data_size = (guint64)sb.st_size;
483                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
484                                 data_size = player->http_content_size;
485                         }
486                         LOGD("try to update bitrate : data_size = %lld", data_size);
487
488                         if (data_size) {
489                                 guint64 bitrate = 0;
490                                 guint64 msec_dur = 0;
491
492                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
493                                 if (msec_dur > 0) {
494                                         bitrate = data_size * 8 * 1000 / msec_dur;
495                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
496                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
497
498                                         has_bitrate = TRUE;
499                                 } else {
500                                         LOGD("player duration is less than 0");
501                                 }
502                         }
503
504                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
505                                 if (player->total_bitrate) {
506                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
507                                         has_bitrate = TRUE;
508                                 }
509                         }
510                 }
511         }
512
513         /* validate all */
514         if (mmf_attrs_commit(attrs)) {
515                 LOGE("failed to update attributes\n");
516                 return FALSE;
517         }
518
519         MMPLAYER_FLEAVE();
520
521         return TRUE;
522 }
523
524 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
525 {
526         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
527
528         MMPLAYER_FENTER();
529
530         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
531                         player->pipeline &&
532                         player->pipeline->mainbin &&
533                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
534                         STREAMING_SERVICE_NONE);
535
536         /* streaming service type if streaming */
537         if (!MMPLAYER_IS_STREAMING(player))
538                 return STREAMING_SERVICE_NONE;
539
540         if (MMPLAYER_IS_HTTP_STREAMING(player))
541                 streaming_type = (player->duration == 0) ?
542                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
543
544         switch (streaming_type) {
545         case STREAMING_SERVICE_LIVE:
546                 LOGD("it's live streaming");
547                 break;
548         case STREAMING_SERVICE_VOD:
549                 LOGD("it's vod streaming");
550                 break;
551         default:
552                 LOGE("should not get here");
553                 break;
554         }
555
556         MMPLAYER_FLEAVE();
557
558         return streaming_type;
559 }
560
561
562 /* this function sets the player state and also report
563  * it to applicaton by calling callback function
564  */
565 int
566 __mmplayer_set_state(mm_player_t* player, int state)
567 {
568         MMMessageParamType msg = {0, };
569         gboolean post_bos = FALSE;
570
571         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
572
573         if (MMPLAYER_CURRENT_STATE(player) == state) {
574                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
575                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
576                 return MM_ERROR_NONE;
577         }
578
579         /* update player states */
580         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
581         MMPLAYER_CURRENT_STATE(player) = state;
582
583         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
584                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
585
586         /* print state */
587         MMPLAYER_PRINT_STATE(player);
588
589         switch (MMPLAYER_CURRENT_STATE(player)) {
590         case MM_PLAYER_STATE_NULL:
591         case MM_PLAYER_STATE_READY:
592                 break;
593
594         case MM_PLAYER_STATE_PAUSED:
595                 {
596                         if (!player->sent_bos) {
597                                 /* rtsp case, get content attrs by GstMessage */
598                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
599                                         /* it's first time to update all content attrs. */
600                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
601                                 }
602                         }
603
604                         /* add audio callback probe if condition is satisfied */
605                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
606                                 __mmplayer_configure_audio_callback(player);
607
608                         /* FIXIT : handle return value */
609                 }
610                 break;
611
612         case MM_PLAYER_STATE_PLAYING:
613                 {
614                         /* try to get content metadata */
615                         if (!player->sent_bos) {
616                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
617                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
618                                  * legacy mmfw-player api */
619                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
620                         }
621
622                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
623                                 if (!player->sent_bos)
624                                         __mmplayer_handle_missed_plugin(player);
625                         }
626
627                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
628                                 /* initialize because auto resume is done well. */
629                                 player->resumed_by_rewind = FALSE;
630                                 player->playback_rate = 1.0;
631                         }
632
633                         if (!player->sent_bos) {
634                                 /* check audio codec field is set or not
635                                  * we can get it from typefinder or codec's caps.
636                                  */
637                                 gchar *audio_codec = NULL;
638                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
639
640                                 /* The codec format can't be sent for audio only case like amr, mid etc.
641                                  * Because, parser don't make related TAG.
642                                  * So, if it's not set yet, fill it with found data.
643                                  */
644                                 if (!audio_codec) {
645                                         if (g_strrstr(player->type, "audio/midi"))
646                                                 audio_codec = g_strdup("MIDI");
647                                         else if (g_strrstr(player->type, "audio/x-amr"))
648                                                 audio_codec = g_strdup("AMR");
649                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
650                                                 audio_codec = g_strdup("AAC");
651                                         else
652                                                 audio_codec = g_strdup("unknown");
653                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
654
655                                         MMPLAYER_FREEIF(audio_codec);
656                                         if (mmf_attrs_commit(player->attrs))
657                                                 LOGE("failed to update attributes\n");
658
659                                         LOGD("set audio codec type with caps\n");
660                                 }
661
662                                 post_bos = TRUE;
663                         }
664                 }
665                 break;
666
667         case MM_PLAYER_STATE_NONE:
668         default:
669                 LOGW("invalid target state, there is nothing to do.\n");
670                 break;
671         }
672
673
674         /* post message to application */
675         if (MMPLAYER_TARGET_STATE(player) == state) {
676                 /* fill the message with state of player */
677                 msg.union_type = MM_MSG_UNION_STATE;
678                 msg.state.previous = MMPLAYER_PREV_STATE(player);
679                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
680
681                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
682
683                 /* state changed by resource callback */
684                 if (player->interrupted_by_resource) {
685                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
686                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
687                 } else { /* state changed by usecase */
688                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
689                 }
690         } else {
691                 LOGD("intermediate state, do nothing.\n");
692                 MMPLAYER_PRINT_STATE(player);
693                 return MM_ERROR_NONE;
694         }
695
696         if (post_bos) {
697                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
698                 player->sent_bos = TRUE;
699         }
700
701         return MM_ERROR_NONE;
702 }
703
704 static gpointer __mmplayer_next_play_thread(gpointer data)
705 {
706         mm_player_t* player = (mm_player_t*) data;
707         MMPlayerGstElement *mainbin = NULL;
708
709         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
710
711         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
712         while (!player->next_play_thread_exit) {
713                 LOGD("next play thread started. waiting for signal.\n");
714                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
715
716                 LOGD("reconfigure pipeline for gapless play.\n");
717
718                 if (player->next_play_thread_exit) {
719                         if (player->gapless.reconfigure) {
720                                 player->gapless.reconfigure = false;
721                                 MMPLAYER_PLAYBACK_UNLOCK(player);
722                         }
723                         LOGD("exiting gapless play thread\n");
724                         break;
725                 }
726
727                 mainbin = player->pipeline->mainbin;
728
729                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
730                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
731                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
732                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
733                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
734
735                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
736         }
737         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
738
739         return NULL;
740 }
741
742 static void
743 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
744 {
745         MMHandleType attrs = 0;
746         guint64 data_size = 0;
747         gchar* path = NULL;
748         unsigned long pos_msec = 0;
749         struct stat sb;
750
751         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
752
753         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
754
755         attrs = MMPLAYER_GET_ATTRS(player);
756         if (!attrs) {
757                 LOGE("fail to get attributes.\n");
758                 return;
759         }
760
761         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
762                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
763
764                 if (stat(path, &sb) == 0)
765                         data_size = (guint64)sb.st_size;
766         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
767                 data_size = player->http_content_size;
768
769         __mm_player_streaming_buffering(player->streamer,
770                                                                                 buffering_msg,
771                                                                                 data_size,
772                                                                                 player->last_position,
773                                                                                 player->duration);
774
775         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
776
777         return;
778 }
779
780 static int
781 __mmplayer_handle_buffering_message(mm_player_t* player)
782 {
783         int ret = MM_ERROR_NONE;
784         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
785         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
786         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
787         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
788
789         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
790                 LOGW("do nothing for buffering msg\n");
791                 ret = MM_ERROR_PLAYER_INVALID_STATE;
792                 goto exit;
793         }
794
795         prev_state = MMPLAYER_PREV_STATE(player);
796         current_state = MMPLAYER_CURRENT_STATE(player);
797         target_state = MMPLAYER_TARGET_STATE(player);
798         pending_state = MMPLAYER_PENDING_STATE(player);
799
800         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
801                 MMPLAYER_STATE_GET_NAME(prev_state),
802                 MMPLAYER_STATE_GET_NAME(current_state),
803                 MMPLAYER_STATE_GET_NAME(pending_state),
804                 MMPLAYER_STATE_GET_NAME(target_state),
805                 player->streamer->is_buffering);
806
807         if (!player->streamer->is_buffering) {
808                 /* NOTE : if buffering has done, player has to go to target state. */
809                 switch (target_state) {
810                 case MM_PLAYER_STATE_PAUSED:
811                         {
812                                 switch (pending_state) {
813                                 case MM_PLAYER_STATE_PLAYING:
814                                         __gst_pause(player, TRUE);
815                                         break;
816
817                                 case MM_PLAYER_STATE_PAUSED:
818                                         LOGD("player is already going to paused state, there is nothing to do.\n");
819                                         break;
820
821                                 case MM_PLAYER_STATE_NONE:
822                                 case MM_PLAYER_STATE_NULL:
823                                 case MM_PLAYER_STATE_READY:
824                                 default:
825                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
826                                         break;
827                                 }
828                         }
829                         break;
830
831                 case MM_PLAYER_STATE_PLAYING:
832                         {
833                                 switch (pending_state) {
834                                 case MM_PLAYER_STATE_NONE:
835                                         {
836                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
837                                                         __gst_resume(player, TRUE);
838                                         }
839                                         break;
840
841                                 case MM_PLAYER_STATE_PAUSED:
842                                         /* NOTE: It should be worked as asynchronously.
843                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
844                                          */
845                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
846                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
847                                                  * The current state should be changed to paused purposely to prevent state conflict.
848                                                  */
849                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
850                                         }
851                                         __gst_resume(player, TRUE);
852                                         break;
853
854                                 case MM_PLAYER_STATE_PLAYING:
855                                         LOGD("player is already going to playing state, there is nothing to do.\n");
856                                         break;
857
858                                 case MM_PLAYER_STATE_NULL:
859                                 case MM_PLAYER_STATE_READY:
860                                 default:
861                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
862                                         break;
863                                 }
864                         }
865                         break;
866
867                 case MM_PLAYER_STATE_NULL:
868                 case MM_PLAYER_STATE_READY:
869                 case MM_PLAYER_STATE_NONE:
870                 default:
871                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
872                         break;
873                 }
874         } else {
875                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
876                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
877                  */
878                 switch (pending_state) {
879                 case MM_PLAYER_STATE_NONE:
880                         {
881                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
882                                         /* rtsp streaming pause makes rtsp server stop sending data. */
883                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
884                                                 LOGD("set pause state during buffering\n");
885                                                 __gst_pause(player, TRUE);
886                                         }
887                                 }
888                         }
889                         break;
890
891                 case MM_PLAYER_STATE_PLAYING:
892                         /* rtsp streaming pause makes rtsp server stop sending data. */
893                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
894                                 __gst_pause(player, TRUE);
895                         break;
896
897                 case MM_PLAYER_STATE_PAUSED:
898                         break;
899
900                 case MM_PLAYER_STATE_NULL:
901                 case MM_PLAYER_STATE_READY:
902                 default:
903                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
904                         break;
905                 }
906         }
907
908 exit:
909         return ret;
910 }
911
912 static void
913 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
914 {
915         MMPlayerGstElement *textbin;
916         MMPLAYER_FENTER();
917
918         MMPLAYER_RETURN_IF_FAIL(player &&
919                                         player->pipeline &&
920                                         player->pipeline->textbin);
921
922         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
923
924         textbin = player->pipeline->textbin;
925
926         if (is_drop) {
927                 LOGD("Drop subtitle text after getting EOS\n");
928
929                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
930                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
931
932                 player->is_subtitle_force_drop = TRUE;
933         } else {
934                 if (player->is_subtitle_force_drop == TRUE) {
935                         LOGD("Enable subtitle data path without drop\n");
936
937                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
938                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
939
940                         LOGD("non-connected with external display");
941
942                         player->is_subtitle_force_drop = FALSE;
943                 }
944         }
945 }
946
947 static VariantData *
948 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
949 {
950         VariantData *var_info = NULL;
951         g_return_val_if_fail(self != NULL, NULL);
952
953         var_info = g_new0(VariantData, 1);
954         if (!var_info) return NULL;
955         var_info->bandwidth = self->bandwidth;
956         var_info->width = self->width;
957         var_info->height = self->height;
958         return var_info;
959 }
960
961 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
962 {
963         mm_player_t* player = (mm_player_t*)hplayer;
964
965         MMPLAYER_FENTER();
966         MMPLAYER_RETURN_IF_FAIL(player);
967
968         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
969
970         /* destroy the gst bus msg thread */
971         if (player->bus_msg_thread) {
972                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
973                 player->bus_msg_thread_exit = TRUE;
974                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
975                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
976
977                 LOGD("gst bus msg thread exit.");
978                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
979                 player->bus_msg_thread = NULL;
980
981                 g_mutex_clear(&player->bus_msg_thread_mutex);
982                 g_cond_clear(&player->bus_msg_thread_cond);
983         }
984
985         MMPLAYER_FLEAVE();
986 }
987
988 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
989 {
990         mm_player_t *player = (mm_player_t*)(data);
991         GstMessage *msg = NULL;
992         GstBus *bus = NULL;
993
994         MMPLAYER_FENTER();
995         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
996                                                 player->pipeline &&
997                                                 player->pipeline->mainbin &&
998                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
999                                                 NULL);
1000
1001         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1002         if (!bus) {
1003                 LOGE("cannot get BUS from the pipeline");
1004                 return NULL;
1005         }
1006
1007         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1008
1009         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1010         while (!player->bus_msg_thread_exit) {
1011                 msg = gst_bus_pop(bus);
1012                 if (msg == NULL) {
1013                         int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1014                         MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1015                         continue;
1016                 }
1017
1018                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1019                 /* handle the gst msg */
1020                 __mmplayer_gst_callback(msg, player);
1021                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1022                 gst_message_unref(msg);
1023         }
1024
1025         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1026         gst_object_unref(GST_OBJECT(bus));
1027
1028         MMPLAYER_FLEAVE();
1029         return NULL;
1030 }
1031
1032 static void
1033 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1034 {
1035         mm_player_t* player = (mm_player_t*)(data);
1036         static gboolean async_done = FALSE;
1037
1038         MMPLAYER_RETURN_IF_FAIL(player);
1039         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1040
1041         switch (GST_MESSAGE_TYPE(msg)) {
1042         case GST_MESSAGE_UNKNOWN:
1043                 LOGD("unknown message received\n");
1044                 break;
1045
1046         case GST_MESSAGE_EOS:
1047                 {
1048                         MMHandleType attrs = 0;
1049                         gint count = 0;
1050
1051                         LOGD("GST_MESSAGE_EOS received\n");
1052
1053                         /* NOTE : EOS event is comming multiple time. watch out it */
1054                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1055                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1056                                 LOGD("EOS received on non-playing state. ignoring it\n");
1057                                 break;
1058                         }
1059
1060                         if (player->pipeline) {
1061                                 if (player->pipeline->textbin)
1062                                         __mmplayer_drop_subtitle(player, TRUE);
1063
1064                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1065                                         GstPad *pad = NULL;
1066
1067                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1068
1069                                         LOGD("release audio callback\n");
1070
1071                                         /* release audio callback */
1072                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1073                                         player->audio_cb_probe_id = 0;
1074                                         /* audio callback should be free because it can be called even though probe remove.*/
1075                                         player->audio_stream_cb = NULL;
1076                                         player->audio_stream_cb_user_param = NULL;
1077
1078                                 }
1079                         }
1080                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1081                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1082
1083                         /* rewind if repeat count is greater then zero */
1084                         /* get play count */
1085                         attrs = MMPLAYER_GET_ATTRS(player);
1086
1087                         if (attrs) {
1088                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1089
1090                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1091
1092                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1093                                         if (player->playback_rate < 0.0) {
1094                                                 player->resumed_by_rewind = TRUE;
1095                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1096                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1097                                         }
1098
1099                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1100
1101                                         /* initialize */
1102                                         player->sent_bos = FALSE;
1103
1104                                         /* not posting eos when repeating */
1105                                         break;
1106                                 }
1107                         }
1108
1109                         if (player->pipeline)
1110                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1111
1112                         /* post eos message to application */
1113                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1114
1115                         /* reset last position */
1116                         player->last_position = 0;
1117                 }
1118                 break;
1119
1120         case GST_MESSAGE_ERROR:
1121                 {
1122                         GError *error = NULL;
1123                         gchar* debug = NULL;
1124
1125                         /* generating debug info before returning error */
1126                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1127
1128                         /* get error code */
1129                         gst_message_parse_error(msg, &error, &debug);
1130
1131                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1132                                 /* Note : the streaming error from the streaming source is handled
1133                                  *   using __mmplayer_handle_streaming_error.
1134                                  */
1135                                 __mmplayer_handle_streaming_error(player, msg);
1136
1137                                 /* dump state of all element */
1138                                 __mmplayer_dump_pipeline_state(player);
1139                         } else {
1140                                 /* traslate gst error code to msl error code. then post it
1141                                  * to application if needed
1142                                  */
1143                                 __mmplayer_handle_gst_error(player, msg, error);
1144
1145                                 if (debug)
1146                                         LOGE("error debug : %s", debug);
1147                         }
1148
1149                         if (MMPLAYER_IS_HTTP_PD(player))
1150                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1151
1152                         MMPLAYER_FREEIF(debug);
1153                         g_error_free(error);
1154                 }
1155                 break;
1156
1157         case GST_MESSAGE_WARNING:
1158                 {
1159                         char* debug = NULL;
1160                         GError* error = NULL;
1161
1162                         gst_message_parse_warning(msg, &error, &debug);
1163
1164                         LOGD("warning : %s\n", error->message);
1165                         LOGD("debug : %s\n", debug);
1166
1167                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1168
1169                         MMPLAYER_FREEIF(debug);
1170                         g_error_free(error);
1171                 }
1172                 break;
1173
1174         case GST_MESSAGE_TAG:
1175                 {
1176                         LOGD("GST_MESSAGE_TAG\n");
1177                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1178                                 LOGW("failed to extract tags from gstmessage\n");
1179                 }
1180                 break;
1181
1182         case GST_MESSAGE_BUFFERING:
1183                 {
1184                         MMMessageParamType msg_param = {0, };
1185                         int bRet = MM_ERROR_NONE;
1186
1187                         if (!(player->pipeline && player->pipeline->mainbin)) {
1188                                 LOGE("player pipeline handle is null");
1189                                 break;
1190                         }
1191
1192                         if (!MMPLAYER_IS_STREAMING(player))
1193                                 break;
1194
1195                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1196                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1197                                         /* skip the playback control by buffering msg while user request is handled. */
1198                                         gint per = 0;
1199
1200                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1201
1202                                         gst_message_parse_buffering(msg, &per);
1203                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1204
1205                                         msg_param.connection.buffering = per;
1206                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1207                                         break;
1208                                 }
1209                         } else {
1210                                 MMPLAYER_CMD_LOCK(player);
1211                         }
1212
1213                         /* ignore the prev buffering message */
1214                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1215                                 && (player->streamer->is_buffering_done == TRUE)) {
1216                                 gint buffer_percent = 0;
1217
1218                                 gst_message_parse_buffering(msg, &buffer_percent);
1219
1220                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1221                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1222                                         player->streamer->is_buffering_done = FALSE;
1223                                 }
1224                                 MMPLAYER_CMD_UNLOCK(player);
1225                                 break;
1226                         }
1227
1228                         __mmplayer_update_buffer_setting(player, msg);
1229
1230                         bRet = __mmplayer_handle_buffering_message(player);
1231
1232                         if (bRet == MM_ERROR_NONE) {
1233                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1234                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1235
1236                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1237                                         player->pending_resume &&
1238                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1239
1240                                         player->is_external_subtitle_added_now = FALSE;
1241                                         player->pending_resume = FALSE;
1242                                         _mmplayer_resume((MMHandleType)player);
1243                                 }
1244
1245                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1246                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1247
1248                                         if (player->doing_seek) {
1249                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1250                                                         player->doing_seek = FALSE;
1251                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1252                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1253                                                         async_done = TRUE;
1254                                                 }
1255                                         }
1256                                 }
1257                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1258                                 if (!player->streamer) {
1259                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1260                                         MMPLAYER_CMD_UNLOCK(player);
1261                                         break;
1262                                 }
1263
1264                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1265
1266                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1267                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1268
1269                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1270                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1271                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1272                                         } else {
1273                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1274                                         }
1275                                 } else {
1276                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1277                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1278                                 }
1279                         }
1280                         MMPLAYER_CMD_UNLOCK(player);
1281                 }
1282                 break;
1283
1284         case GST_MESSAGE_STATE_CHANGED:
1285                 {
1286                         MMPlayerGstElement *mainbin;
1287                         const GValue *voldstate, *vnewstate, *vpending;
1288                         GstState oldstate = GST_STATE_NULL;
1289                         GstState newstate = GST_STATE_NULL;
1290                         GstState pending = GST_STATE_NULL;
1291
1292                         if (!(player->pipeline && player->pipeline->mainbin)) {
1293                                 LOGE("player pipeline handle is null");
1294                                 break;
1295                         }
1296
1297                         mainbin = player->pipeline->mainbin;
1298
1299                         /* we only handle messages from pipeline */
1300                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1301                                 break;
1302
1303                         /* get state info from msg */
1304                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1305                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1306                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1307
1308                         if (!voldstate || !vnewstate) {
1309                                 LOGE("received msg has wrong format.");
1310                                 break;
1311                         }
1312
1313                         oldstate = (GstState)voldstate->data[0].v_int;
1314                         newstate = (GstState)vnewstate->data[0].v_int;
1315                         if (vpending)
1316                                 pending = (GstState)vpending->data[0].v_int;
1317
1318                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1319                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1320                                 gst_element_state_get_name((GstState)oldstate),
1321                                 gst_element_state_get_name((GstState)newstate),
1322                                 gst_element_state_get_name((GstState)pending));
1323
1324                         if (newstate == GST_STATE_PLAYING) {
1325                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1326
1327                                         int retVal = MM_ERROR_NONE;
1328                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1329
1330                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1331
1332                                         if (MM_ERROR_NONE != retVal)
1333                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1334
1335                                         player->pending_seek.is_pending = FALSE;
1336                                 }
1337                         }
1338
1339                         if (oldstate == newstate) {
1340                                 LOGD("pipeline reports state transition to old state");
1341                                 break;
1342                         }
1343
1344                         switch (newstate) {
1345                         case GST_STATE_VOID_PENDING:
1346                                 break;
1347
1348                         case GST_STATE_NULL:
1349                                 break;
1350
1351                         case GST_STATE_READY:
1352                                 break;
1353
1354                         case GST_STATE_PAUSED:
1355                                 {
1356                                         gboolean prepare_async = FALSE;
1357                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1358
1359                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1360                                                 __mmplayer_configure_audio_callback(player);
1361
1362                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1363                                                 // managed prepare async case
1364                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1365                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1366                                         }
1367
1368                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1369                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1370
1371                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1372                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1373                                                                 player->total_maximum_bitrate, player->total_bitrate);
1374
1375                                                 if (player->pending_seek.is_pending) {
1376                                                         LOGW("trying to do pending seek");
1377                                                         MMPLAYER_CMD_LOCK(player);
1378                                                         __gst_pending_seek(player);
1379                                                         MMPLAYER_CMD_UNLOCK(player);
1380                                                 }
1381                                         }
1382                                 }
1383                                 break;
1384
1385                         case GST_STATE_PLAYING:
1386                                 {
1387                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1388
1389                                         if (MMPLAYER_IS_STREAMING(player)) {
1390                                                 // managed prepare async case when buffering is completed
1391                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1392                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1393                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1394                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1395
1396                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1397
1398                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1399                                                         if (player->streamer->buffering_percent < 100) {
1400
1401                                                                 MMMessageParamType msg_param = {0, };
1402                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1403
1404                                                                 msg_param.connection.buffering = 100;
1405                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1406                                                         }
1407                                                 }
1408                                         }
1409
1410                                         if (player->gapless.stream_changed) {
1411                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1412                                                 player->gapless.stream_changed = FALSE;
1413                                         }
1414
1415                                         if (player->doing_seek && async_done) {
1416                                                 player->doing_seek = FALSE;
1417                                                 async_done = FALSE;
1418                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1419                                         }
1420                                 }
1421                                 break;
1422
1423                         default:
1424                                 break;
1425                         }
1426                 }
1427                 break;
1428
1429         case GST_MESSAGE_CLOCK_LOST:
1430                         {
1431                                 GstClock *clock = NULL;
1432                                 gboolean need_new_clock = FALSE;
1433
1434                                 gst_message_parse_clock_lost(msg, &clock);
1435                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1436
1437                                 if (!player->videodec_linked)
1438                                         need_new_clock = TRUE;
1439                                 else if (!player->ini.use_system_clock)
1440                                         need_new_clock = TRUE;
1441
1442                                 if (need_new_clock) {
1443                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1444                                         __gst_pause(player, FALSE);
1445                                         __gst_resume(player, FALSE);
1446                                 }
1447                         }
1448                         break;
1449
1450         case GST_MESSAGE_NEW_CLOCK:
1451                         {
1452                                 GstClock *clock = NULL;
1453                                 gst_message_parse_new_clock(msg, &clock);
1454                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1455                         }
1456                         break;
1457
1458         case GST_MESSAGE_ELEMENT:
1459                         {
1460                                 const gchar *structure_name;
1461                                 gint count = 0, idx = 0;
1462                                 MMHandleType attrs = 0;
1463
1464                                 attrs = MMPLAYER_GET_ATTRS(player);
1465                                 if (!attrs) {
1466                                         LOGE("cannot get content attribute");
1467                                         break;
1468                                 }
1469
1470                                 if (gst_message_get_structure(msg) == NULL)
1471                                         break;
1472
1473                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1474                                 if (!structure_name)
1475                                         break;
1476
1477                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1478
1479                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1480                                         const GValue *var_info = NULL;
1481
1482                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1483                                         if (var_info != NULL) {
1484                                                 if (player->adaptive_info.var_list)
1485                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1486
1487                                                 /* share addr or copy the list */
1488                                                 player->adaptive_info.var_list =
1489                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1490
1491                                                 count = g_list_length(player->adaptive_info.var_list);
1492                                                 if (count > 0) {
1493                                                         VariantData *temp = NULL;
1494
1495                                                         /* print out for debug */
1496                                                         LOGD("num of variant_info %d", count);
1497                                                         for (idx = 0; idx < count; idx++) {
1498                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1499                                                                 if (temp)
1500                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1501                                                         }
1502                                                 }
1503                                         }
1504                                 }
1505
1506                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1507                                         gint num_buffers = 0;
1508                                         gint extra_num_buffers = 0;
1509
1510                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1511                                                 player->video_num_buffers = num_buffers;
1512                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1513                                         }
1514
1515                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1516                                                 player->video_extra_num_buffers = extra_num_buffers;
1517                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1518                                         }
1519                                         break;
1520                                 }
1521
1522                                 if (!strcmp(structure_name, "Language_list")) {
1523                                         const GValue *lang_list = NULL;
1524                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1525                                         if (lang_list != NULL) {
1526                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1527                                                 if (count > 1)
1528                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1529                                         }
1530                                 }
1531
1532                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1533                                         const GValue *lang_list = NULL;
1534                                         MMPlayerLangStruct *temp = NULL;
1535
1536                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1537                                         if (lang_list != NULL) {
1538                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1539                                                 if (count) {
1540                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1541                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1542                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1543                                                         if (mmf_attrs_commit(attrs))
1544                                                                 LOGE("failed to commit.\n");
1545                                                         LOGD("Total subtitle tracks = %d \n", count);
1546
1547                                                         while (count) {
1548                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1549                                                                 if (temp)
1550                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1551                                                                                                 temp->language_key, temp->language_code);
1552                                                                 count--;
1553                                                         }
1554                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1555                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1556                                                 }
1557                                         }
1558                                 }
1559
1560                                 /* custom message */
1561                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1562                                         MMMessageParamType msg_param = {0,};
1563                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1564                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1565                                 }
1566
1567                                 /* custom message for RTSP attribute :
1568                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1569                                     sdp which has contents info is received when rtsp connection is opened.
1570                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1571                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1572
1573                                         gchar *audio_codec = NULL;
1574                                         gchar *video_codec = NULL;
1575                                         gchar *video_frame_size = NULL;
1576
1577                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1578                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1579                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1580                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1581
1582                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1583                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1584                                         if (audio_codec)
1585                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1586
1587                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1588                                         LOGD("rtsp_video_codec : %s", video_codec);
1589                                         if (video_codec)
1590                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1591
1592                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1593                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1594                                         if (video_frame_size) {
1595
1596                                                 char *seperator = strchr(video_frame_size, '-');
1597                                                 if (seperator) {
1598
1599                                                         char video_width[10] = {0,};
1600                                                         int frame_size_len = strlen(video_frame_size);
1601                                                         int separtor_len = strlen(seperator);
1602
1603                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1604                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1605
1606                                                         seperator++;
1607                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1608                                                 }
1609                                         }
1610
1611                                         if (mmf_attrs_commit(attrs))
1612                                                 LOGE("failed to commit.\n");
1613                                 }
1614                         }
1615                         break;
1616
1617         case GST_MESSAGE_DURATION_CHANGED:
1618                 {
1619                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1620                         if (!__mmplayer_gst_handle_duration(player, msg))
1621                                 LOGW("failed to update duration");
1622                 }
1623
1624                 break;
1625
1626         case GST_MESSAGE_ASYNC_START:
1627                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1628                 break;
1629
1630         case GST_MESSAGE_ASYNC_DONE:
1631                 {
1632                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1633
1634                         /* we only handle messages from pipeline */
1635                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1636                                 break;
1637
1638                         if (player->doing_seek) {
1639                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1640                                         player->doing_seek = FALSE;
1641                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1642                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1643                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1644                                                 (player->streamer) &&
1645                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1646                                                 (player->streamer->is_buffering == FALSE)) {
1647                                                 GstQuery *query = NULL;
1648                                                 gboolean busy = FALSE;
1649                                                 gint percent = 0;
1650
1651                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1652                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1653                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1654                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1655                                                         gst_query_unref(query);
1656
1657                                                         LOGD("buffered percent(%s): %d\n",
1658                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1659                                                 }
1660
1661                                                 if (percent >= 100) {
1662                                                         player->streamer->is_buffering = FALSE;
1663                                                         __mmplayer_handle_buffering_message(player);
1664                                                 }
1665                                         }
1666
1667                                         async_done = TRUE;
1668                                 }
1669                         }
1670                 }
1671                 break;
1672
1673         #if 0 /* delete unnecessary logs */
1674         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1675         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1676         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1677         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1678         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1679         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1680         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1681         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1682         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1683         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1684         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1685         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1686         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1687         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1688         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1689         #endif
1690
1691         default:
1692                 break;
1693         }
1694
1695         /* should not call 'gst_message_unref(msg)' */
1696         return;
1697 }
1698
1699 static gboolean
1700 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1701 {
1702         gint64 bytes = 0;
1703
1704         MMPLAYER_FENTER();
1705
1706         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1707         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1708
1709         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1710                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1711                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1712
1713                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1714                         LOGD("data total size of http content: %lld", bytes);
1715                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1716                 }
1717         } else
1718                 /* handling audio clip which has vbr. means duration is keep changing */
1719                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1720
1721         MMPLAYER_FLEAVE();
1722
1723         return TRUE;
1724 }
1725
1726 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1727                 mm_player_spherical_metadata_t *metadata) {
1728         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1729         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1730         gst_tag_list_get_string(tags, "stitching_software",
1731                         &metadata->stitching_software);
1732         gst_tag_list_get_string(tags, "projection_type",
1733                         &metadata->projection_type_string);
1734         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1735         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1736         gst_tag_list_get_int(tags, "init_view_heading",
1737                         &metadata->init_view_heading);
1738         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1739         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1740         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1741         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1742                         &metadata->full_pano_width_pixels);
1743         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1744                         &metadata->full_pano_height_pixels);
1745         gst_tag_list_get_int(tags, "cropped_area_image_width",
1746                         &metadata->cropped_area_image_width);
1747         gst_tag_list_get_int(tags, "cropped_area_image_height",
1748                         &metadata->cropped_area_image_height);
1749         gst_tag_list_get_int(tags, "cropped_area_left",
1750                         &metadata->cropped_area_left);
1751         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1752         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1753         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1754         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1755 }
1756
1757 static gboolean
1758 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1759 {
1760
1761 /* macro for better code readability */
1762 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1763 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1764         if (string != NULL) { \
1765                 SECURE_LOGD("update tag string : %s\n", string); \
1766                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1767                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1768                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1769                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1770                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1771                         g_free(new_string); \
1772                         new_string = NULL; \
1773                 } else { \
1774                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1775                 } \
1776                 g_free(string); \
1777                 string = NULL; \
1778         } \
1779 }
1780
1781 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1782 do {    \
1783         GstSample *sample = NULL;\
1784         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1785                 GstMapInfo info = GST_MAP_INFO_INIT;\
1786                 buffer = gst_sample_get_buffer(sample);\
1787                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1788                         LOGD("failed to get image data from tag");\
1789                         gst_sample_unref(sample);\
1790                         return FALSE;\
1791                 } \
1792                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1793                 MMPLAYER_FREEIF(player->album_art);\
1794                 player->album_art = (gchar *)g_malloc(info.size);\
1795                 if (player->album_art) {\
1796                         memcpy(player->album_art, info.data, info.size);\
1797                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1798                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1799                                 msg_param.data = (void *)player->album_art;\
1800                                 msg_param.size = info.size;\
1801                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1802                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1803                         } \
1804                 } \
1805                 gst_buffer_unmap(buffer, &info);\
1806                 gst_sample_unref(sample);\
1807         }       \
1808 } while (0)
1809
1810 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1811 do {    \
1812         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1813                 if (v_uint) { \
1814                         int i = 0; \
1815                         gchar *tag_list_str = NULL; \
1816                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1817                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1818                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1819                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1820                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1821                         else \
1822                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1823                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1824                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1825                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1826                                 player->bitrate[track_type] = v_uint; \
1827                                 player->total_bitrate = 0; \
1828                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1829                                         player->total_bitrate += player->bitrate[i]; \
1830                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1831                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1832                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1833                                 player->maximum_bitrate[track_type] = v_uint; \
1834                                 player->total_maximum_bitrate = 0; \
1835                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1836                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1837                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1838                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1839                         } else { \
1840                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1841                         } \
1842                         v_uint = 0;\
1843                         g_free(tag_list_str); \
1844                 } \
1845         } \
1846 } while (0)
1847
1848 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1849 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1850         if (date != NULL) {\
1851                 string = g_strdup_printf("%d", g_date_get_year(date));\
1852                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1853                 SECURE_LOGD("metainfo year : %s\n", string);\
1854                 MMPLAYER_FREEIF(string);\
1855                 g_date_free(date);\
1856         } \
1857 }
1858
1859 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1860 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1861         if (datetime != NULL) {\
1862                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1863                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1864                 SECURE_LOGD("metainfo year : %s\n", string);\
1865                 MMPLAYER_FREEIF(string);\
1866                 gst_date_time_unref(datetime);\
1867         } \
1868 }
1869
1870 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1871 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1872         if (v_uint64) {\
1873                 /* FIXIT : don't know how to store date */\
1874                 g_assert(1);\
1875                 v_uint64 = 0;\
1876         } \
1877 }
1878
1879 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1880 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1881         if (v_double) {\
1882                 /* FIXIT : don't know how to store date */\
1883                 g_assert(1);\
1884                 v_double = 0;\
1885         } \
1886 }
1887
1888         /* function start */
1889         GstTagList* tag_list = NULL;
1890
1891         MMHandleType attrs = 0;
1892
1893         char *string = NULL;
1894         guint v_uint = 0;
1895         GDate *date = NULL;
1896         GstDateTime *datetime = NULL;
1897         /* album cover */
1898         GstBuffer *buffer = NULL;
1899         gint index = 0;
1900         MMMessageParamType msg_param = {0, };
1901
1902         /* currently not used. but those are needed for above macro */
1903         //guint64 v_uint64 = 0;
1904         //gdouble v_double = 0;
1905
1906         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1907
1908         attrs = MMPLAYER_GET_ATTRS(player);
1909
1910         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1911
1912         /* get tag list from gst message */
1913         gst_message_parse_tag(msg, &tag_list);
1914
1915         /* store tags to player attributes */
1916         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1917         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1918         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1919         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1920         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1922         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1923         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1924         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1925         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1926         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1927         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1928         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1929         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1930         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1931         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1932         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1933         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1934         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1937         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1938         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1939         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1940         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1941         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1942         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1943         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1944         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1945         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1946         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1947         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1948         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1949         MMPLAYER_UPDATE_TAG_LOCK(player);
1950         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1951         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1952         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1953         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1954         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1955         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1956         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1957         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1958         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1959         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1960         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1961         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1962         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1963         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1964         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1965
1966         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1967                 if (player->video360_metadata.is_spherical == -1) {
1968                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1969                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1970                                         player->video360_metadata.is_spherical);
1971                         if (player->video360_metadata.is_spherical == 1) {
1972                                 LOGD("This is spherical content for 360 playback.");
1973                                 player->is_content_spherical = TRUE;
1974                         } else {
1975                                 LOGD("This is not spherical content");
1976                                 player->is_content_spherical = FALSE;
1977                         }
1978
1979                         if (player->video360_metadata.projection_type_string) {
1980                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1981                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1982                                 } else {
1983                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1984                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1985                                 }
1986                         }
1987
1988                         if (player->video360_metadata.stereo_mode_string) {
1989                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1990                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1991                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1992                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1993                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1994                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1995                                 } else {
1996                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1997                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1998                                 }
1999                         }
2000                 }
2001         }
2002
2003         if (mmf_attrs_commit(attrs))
2004                 LOGE("failed to commit.\n");
2005
2006         gst_tag_list_free(tag_list);
2007
2008         return TRUE;
2009 }
2010
2011 static void
2012 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2013 {
2014         mm_player_t* player = (mm_player_t*) data;
2015
2016         MMPLAYER_FENTER();
2017
2018         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2019           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2020           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2021           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2022
2023           * [1] audio and video will be dumped with filesink.
2024           * [2] autoplugging is done by just using pad caps.
2025           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2026           * and the video will be dumped via filesink.
2027           */
2028         if (player->num_dynamic_pad == 0) {
2029                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2030
2031                 if (!__mmplayer_gst_remove_fakesink(player,
2032                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2033                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2034                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2035                          * source element are not same. To overcome this situation, this function will called
2036                          * several places and several times. Therefore, this is not an error case.
2037                          */
2038                         return;
2039         }
2040
2041         /* create dot before error-return. for debugging */
2042         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2043
2044         player->no_more_pad = TRUE;
2045
2046         MMPLAYER_FLEAVE();
2047 }
2048
2049 static gboolean
2050 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2051 {
2052         GstElement* parent = NULL;
2053
2054         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2055
2056         /* if we have no fakesink. this meas we are using decodebin which doesn'
2057         t need to add extra fakesink */
2058         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2059
2060         /* lock */
2061         MMPLAYER_FSINK_LOCK(player);
2062
2063         if (!fakesink->gst)
2064                 goto ERROR;
2065
2066         /* get parent of fakesink */
2067         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2068         if (!parent) {
2069                 LOGD("fakesink already removed\n");
2070                 goto ERROR;
2071         }
2072
2073         gst_element_set_locked_state(fakesink->gst, TRUE);
2074
2075         /* setting the state to NULL never returns async
2076          * so no need to wait for completion of state transiton
2077          */
2078         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2079                 LOGE("fakesink state change failure!\n");
2080                 /* FIXIT : should I return here? or try to proceed to next? */
2081                 /* return FALSE; */
2082
2083         /* remove fakesink from it's parent */
2084         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2085                 LOGE("failed to remove fakesink\n");
2086
2087                 gst_object_unref(parent);
2088
2089                 goto ERROR;
2090         }
2091
2092         gst_object_unref(parent);
2093
2094         LOGD("state-holder removed\n");
2095
2096         gst_element_set_locked_state(fakesink->gst, FALSE);
2097
2098         MMPLAYER_FSINK_UNLOCK(player);
2099         return TRUE;
2100
2101 ERROR:
2102         if (fakesink->gst)
2103                 gst_element_set_locked_state(fakesink->gst, FALSE);
2104
2105         MMPLAYER_FSINK_UNLOCK(player);
2106         return FALSE;
2107 }
2108
2109
2110 static void
2111 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2112 {
2113         GstPad *sinkpad = NULL;
2114         GstCaps* caps = NULL;
2115         GstElement* new_element = NULL;
2116         GstStructure* str = NULL;
2117         const gchar* name = NULL;
2118
2119         mm_player_t* player = (mm_player_t*) data;
2120
2121         MMPLAYER_FENTER();
2122
2123         MMPLAYER_RETURN_IF_FAIL(element && pad);
2124         MMPLAYER_RETURN_IF_FAIL(player &&
2125                                         player->pipeline &&
2126                                         player->pipeline->mainbin);
2127
2128
2129         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2130          * num_dynamic_pad will decreased after creating a sinkbin.
2131          */
2132         player->num_dynamic_pad++;
2133         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2134
2135         caps = gst_pad_query_caps(pad, NULL);
2136
2137         MMPLAYER_CHECK_NULL(caps);
2138
2139         /* clear  previous result*/
2140         player->have_dynamic_pad = FALSE;
2141
2142         str = gst_caps_get_structure(caps, 0);
2143
2144         if (!str) {
2145                 LOGE("cannot get structure from caps.\n");
2146                 goto ERROR;
2147         }
2148
2149         name = gst_structure_get_name(str);
2150         if (!name) {
2151                 LOGE("cannot get mimetype from structure.\n");
2152                 goto ERROR;
2153         }
2154
2155         if (strstr(name, "video")) {
2156                 gint stype = 0;
2157                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2158
2159                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2160                         if (player->v_stream_caps) {
2161                                 gst_caps_unref(player->v_stream_caps);
2162                                 player->v_stream_caps = NULL;
2163                         }
2164
2165                         new_element = gst_element_factory_make("fakesink", NULL);
2166                         player->num_dynamic_pad--;
2167                         goto NEW_ELEMENT;
2168                 }
2169         }
2170
2171         /* clear  previous result*/
2172         player->have_dynamic_pad = FALSE;
2173
2174         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2175                 LOGE("failed to autoplug for caps");
2176                 goto ERROR;
2177         }
2178
2179         /* check if there's dynamic pad*/
2180         if (player->have_dynamic_pad) {
2181                 LOGE("using pad caps assums there's no dynamic pad !\n");
2182                 goto ERROR;
2183         }
2184
2185         gst_caps_unref(caps);
2186         caps = NULL;
2187
2188 NEW_ELEMENT:
2189
2190         /* excute new_element if created*/
2191         if (new_element) {
2192                 LOGD("adding new element to pipeline\n");
2193
2194                 /* set state to READY before add to bin */
2195                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2196
2197                 /* add new element to the pipeline */
2198                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2199                         LOGE("failed to add autoplug element to bin\n");
2200                         goto ERROR;
2201                 }
2202
2203                 /* get pad from element */
2204                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2205                 if (!sinkpad) {
2206                         LOGE("failed to get sinkpad from autoplug element\n");
2207                         goto ERROR;
2208                 }
2209
2210                 /* link it */
2211                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2212                         LOGE("failed to link autoplug element\n");
2213                         goto ERROR;
2214                 }
2215
2216                 gst_object_unref(sinkpad);
2217                 sinkpad = NULL;
2218
2219                 /* run. setting PLAYING here since streamming source is live source */
2220                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2221         }
2222
2223         if (caps)
2224                 gst_caps_unref(caps);
2225
2226         MMPLAYER_FLEAVE();
2227
2228         return;
2229
2230 STATE_CHANGE_FAILED:
2231 ERROR:
2232         /* FIXIT : take care if new_element has already added to pipeline */
2233         if (new_element)
2234                 gst_object_unref(GST_OBJECT(new_element));
2235
2236         if (sinkpad)
2237                 gst_object_unref(GST_OBJECT(sinkpad));
2238
2239         if (caps)
2240                 gst_caps_unref(caps);
2241
2242         /* FIXIT : how to inform this error to MSL ????? */
2243         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2244          * then post an error to application
2245          */
2246 }
2247
2248 static GstPadProbeReturn
2249 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2250 {
2251         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2252         return GST_PAD_PROBE_OK;
2253 }
2254
2255 static GstPadProbeReturn
2256 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2257 {
2258         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2259         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2260         mm_player_t* player = (mm_player_t*)data;
2261         GstCaps* caps = NULL;
2262         GstStructure* str = NULL;
2263         const gchar* name = NULL;
2264         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2265
2266
2267         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2268                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2269                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2270                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2271                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2272                         return ret;
2273         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2274                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2275                         return ret;
2276         }
2277
2278         caps = gst_pad_query_caps(pad, NULL);
2279         if (!caps) {
2280                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2281                 return ret;
2282         }
2283
2284         str = gst_caps_get_structure(caps, 0);
2285         if (!str) {
2286                 LOGE("failed to get structure from caps");
2287                 goto ERROR;
2288         }
2289
2290         name = gst_structure_get_name(str);
2291         if (!name) {
2292                 LOGE("failed to get name from str");
2293                 goto ERROR;
2294         }
2295
2296         if (strstr(name, "audio")) {
2297                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2298         } else if (strstr(name, "video")) {
2299                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2300         } else {
2301                 /* text track is not supportable */
2302                 LOGE("invalid name %s", name);
2303                 goto ERROR;
2304         }
2305
2306         switch (GST_EVENT_TYPE(event)) {
2307         case GST_EVENT_EOS:
2308                 {
2309                         /* in case of gapless, drop eos event not to send it to sink */
2310                         if (player->gapless.reconfigure && !player->msg_posted) {
2311                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2312                                 ret = GST_PAD_PROBE_DROP;
2313                         }
2314                         break;
2315                 }
2316         case GST_EVENT_STREAM_START:
2317                 {
2318                         gint64 stop_running_time = 0;
2319                         gint64 position_running_time = 0;
2320                         gint64 position = 0;
2321                         gint idx = 0;
2322
2323                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2324                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2325                                         !(player->selector[idx].event_probe_id)) {
2326                                         /* LOGW("[%d] skip", idx); */
2327                                         continue;
2328                                 }
2329
2330                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2331                                         stop_running_time =
2332                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2333                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2334                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2335                                         stop_running_time =
2336                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2337                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2338                                 } else {
2339                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2340                                         stop_running_time =
2341                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2342                                                                 GST_FORMAT_TIME, player->duration);
2343                                 }
2344
2345                                 position_running_time =
2346                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2347                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2348
2349                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2350                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2351                                         idx,
2352                                         GST_TIME_ARGS(stop_running_time),
2353                                         GST_TIME_ARGS(position_running_time),
2354                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2355                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2356
2357                                 position_running_time = MAX(position_running_time, stop_running_time);
2358                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2359                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2360                                 position_running_time = MAX(0, position_running_time);
2361                                 position = MAX(position, position_running_time);
2362                         }
2363
2364                         if (position != 0) {
2365                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2366                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2367                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2368
2369                                 player->gapless.start_time[stream_type] += position;
2370                         }
2371                         break;
2372                 }
2373         case GST_EVENT_FLUSH_STOP:
2374                 {
2375                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2376                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2377                         player->gapless.start_time[stream_type] = 0;
2378                         break;
2379                 }
2380         case GST_EVENT_SEGMENT:
2381                 {
2382                         GstSegment segment;
2383                         GstEvent *tmpev;
2384
2385                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2386                         gst_event_copy_segment(event, &segment);
2387
2388                         if (segment.format == GST_FORMAT_TIME) {
2389                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2390                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2391                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2392                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2393                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2394                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2395
2396                                 /* keep the all the segment ev to cover the seeking */
2397                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2398                                 player->gapless.update_segment[stream_type] = TRUE;
2399
2400                                 if (!player->gapless.running)
2401                                         break;
2402
2403                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2404
2405                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2406
2407                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2408                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2409                                 gst_event_unref(event);
2410                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2411                         }
2412                         break;
2413                 }
2414         case GST_EVENT_QOS:
2415                 {
2416                         gdouble proportion = 0.0;
2417                         GstClockTimeDiff diff = 0;
2418                         GstClockTime timestamp = 0;
2419                         gint64 running_time_diff = -1;
2420                         GstQOSType type = 0;
2421                         GstEvent *tmpev = NULL;
2422
2423                         running_time_diff = player->gapless.segment[stream_type].base;
2424
2425                         if (running_time_diff <= 0) /* don't need to adjust */
2426                                 break;
2427
2428                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2429                         gst_event_unref(event);
2430
2431                         if (timestamp < running_time_diff) {
2432                                 LOGW("QOS event from previous group");
2433                                 ret = GST_PAD_PROBE_DROP;
2434                                 break;
2435                         }
2436
2437                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2438                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2439                                                 stream_type, GST_TIME_ARGS(timestamp),
2440                                                 GST_TIME_ARGS(running_time_diff),
2441                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2442
2443                         timestamp -= running_time_diff;
2444
2445                         /* That case is invalid for QoS events */
2446                         if (diff < 0 && -diff > timestamp) {
2447                                 LOGW("QOS event from previous group");
2448                                 ret = GST_PAD_PROBE_DROP;
2449                                 break;
2450                         }
2451
2452                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2453                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2454
2455                         break;
2456                 }
2457         default:
2458                 break;
2459         }
2460
2461 ERROR:
2462         if (caps)
2463                 gst_caps_unref(caps);
2464         return ret;
2465 }
2466
2467 static void
2468 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2469 {
2470         mm_player_t* player = NULL;
2471         GstElement* pipeline = NULL;
2472         GstElement* selector = NULL;
2473         GstElement* fakesink = NULL;
2474         GstCaps* caps = NULL;
2475         GstStructure* str = NULL;
2476         const gchar* name = NULL;
2477         GstPad* sinkpad = NULL;
2478         GstPad* srcpad = NULL;
2479         gboolean first_track = FALSE;
2480
2481         enum MainElementID elemId = MMPLAYER_M_NUM;
2482         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2483
2484         /* check handles */
2485         player = (mm_player_t*)data;
2486
2487         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2488         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2489
2490         //LOGD("pad-added signal handling\n");
2491
2492         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2493
2494         /* get mimetype from caps */
2495         caps = gst_pad_query_caps(pad, NULL);
2496         if (!caps) {
2497                 LOGE("cannot get caps from pad.\n");
2498                 goto ERROR;
2499         }
2500
2501         str = gst_caps_get_structure(caps, 0);
2502         if (!str) {
2503                 LOGE("cannot get structure from caps.\n");
2504                 goto ERROR;
2505         }
2506
2507         name = gst_structure_get_name(str);
2508         if (!name) {
2509                 LOGE("cannot get mimetype from structure.\n");
2510                 goto ERROR;
2511         }
2512
2513         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2514         //LOGD("detected mimetype : %s\n", name);
2515
2516         if (strstr(name, "video")) {
2517                 gint stype = 0;
2518
2519                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2520                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2521
2522                 /* don't make video because of not required, and not support multiple track */
2523                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2524                         LOGD("no video sink by null surface");
2525
2526                         gchar *caps_str = gst_caps_to_string(caps);
2527                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2528                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2529                                 player->set_mode.video_zc = TRUE;
2530
2531                         MMPLAYER_FREEIF(caps_str);
2532
2533                         if (player->v_stream_caps) {
2534                                 gst_caps_unref(player->v_stream_caps);
2535                                 player->v_stream_caps = NULL;
2536                         }
2537
2538                         LOGD("create fakesink instead of videobin");
2539
2540                         /* fake sink */
2541                         fakesink = gst_element_factory_make("fakesink", NULL);
2542                         if (fakesink == NULL) {
2543                                 LOGE("ERROR : fakesink create error\n");
2544                                 goto ERROR;
2545                         }
2546
2547                         if (player->ini.set_dump_element_flag)
2548                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2549
2550                         player->video_fakesink = fakesink;
2551
2552                         /* store it as it's sink element */
2553                         __mmplayer_add_sink(player, player->video_fakesink);
2554
2555                         gst_bin_add(GST_BIN(pipeline), fakesink);
2556
2557                         // link
2558                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2559
2560                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2561                                 LOGW("failed to link fakesink\n");
2562                                 gst_object_unref(GST_OBJECT(fakesink));
2563                                 goto ERROR;
2564                         }
2565
2566                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2567                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2568                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2569                         }
2570
2571                         if (player->set_mode.media_packet_video_stream) {
2572                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2573
2574                                 MMPLAYER_SIGNAL_CONNECT(player,
2575                                                                                 G_OBJECT(fakesink),
2576                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2577                                                                                 "handoff",
2578                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2579                                                                                 (gpointer)player);
2580
2581                                 MMPLAYER_SIGNAL_CONNECT(player,
2582                                                                                 G_OBJECT(fakesink),
2583                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2584                                                                                 "preroll-handoff",
2585                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2586                                                                                 (gpointer)player);
2587                         }
2588
2589                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2590                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2591                         goto DONE;
2592                 }
2593
2594                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2595                         __mmplayer_gst_decode_callback(elem, pad, player);
2596                         goto DONE;
2597                 }
2598
2599                 LOGD("video selector \n");
2600                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2601                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2602         } else {
2603                 if (strstr(name, "audio")) {
2604                         gint samplerate = 0;
2605                         gint channels = 0;
2606
2607                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2608                                 __mmplayer_gst_decode_callback(elem, pad, player);
2609                                 goto DONE;
2610                         }
2611
2612                         LOGD("audio selector \n");
2613                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2614                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2615
2616                         gst_structure_get_int(str, "rate", &samplerate);
2617                         gst_structure_get_int(str, "channels", &channels);
2618
2619                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2620                                 /* fake sink */
2621                                 fakesink = gst_element_factory_make("fakesink", NULL);
2622                                 if (fakesink == NULL) {
2623                                         LOGE("ERROR : fakesink create error\n");
2624                                         goto ERROR;
2625                                 }
2626
2627                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2628
2629                                 /* link */
2630                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2631
2632                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2633                                         LOGW("failed to link fakesink\n");
2634                                         gst_object_unref(GST_OBJECT(fakesink));
2635                                         goto ERROR;
2636                                 }
2637
2638                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2639                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2640                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2641
2642                                 goto DONE;
2643                         }
2644                 } else if (strstr(name, "text")) {
2645                         LOGD("text selector \n");
2646                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2647                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2648                 } else {
2649                         LOGE("wrong elem id \n");
2650                         goto ERROR;
2651                 }
2652         }
2653
2654         selector = player->pipeline->mainbin[elemId].gst;
2655         if (selector == NULL) {
2656                 selector = gst_element_factory_make("input-selector", NULL);
2657                 LOGD("Creating input-selector\n");
2658                 if (selector == NULL) {
2659                         LOGE("ERROR : input-selector create error\n");
2660                         goto ERROR;
2661                 }
2662                 g_object_set(selector, "sync-streams", TRUE, NULL);
2663
2664                 player->pipeline->mainbin[elemId].id = elemId;
2665                 player->pipeline->mainbin[elemId].gst = selector;
2666
2667                 first_track = TRUE;
2668                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2669
2670                 srcpad = gst_element_get_static_pad(selector, "src");
2671
2672                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2673                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2674                         __mmplayer_gst_selector_blocked, NULL, NULL);
2675                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2676                         __mmplayer_gst_selector_event_probe, player, NULL);
2677
2678                 gst_element_set_state(selector, GST_STATE_PAUSED);
2679                 gst_bin_add(GST_BIN(pipeline), selector);
2680         } else
2681                 LOGD("input-selector is already created.\n");
2682
2683         // link
2684         LOGD("Calling request pad with selector %p \n", selector);
2685         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2686
2687         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2688
2689         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2690                 LOGW("failed to link selector\n");
2691                 gst_object_unref(GST_OBJECT(selector));
2692                 goto ERROR;
2693         }
2694
2695         if (first_track) {
2696                 LOGD("this is first track --> active track \n");
2697                 g_object_set(selector, "active-pad", sinkpad, NULL);
2698         }
2699
2700         _mmplayer_track_update_info(player, stream_type, sinkpad);
2701
2702
2703 DONE:
2704 ERROR:
2705
2706         if (caps)
2707                 gst_caps_unref(caps);
2708
2709         if (sinkpad) {
2710                 gst_object_unref(GST_OBJECT(sinkpad));
2711                 sinkpad = NULL;
2712         }
2713
2714         if (srcpad) {
2715                 gst_object_unref(GST_OBJECT(srcpad));
2716                 srcpad = NULL;
2717         }
2718
2719         return;
2720 }
2721
2722 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2723 {
2724         GstPad* srcpad = NULL;
2725         MMHandleType attrs = 0;
2726         gint active_index = 0;
2727
2728         // [link] input-selector :: textbin
2729         srcpad = gst_element_get_static_pad(text_selector, "src");
2730         if (!srcpad) {
2731                 LOGE("failed to get srcpad from selector\n");
2732                 return;
2733         }
2734
2735         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2736
2737         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2738         if ((active_index != DEFAULT_TRACK) &&
2739                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2740                 LOGW("failed to change text track\n");
2741                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2742         }
2743
2744         player->no_more_pad = TRUE;
2745         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2746
2747         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2748         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2749                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2750                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2751         }
2752
2753         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2754
2755         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2756                 player->has_closed_caption = TRUE;
2757
2758         attrs = MMPLAYER_GET_ATTRS(player);
2759         if (attrs) {
2760                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2761                 if (mmf_attrs_commit(attrs))
2762                         LOGE("failed to commit.\n");
2763         } else
2764                 LOGE("cannot get content attribute");
2765
2766         if (srcpad) {
2767                 gst_object_unref(GST_OBJECT(srcpad));
2768                 srcpad = NULL;
2769         }
2770 }
2771
2772 static void
2773 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2774 {
2775         mm_player_t* player = (mm_player_t*)data;
2776         GstElement* selector = NULL;
2777         GstElement* queue = NULL;
2778
2779         GstPad* srcpad = NULL;
2780         GstPad* sinkpad = NULL;
2781         GstCaps* caps = NULL;
2782         gchar* caps_str = NULL;
2783
2784         MMPLAYER_FENTER();
2785         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2786
2787         caps = gst_pad_get_current_caps(pad);
2788         caps_str = gst_caps_to_string(caps);
2789         LOGD("deinterleave new caps : %s\n", caps_str);
2790         MMPLAYER_FREEIF(caps_str);
2791         gst_caps_unref(caps);
2792
2793         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2794                 LOGE("ERROR : queue create error\n");
2795                 goto ERROR;
2796         }
2797
2798         g_object_set(G_OBJECT(queue),
2799                                 "max-size-buffers", 10,
2800                                 "max-size-bytes", 0,
2801                                 "max-size-time", (guint64)0,
2802                                 NULL);
2803
2804         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2805
2806         if (!selector) {
2807                 LOGE("there is no audio channel selector.\n");
2808                 goto ERROR;
2809         }
2810
2811         srcpad = gst_element_get_static_pad(queue, "src");
2812         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2813
2814         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2815
2816         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2817                 LOGW("failed to link deinterleave - selector\n");
2818                 goto ERROR;
2819         }
2820
2821         gst_element_set_state(queue, GST_STATE_PAUSED);
2822         player->audio_mode.total_track_num++;
2823
2824 ERROR:
2825
2826         if (srcpad) {
2827                 gst_object_unref(GST_OBJECT(srcpad));
2828                 srcpad = NULL;
2829         }
2830
2831         if (sinkpad) {
2832                 gst_object_unref(GST_OBJECT(sinkpad));
2833                 sinkpad = NULL;
2834         }
2835
2836         MMPLAYER_FLEAVE();
2837         return;
2838 }
2839
2840 static void
2841 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2842 {
2843         mm_player_t* player = NULL;
2844         GstElement* selector = NULL;
2845         GstPad* sinkpad = NULL;
2846         gint active_index = 0;
2847         gchar* change_pad_name = NULL;
2848         GstCaps* caps = NULL;   // no need to unref
2849         gint default_audio_ch = 0;
2850
2851         MMPLAYER_FENTER();
2852         player = (mm_player_t*) data;
2853
2854         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2855
2856         if (!selector) {
2857                 LOGE("there is no audio channel selector.\n");
2858                 goto ERROR;
2859         }
2860
2861         active_index = player->audio_mode.active_pad_index;
2862
2863         if (active_index != default_audio_ch) {
2864                 gint audio_ch = default_audio_ch;
2865
2866                 /*To get the new pad from the selector*/
2867                 change_pad_name = g_strdup_printf("sink%d", active_index);
2868                 if (change_pad_name != NULL) {
2869                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2870                         if (sinkpad != NULL) {
2871                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2872                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2873
2874                                 audio_ch = active_index;
2875
2876                                 caps = gst_pad_get_current_caps(sinkpad);
2877                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2878
2879                                 __mmplayer_set_audio_attrs(player, caps);
2880                                 gst_caps_unref(caps);
2881                         }
2882                         MMPLAYER_FREEIF(change_pad_name);
2883                 }
2884
2885                 player->audio_mode.active_pad_index = audio_ch;
2886                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2887         }
2888
2889 ERROR:
2890
2891         if (sinkpad)
2892                 gst_object_unref(sinkpad);
2893
2894         MMPLAYER_FLEAVE();
2895         return;
2896 }
2897
2898 static void
2899 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2900 {
2901         mm_player_t* player = NULL;
2902         MMPlayerGstElement *mainbin = NULL;
2903
2904         GstElement* tee = NULL;
2905         GstElement* stereo_queue = NULL;
2906         GstElement* mono_queue = NULL;
2907         GstElement* conv = NULL;
2908         GstElement* filter = NULL;
2909         GstElement* deinterleave = NULL;
2910         GstElement* selector = NULL;
2911
2912         GstPad* srcpad = NULL;
2913         GstPad* selector_srcpad = NULL;
2914         GstPad* sinkpad = NULL;
2915         GstCaps* caps = NULL;
2916         gulong block_id = 0;
2917
2918         MMPLAYER_FENTER();
2919
2920         /* check handles */
2921         player = (mm_player_t*) data;
2922
2923         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2924         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2925
2926         mainbin = player->pipeline->mainbin;
2927
2928         /* tee */
2929         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2930                 LOGE("ERROR : tee create error\n");
2931                 goto ERROR;
2932         }
2933
2934         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2935         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2936
2937         gst_element_set_state(tee, GST_STATE_PAUSED);
2938
2939         /* queue */
2940         srcpad = gst_element_get_request_pad(tee, "src_%u");
2941         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2942                 LOGE("ERROR : stereo queue create error\n");
2943                 goto ERROR;
2944         }
2945
2946         g_object_set(G_OBJECT(stereo_queue),
2947                                 "max-size-buffers", 10,
2948                                 "max-size-bytes", 0,
2949                                 "max-size-time", (guint64)0,
2950                                 NULL);
2951
2952         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2953         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2954
2955         if (srcpad) {
2956                 gst_object_unref(GST_OBJECT(srcpad));
2957                 srcpad = NULL;
2958         }
2959
2960         srcpad = gst_element_get_request_pad(tee, "src_%u");
2961
2962         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2963                 LOGE("ERROR : mono queue create error\n");
2964                 goto ERROR;
2965         }
2966
2967         g_object_set(G_OBJECT(mono_queue),
2968                                 "max-size-buffers", 10,
2969                                 "max-size-bytes", 0,
2970                                 "max-size-time", (guint64)0,
2971                                 NULL);
2972
2973         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2974         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2975
2976         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2977         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2978
2979         /* audioconvert */
2980         srcpad = gst_element_get_static_pad(mono_queue, "src");
2981         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2982                 LOGE("ERROR : audioconvert create error\n");
2983                 goto ERROR;
2984         }
2985
2986         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2987         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2988
2989         /* caps filter */
2990         if (srcpad) {
2991                 gst_object_unref(GST_OBJECT(srcpad));
2992                 srcpad = NULL;
2993         }
2994         srcpad = gst_element_get_static_pad(conv, "src");
2995
2996         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2997                 LOGE("ERROR : capsfilter create error\n");
2998                 goto ERROR;
2999         }
3000
3001         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3002         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3003
3004         caps = gst_caps_from_string("audio/x-raw-int, "
3005                                 "width = (int) 16, "
3006                                 "depth = (int) 16, "
3007                                 "channels = (int) 2");
3008
3009         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3010         gst_caps_unref(caps);
3011
3012         gst_element_set_state(conv, GST_STATE_PAUSED);
3013         gst_element_set_state(filter, GST_STATE_PAUSED);
3014
3015         /* deinterleave */
3016         if (srcpad) {
3017                 gst_object_unref(GST_OBJECT(srcpad));
3018                 srcpad = NULL;
3019         }
3020         srcpad = gst_element_get_static_pad(filter, "src");
3021
3022         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3023                 LOGE("ERROR : deinterleave create error\n");
3024                 goto ERROR;
3025         }
3026
3027         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3028
3029         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3030                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3031
3032         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3033                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3034
3035         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3036         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3037
3038         /* selector */
3039         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3040         if (selector == NULL) {
3041                 LOGE("ERROR : audio-selector create error\n");
3042                 goto ERROR;
3043         }
3044
3045         g_object_set(selector, "sync-streams", TRUE, NULL);
3046         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3047
3048         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3049         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3050
3051         selector_srcpad = gst_element_get_static_pad(selector, "src");
3052
3053         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3054         block_id =
3055                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3056                         __mmplayer_gst_selector_blocked, NULL, NULL);
3057
3058         if (srcpad) {
3059                 gst_object_unref(GST_OBJECT(srcpad));
3060                 srcpad = NULL;
3061         }
3062
3063         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3064         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3065
3066         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3067                 LOGW("failed to link queue_stereo - selector\n");
3068                 goto ERROR;
3069         }
3070
3071         player->audio_mode.total_track_num++;
3072
3073         g_object_set(selector, "active-pad", sinkpad, NULL);
3074         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3075         gst_element_set_state(selector, GST_STATE_PAUSED);
3076
3077         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3078
3079 ERROR:
3080
3081         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3082         if (block_id != 0) {
3083                 gst_pad_remove_probe(selector_srcpad, block_id);
3084                 block_id = 0;
3085         }
3086
3087         if (sinkpad) {
3088                 gst_object_unref(GST_OBJECT(sinkpad));
3089                 sinkpad = NULL;
3090         }
3091
3092         if (srcpad) {
3093                 gst_object_unref(GST_OBJECT(srcpad));
3094                 srcpad = NULL;
3095         }
3096
3097         if (selector_srcpad) {
3098                 gst_object_unref(GST_OBJECT(selector_srcpad));
3099                 selector_srcpad = NULL;
3100         }
3101
3102         MMPLAYER_FLEAVE();
3103         return;
3104 }
3105
3106 static void
3107 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3108 {
3109         mm_player_t* player = NULL;
3110         GstPad* srcpad = NULL;
3111         GstElement* video_selector = NULL;
3112         GstElement* audio_selector = NULL;
3113         GstElement* text_selector = NULL;
3114         MMHandleType attrs = 0;
3115         gint active_index = 0;
3116         gint64 dur_bytes = 0L;
3117
3118         player = (mm_player_t*) data;
3119
3120         LOGD("no-more-pad signal handling\n");
3121
3122         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3123                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3124                 LOGW("no need to go more");
3125
3126                 if (player->gapless.reconfigure) {
3127                         player->gapless.reconfigure = FALSE;
3128                         MMPLAYER_PLAYBACK_UNLOCK(player);
3129                 }
3130
3131                 return;
3132         }
3133
3134         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3135                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3136                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3137                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3138                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3139
3140                 if (NULL == player->streamer) {
3141                         LOGW("invalid state for buffering");
3142                         goto ERROR;
3143                 }
3144
3145                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3146                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3147
3148                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3149                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3150
3151                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3152
3153                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3154                         LOGE("fail to get duration.\n");
3155
3156                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3157                 // use file information was already set on Q2 when it was created.
3158                 __mm_player_streaming_set_queue2(player->streamer,
3159                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3160                                                 TRUE,                                                           // use_buffering
3161                                                 buffer_bytes,
3162                                                 init_buffering_time,
3163                                                 1.0,                                                            // low percent
3164                                                 player->ini.http_buffering_limit,       // high percent
3165                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3166                                                 NULL,
3167                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3168         }
3169
3170         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3171         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3172         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3173         if (video_selector) {
3174                 // [link] input-selector :: videobin
3175                 srcpad = gst_element_get_static_pad(video_selector, "src");
3176                 if (!srcpad) {
3177                         LOGE("failed to get srcpad from video selector\n");
3178                         goto ERROR;
3179                 }
3180
3181                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3182                 if (!text_selector && !audio_selector)
3183                         player->no_more_pad = TRUE;
3184
3185                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3186
3187                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3188                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3189                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3190                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3191                 }
3192         }
3193
3194         if (audio_selector) {
3195                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3196                 if ((active_index != DEFAULT_TRACK) &&
3197                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3198                         LOGW("failed to change audio track\n");
3199                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3200                 }
3201
3202                 // [link] input-selector :: audiobin
3203                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3204                 if (!srcpad) {
3205                         LOGE("failed to get srcpad from selector\n");
3206                         goto ERROR;
3207                 }
3208
3209                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3210                 if (!text_selector)
3211                         player->no_more_pad = TRUE;
3212
3213                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3214                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3215                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3216                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3217                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3218                         }
3219
3220                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3221                 } else {
3222                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3223
3224                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3225                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3226                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3227                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3228                         }
3229                 }
3230
3231                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3232
3233                 attrs = MMPLAYER_GET_ATTRS(player);
3234                 if (attrs) {
3235                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3236                         if (mmf_attrs_commit(attrs))
3237                                 LOGE("failed to commit.\n");
3238                 } else
3239                         LOGE("cannot get content attribute");
3240         } else {
3241                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3242                         LOGD("There is no audio track : remove audiobin");
3243
3244                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3245                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3246
3247                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3248                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3249                 }
3250
3251                 if (player->num_dynamic_pad == 0)
3252                         __mmplayer_pipeline_complete(NULL, player);
3253         }
3254
3255         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3256                 if (text_selector)
3257                         __mmplayer_handle_text_decode_path(player, text_selector);
3258         }
3259
3260         MMPLAYER_FLEAVE();
3261
3262 ERROR:
3263         if (srcpad) {
3264                 gst_object_unref(GST_OBJECT(srcpad));
3265                 srcpad = NULL;
3266         }
3267
3268         if (player->gapless.reconfigure) {
3269                 player->gapless.reconfigure = FALSE;
3270                 MMPLAYER_PLAYBACK_UNLOCK(player);
3271         }
3272 }
3273
3274 static void
3275 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3276 {
3277         mm_player_t* player = NULL;
3278         MMHandleType attrs = 0;
3279         GstElement* pipeline = NULL;
3280         GstCaps* caps = NULL;
3281         gchar* caps_str = NULL;
3282         GstStructure* str = NULL;
3283         const gchar* name = NULL;
3284         GstPad* sinkpad = NULL;
3285         GstElement* sinkbin = NULL;
3286         gboolean reusing = FALSE;
3287         GstElement *text_selector = NULL;
3288
3289         /* check handles */
3290         player = (mm_player_t*) data;
3291
3292         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3293         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3294
3295         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3296
3297         attrs = MMPLAYER_GET_ATTRS(player);
3298         if (!attrs) {
3299                 LOGE("cannot get content attribute\n");
3300                 goto ERROR;
3301         }
3302
3303         /* get mimetype from caps */
3304         caps = gst_pad_query_caps(pad, NULL);
3305         if (!caps) {
3306                 LOGE("cannot get caps from pad.\n");
3307                 goto ERROR;
3308         }
3309         caps_str = gst_caps_to_string(caps);
3310
3311         str = gst_caps_get_structure(caps, 0);
3312         if (!str) {
3313                 LOGE("cannot get structure from caps.\n");
3314                 goto ERROR;
3315         }
3316
3317         name = gst_structure_get_name(str);
3318         if (!name) {
3319                 LOGE("cannot get mimetype from structure.\n");
3320                 goto ERROR;
3321         }
3322
3323         //LOGD("detected mimetype : %s\n", name);
3324
3325         if (strstr(name, "audio")) {
3326                 if (player->pipeline->audiobin == NULL) {
3327                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3328                                 LOGE("failed to create audiobin. continuing without audio\n");
3329                                 goto ERROR;
3330                         }
3331
3332                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3333                         LOGD("creating audiosink bin success\n");
3334                 } else {
3335                         reusing = TRUE;
3336                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3337                         LOGD("reusing audiobin\n");
3338                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3339                 }
3340
3341                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3342                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3343
3344                 player->audiosink_linked  = 1;
3345
3346                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3347                 if (!sinkpad) {
3348                         LOGE("failed to get pad from sinkbin\n");
3349                         goto ERROR;
3350                 }
3351         } else if (strstr(name, "video")) {
3352                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3353                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3354                         player->set_mode.video_zc = TRUE;
3355
3356                 if (player->pipeline->videobin == NULL) {
3357                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3358                         /* get video surface type */
3359                         int surface_type = 0;
3360                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3361                         LOGD("display_surface_type(%d)\n", surface_type);
3362
3363                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3364                                 LOGD("not make videobin because it dose not want\n");
3365                                 goto ERROR;
3366                         }
3367
3368                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3369                                 /* mark video overlay for acquire */
3370                                 if (player->video_overlay_resource == NULL) {
3371                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3372                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3373                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3374                                                         &player->video_overlay_resource)
3375                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3376                                                 LOGE("could not mark video_overlay resource for acquire\n");
3377                                                 goto ERROR;
3378                                         }
3379                                 }
3380                         }
3381
3382                         player->interrupted_by_resource = FALSE;
3383                         /* acquire resources for video overlay */
3384                         if (mm_resource_manager_commit(player->resource_manager) !=
3385                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3386                                 LOGE("could not acquire resources for video playing\n");
3387                                 goto ERROR;
3388                         }
3389
3390                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3391                                 LOGE("failed to create videobin. continuing without video\n");
3392                                 goto ERROR;
3393                         }
3394
3395                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3396                         LOGD("creating videosink bin success\n");
3397                 } else {
3398                         reusing = TRUE;
3399                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3400                         LOGD("re-using videobin\n");
3401                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3402                 }
3403
3404                 player->videosink_linked  = 1;
3405
3406                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3407                 if (!sinkpad) {
3408                         LOGE("failed to get pad from sinkbin\n");
3409                         goto ERROR;
3410                 }
3411         } else if (strstr(name, "text")) {
3412                 if (player->pipeline->textbin == NULL) {
3413                         MMPlayerGstElement* mainbin = NULL;
3414
3415                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3416                                 LOGE("failed to create text sink bin. continuing without text\n");
3417                                 goto ERROR;
3418                         }
3419
3420                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3421                         LOGD("creating textsink bin success\n");
3422
3423                         /* FIXIT : track number shouldn't be hardcoded */
3424                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3425
3426                         player->textsink_linked  = 1;
3427                         LOGI("player->textsink_linked set to 1\n");
3428
3429                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3430                         if (!sinkpad) {
3431                                 LOGE("failed to get pad from sinkbin\n");
3432                                 goto ERROR;
3433                         }
3434
3435                         mainbin = player->pipeline->mainbin;
3436
3437                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3438                                 /* input selector */
3439                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3440                                 if (!text_selector) {
3441                                         LOGE("failed to create subtitle input selector element\n");
3442                                         goto ERROR;
3443                                 }
3444                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3445
3446                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3447                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3448
3449                                 /* warm up */
3450                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3451                                         LOGE("failed to set state(READY) to sinkbin\n");
3452                                         goto ERROR;
3453                                 }
3454
3455                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3456                                         LOGW("failed to add subtitle input selector\n");
3457                                         goto ERROR;
3458                                 }
3459
3460                                 LOGD("created element input-selector");
3461
3462                         } else {
3463                                 LOGD("already having subtitle input selector");
3464                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3465                         }
3466                 } else {
3467                         if (!player->textsink_linked) {
3468                                 LOGD("re-using textbin\n");
3469
3470                                 reusing = TRUE;
3471                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3472
3473                                 player->textsink_linked  = 1;
3474                                 LOGI("player->textsink_linked set to 1\n");
3475                         } else
3476                                 LOGD("ignoring internal subtutle since external subtitle is available");
3477                 }
3478         } else {
3479                 LOGW("unknown type of elementary stream!ignoring it...\n");
3480                 goto ERROR;
3481         }
3482
3483         if (sinkbin) {
3484                 if (!reusing) {
3485                         /* warm up */
3486                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3487                                 LOGE("failed to set state(READY) to sinkbin\n");
3488                                 goto ERROR;
3489                         }
3490
3491                         /* Added for multi audio support to avoid adding audio bin again*/
3492                         /* add */
3493                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3494                                 LOGE("failed to add sinkbin to pipeline\n");
3495                                 goto ERROR;
3496                         }
3497                 }
3498
3499                 /* link */
3500                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3501                         LOGE("failed to get pad from sinkbin\n");
3502                         goto ERROR;
3503                 }
3504
3505                 if (!reusing) {
3506                         /* run */
3507                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3508                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3509                                 goto ERROR;
3510                         }
3511
3512                         if (text_selector) {
3513                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3514                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3515                                         goto ERROR;
3516                                 }
3517                         }
3518                 }
3519
3520                 gst_object_unref(sinkpad);
3521                 sinkpad = NULL;
3522         }
3523
3524         LOGD("[handle: %p] linking sink bin success", player);
3525
3526         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3527          * streaming task. if the task blocked, then buffer will not flow to the next element
3528          *(autoplugging element). so this is special hack for streaming. please try to remove it
3529          */
3530         /* dec stream count. we can remove fakesink if it's zero */
3531         if (player->num_dynamic_pad)
3532                 player->num_dynamic_pad--;
3533
3534         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3535
3536         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3537                 __mmplayer_pipeline_complete(NULL, player);
3538
3539 ERROR:
3540
3541         MMPLAYER_FREEIF(caps_str);
3542
3543         if (caps)
3544                 gst_caps_unref(caps);
3545
3546         if (sinkpad)
3547                 gst_object_unref(GST_OBJECT(sinkpad));
3548
3549         /* flusing out new attributes */
3550         if (mmf_attrs_commit(attrs))
3551                 LOGE("failed to comit attributes\n");
3552
3553         return;
3554 }
3555
3556 static gboolean
3557 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3558 {
3559         int pro_value = 0; // in the case of expection, default will be returned.
3560         int dest_angle = rotation_angle;
3561         int rotation_type = -1;
3562
3563         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3564         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3565         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3566
3567         if (rotation_angle >= 360)
3568                 dest_angle = rotation_angle - 360;
3569
3570         /* chech if supported or not */
3571         if (dest_angle % 90) {
3572                 LOGD("not supported rotation angle = %d", rotation_angle);
3573                 return FALSE;
3574         }
3575
3576         /*
3577           * tizenwlsink (A)
3578           * custom_convert - none (B)
3579           * videoflip - none (C)
3580           */
3581         if (player->set_mode.video_zc) {
3582                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3583                         rotation_type = ROTATION_USING_CUSTOM;
3584                 else // A
3585                         rotation_type = ROTATION_USING_SINK;
3586         } else {
3587                 int surface_type = 0;
3588                 rotation_type = ROTATION_USING_FLIP;
3589
3590                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3591                 LOGD("check display surface type attribute: %d", surface_type);
3592
3593                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3594                         rotation_type = ROTATION_USING_SINK;
3595                 else
3596                         rotation_type = ROTATION_USING_FLIP; //C
3597
3598                 LOGD("using %d type for rotation", rotation_type);
3599         }
3600
3601         /* get property value for setting */
3602         switch (rotation_type) {
3603         case ROTATION_USING_SINK: // tizenwlsink
3604                 {
3605                         switch (dest_angle) {
3606                         case 0:
3607                                 break;
3608                         case 90:
3609                                 pro_value = 3; // clockwise 90
3610                                 break;
3611                         case 180:
3612                                 pro_value = 2;
3613                                 break;
3614                         case 270:
3615                                 pro_value = 1; // counter-clockwise 90
3616                                 break;
3617                         }
3618                 }
3619                 break;
3620         case ROTATION_USING_CUSTOM:
3621                 {
3622                         gchar *ename = NULL;
3623                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3624
3625                         if (g_strrstr(ename, "fimcconvert")) {
3626                                 switch (dest_angle) {
3627                                 case 0:
3628                                         break;
3629                                 case 90:
3630                                         pro_value = 90; // clockwise 90
3631                                         break;
3632                                 case 180:
3633                                         pro_value = 180;
3634                                         break;
3635                                 case 270:
3636                                         pro_value = 270; // counter-clockwise 90
3637                                         break;
3638                                 }
3639                         }
3640                 }
3641                 break;
3642         case ROTATION_USING_FLIP: // videoflip
3643                 {
3644                                 switch (dest_angle) {
3645                                 case 0:
3646                                         break;
3647                                 case 90:
3648                                         pro_value = 1; // clockwise 90
3649                                         break;
3650                                 case 180:
3651                                         pro_value = 2;
3652                                         break;
3653                                 case 270:
3654                                         pro_value = 3; // counter-clockwise 90
3655                                         break;
3656                                 }
3657                 }
3658                 break;
3659         }
3660
3661         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3662
3663         *value = pro_value;
3664
3665         return TRUE;
3666 }
3667
3668 int
3669 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3670 {
3671         /* check video sinkbin is created */
3672         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3673                 player->pipeline &&
3674                 player->pipeline->videobin &&
3675                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3676                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3677                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3678
3679         return MM_ERROR_NONE;
3680 }
3681
3682 void
3683 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3684 {
3685         int rotation_value = 0;
3686         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3687         int user_angle = 0;
3688         MMPLAYER_FENTER();
3689
3690         /* check video sinkbin is created */
3691         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3692                 return;
3693
3694         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3695
3696         /* get rotation value to set */
3697         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3698         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3699         LOGD("set video param : rotate %d", rotation_value);
3700 }
3701
3702 void
3703 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3704 {
3705         MMHandleType attrs = 0;
3706         int visible = 0;
3707         MMPLAYER_FENTER();
3708
3709         /* check video sinkbin is created */
3710         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3711                 return;
3712
3713         attrs = MMPLAYER_GET_ATTRS(player);
3714         MMPLAYER_RETURN_IF_FAIL(attrs);
3715
3716         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3717         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3718         LOGD("set video param : visible %d", visible);
3719 }
3720
3721 void
3722 __mmplayer_video_param_set_display_method(mm_player_t* player)
3723 {
3724         MMHandleType attrs = 0;
3725         int display_method = 0;
3726         MMPLAYER_FENTER();
3727
3728         /* check video sinkbin is created */
3729         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3730                 return;
3731
3732         attrs = MMPLAYER_GET_ATTRS(player);
3733         MMPLAYER_RETURN_IF_FAIL(attrs);
3734
3735         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3736         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3737         LOGD("set video param : method %d", display_method);
3738 }
3739
3740 void
3741 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3742 {
3743         MMHandleType attrs = 0;
3744         void *handle = NULL;
3745         /*set wl_display*/
3746         int wl_window_x = 0;
3747         int wl_window_y = 0;
3748         int wl_window_width = 0;
3749         int wl_window_height = 0;
3750         MMPLAYER_FENTER();
3751
3752         /* check video sinkbin is created */
3753         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3754                 return;
3755
3756         attrs = MMPLAYER_GET_ATTRS(player);
3757         MMPLAYER_RETURN_IF_FAIL(attrs);
3758
3759         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3760
3761         if (handle) {
3762                 /*It should be set after setting window*/
3763                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3764                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3765                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3766                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3767
3768                 /* After setting window handle, set render      rectangle */
3769                 gst_video_overlay_set_render_rectangle(
3770                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3771                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3772                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3773                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3774
3775         }
3776 }
3777 void
3778 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3779 {
3780         MMHandleType attrs = 0;
3781         void *handle = NULL;
3782
3783         /* check video sinkbin is created */
3784         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3785                 return;
3786
3787         attrs = MMPLAYER_GET_ATTRS(player);
3788         MMPLAYER_RETURN_IF_FAIL(attrs);
3789
3790         /* common case if using overlay surface */
3791         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3792
3793         if (handle) {
3794                 /* default is using wl_surface_id */
3795                 unsigned int wl_surface_id      = 0;
3796                 wl_surface_id = *(int*)handle;
3797                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3798                 gst_video_overlay_set_wl_window_wl_surface_id(
3799                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3800                                 *(int*)handle);
3801         } else
3802                 /* FIXIT : is it error case? */
3803                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3804 }
3805
3806
3807 int
3808 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3809 {
3810         bool update_all_param = FALSE;
3811         MMPLAYER_FENTER();
3812
3813         /* check video sinkbin is created */
3814         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3815                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3816
3817         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3818                 LOGE("can not find tizenwlsink");
3819                 return MM_ERROR_PLAYER_INTERNAL;
3820         }
3821
3822         LOGD("param_name : %s", param_name);
3823         if (!g_strcmp0(param_name, "update_all_param"))
3824                 update_all_param = TRUE;
3825
3826         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3827                 __mmplayer_video_param_set_display_overlay(player);
3828         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3829                 __mmplayer_video_param_set_display_method(player);
3830         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3831                 __mmplayer_video_param_set_render_rectangle(player);
3832         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3833                 __mmplayer_video_param_set_display_visible(player);
3834         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3835                 __mmplayer_video_param_set_display_rotation(player);
3836
3837         return MM_ERROR_NONE;
3838 }
3839
3840 int
3841 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3842 {
3843         MMHandleType attrs = 0;
3844         int surface_type = 0;
3845         int ret = MM_ERROR_NONE;
3846
3847         MMPLAYER_FENTER();
3848
3849         /* check video sinkbin is created */
3850         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3851                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3852
3853         attrs = MMPLAYER_GET_ATTRS(player);
3854         if (!attrs) {
3855                 LOGE("cannot get content attribute");
3856                 return MM_ERROR_PLAYER_INTERNAL;
3857         }
3858         LOGD("param_name : %s", param_name);
3859
3860         /* update display surface */
3861         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3862         LOGD("check display surface type attribute: %d", surface_type);
3863
3864         /* configuring display */
3865         switch (surface_type) {
3866         case MM_DISPLAY_SURFACE_OVERLAY:
3867                 {
3868                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3869                         if (ret != MM_ERROR_NONE)
3870                                 return ret;
3871                 }
3872                 break;
3873         }
3874
3875         MMPLAYER_FLEAVE();
3876
3877         return MM_ERROR_NONE;
3878 }
3879
3880 int
3881 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3882 {
3883         gboolean disable_overlay = FALSE;
3884         mm_player_t* player = (mm_player_t*) hplayer;
3885         int ret = MM_ERROR_NONE;
3886
3887         MMPLAYER_FENTER();
3888         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3889         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3890                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3891                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3892
3893         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3894                 LOGW("Display control is not supported");
3895                 return MM_ERROR_PLAYER_INTERNAL;
3896         }
3897
3898         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3899
3900         if (audio_only == (bool)disable_overlay) {
3901                 LOGE("It's the same with current setting: (%d)", audio_only);
3902                 return MM_ERROR_NONE;
3903         }
3904
3905         if (audio_only) {
3906                 LOGE("disable overlay");
3907                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3908
3909                 /* release overlay resource */
3910                 if (player->video_overlay_resource != NULL) {
3911                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3912                                         player->video_overlay_resource);
3913                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3914                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3915                                 goto ERROR;
3916                         }
3917                         player->video_overlay_resource = NULL;
3918                 }
3919
3920                 ret = mm_resource_manager_commit(player->resource_manager);
3921                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3922                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3923                         goto ERROR;
3924                 }
3925         } else {
3926                 /* mark video overlay for acquire */
3927                 if (player->video_overlay_resource == NULL) {
3928                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3929                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3930                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3931                                         &player->video_overlay_resource);
3932                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3933                                 LOGE("could not prepare for video_overlay resource\n");
3934                                 goto ERROR;
3935                         }
3936                 }
3937
3938                 player->interrupted_by_resource = FALSE;
3939                 /* acquire resources for video overlay */
3940                 ret = mm_resource_manager_commit(player->resource_manager);
3941                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3942                         LOGE("could not acquire resources for video playing\n");
3943                         goto ERROR;
3944                 }
3945
3946                 LOGD("enable overlay");
3947                 __mmplayer_video_param_set_display_overlay(player);
3948                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3949         }
3950
3951 ERROR:
3952         MMPLAYER_FLEAVE();
3953         return MM_ERROR_NONE;
3954 }
3955
3956 int
3957 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3958 {
3959         mm_player_t* player = (mm_player_t*) hplayer;
3960         gboolean disable_overlay = FALSE;
3961
3962         MMPLAYER_FENTER();
3963
3964         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3965         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3966         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3967                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3968                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3969
3970         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3971                 LOGW("Display control is not supported");
3972                 return MM_ERROR_PLAYER_INTERNAL;
3973         }
3974
3975         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3976
3977         *paudio_only = (bool)(disable_overlay);
3978
3979         LOGD("audio_only : %d", *paudio_only);
3980
3981         MMPLAYER_FLEAVE();
3982
3983         return MM_ERROR_NONE;
3984 }
3985
3986 static int
3987 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3988 {
3989         GList* bucket = element_bucket;
3990         MMPlayerGstElement* element = NULL;
3991         MMPlayerGstElement* prv_element = NULL;
3992         gint successful_link_count = 0;
3993
3994         MMPLAYER_FENTER();
3995
3996         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3997
3998         prv_element = (MMPlayerGstElement*)bucket->data;
3999         bucket = bucket->next;
4000
4001         for (; bucket; bucket = bucket->next) {
4002                 element = (MMPlayerGstElement*)bucket->data;
4003
4004                 if (element && element->gst) {
4005                         /* If next element is audio appsrc then make a separate audio pipeline */
4006                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4007                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4008                                 prv_element = element;
4009                                 continue;
4010                         }
4011
4012                         if (prv_element && prv_element->gst) {
4013                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4014                                         LOGD("linking [%s] to [%s] success\n",
4015                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4017                                         successful_link_count++;
4018                                 } else {
4019                                         LOGD("linking [%s] to [%s] failed\n",
4020                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4021                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4022                                         return -1;
4023                                 }
4024                         }
4025                 }
4026
4027                 prv_element = element;
4028         }
4029
4030         MMPLAYER_FLEAVE();
4031
4032         return successful_link_count;
4033 }
4034
4035 static int
4036 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4037 {
4038         GList* bucket = element_bucket;
4039         MMPlayerGstElement* element = NULL;
4040         int successful_add_count = 0;
4041
4042         MMPLAYER_FENTER();
4043
4044         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4045         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4046
4047         for (; bucket; bucket = bucket->next) {
4048                 element = (MMPlayerGstElement*)bucket->data;
4049
4050                 if (element && element->gst) {
4051                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4052                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4053                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4054                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4055                                 return 0;
4056                         }
4057                         successful_add_count++;
4058                 }
4059         }
4060
4061         MMPLAYER_FLEAVE();
4062
4063         return successful_add_count;
4064 }
4065
4066 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4067 {
4068         mm_player_t* player = (mm_player_t*) data;
4069         GstCaps *caps = NULL;
4070         GstStructure *str = NULL;
4071         const char *name;
4072
4073         MMPLAYER_FENTER();
4074
4075         MMPLAYER_RETURN_IF_FAIL(pad)
4076         MMPLAYER_RETURN_IF_FAIL(unused)
4077         MMPLAYER_RETURN_IF_FAIL(data)
4078
4079         caps = gst_pad_get_current_caps(pad);
4080         if (!caps)
4081                 return;
4082
4083         str = gst_caps_get_structure(caps, 0);
4084         if (!str)
4085                 goto ERROR;
4086
4087         name = gst_structure_get_name(str);
4088         if (!name)
4089                 goto ERROR;
4090
4091         LOGD("name = %s\n", name);
4092
4093         if (strstr(name, "audio")) {
4094                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4095
4096                 if (player->audio_stream_changed_cb) {
4097                         LOGE("call the audio stream changed cb\n");
4098                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4099                 }
4100         } else if (strstr(name, "video")) {
4101                 if ((name = gst_structure_get_string(str, "format")))
4102                         player->set_mode.video_zc = name[0] == 'S';
4103
4104                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4105
4106                 if (player->video_stream_changed_cb) {
4107                         LOGE("call the video stream changed cb\n");
4108                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4109                 }
4110         } else
4111                 goto ERROR;
4112
4113 ERROR:
4114
4115         gst_caps_unref(caps);
4116
4117         MMPLAYER_FLEAVE();
4118
4119         return;
4120 }
4121
4122
4123
4124 /**
4125  * This function is to create audio pipeline for playing.
4126  *
4127  * @param       player          [in]    handle of player
4128  *
4129  * @return      This function returns zero on success.
4130  * @remark
4131  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4132  */
4133 /* macro for code readability. just for sinkbin-creation functions */
4134 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4135 do {\
4136         x_bin[x_id].id = x_id;\
4137         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4138         if (!x_bin[x_id].gst) {\
4139                 LOGE("failed to create %s \n", x_factory);\
4140                 goto ERROR;\
4141         } else {\
4142                 if (x_player->ini.set_dump_element_flag)\
4143                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4144         } \
4145         if (x_add_bucket)\
4146                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4147 } while (0);
4148
4149 static void
4150 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4151 {
4152         GList *l = NULL;
4153
4154         MMPLAYER_FENTER();
4155         MMPLAYER_RETURN_IF_FAIL(player);
4156
4157         if (player->audio_stream_buff_list) {
4158                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4159                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4160                         if (tmp) {
4161                                 if (send_all) {
4162                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4163                                         __mmplayer_audio_stream_send_data(player, tmp);
4164                                 }
4165                                 if (tmp->pcm_data)
4166                                         g_free(tmp->pcm_data);
4167                                 g_free(tmp);
4168                         }
4169                 }
4170                 g_list_free(player->audio_stream_buff_list);
4171                 player->audio_stream_buff_list = NULL;
4172         }
4173
4174         MMPLAYER_FLEAVE();
4175 }
4176
4177 static void
4178 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4179 {
4180         MMPlayerAudioStreamDataType audio_stream = { 0, };
4181
4182         MMPLAYER_FENTER();
4183         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4184
4185         audio_stream.bitrate = a_buffer->bitrate;
4186         audio_stream.channel = a_buffer->channel;
4187         audio_stream.depth = a_buffer->depth;
4188         audio_stream.is_little_endian = a_buffer->is_little_endian;
4189         audio_stream.channel_mask = a_buffer->channel_mask;
4190         audio_stream.data_size = a_buffer->data_size;
4191         audio_stream.data = a_buffer->pcm_data;
4192
4193         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4194         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4195
4196         MMPLAYER_FLEAVE();
4197 }
4198
4199 static void
4200 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4201 {
4202         mm_player_t* player = (mm_player_t*) data;
4203
4204         gint channel = 0;
4205         gint rate = 0;
4206         gint depth = 0;
4207         gint endianness = 0;
4208         guint64 channel_mask = 0;
4209         void *a_data = NULL;
4210         gint a_size = 0;
4211         mm_player_audio_stream_buff_t *a_buffer = NULL;
4212         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4213         GList *l = NULL;
4214
4215         MMPLAYER_FENTER();
4216         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4217
4218         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4219         a_data = mapinfo.data;
4220         a_size = mapinfo.size;
4221
4222         GstCaps *caps = gst_pad_get_current_caps(pad);
4223         GstStructure *structure = gst_caps_get_structure(caps, 0);
4224
4225         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4226         gst_structure_get_int(structure, "rate", &rate);
4227         gst_structure_get_int(structure, "channels", &channel);
4228         gst_structure_get_int(structure, "depth", &depth);
4229         gst_structure_get_int(structure, "endianness", &endianness);
4230         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4231         gst_caps_unref(GST_CAPS(caps));
4232
4233         /* In case of the sync is false, use buffer list.              *
4234          * The num of buffer list depends on the num of audio channels */
4235         if (player->audio_stream_buff_list) {
4236                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4237                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4238                         if (tmp) {
4239                                 if (channel_mask == tmp->channel_mask) {
4240                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4241                                         if (tmp->data_size + a_size < tmp->buff_size) {
4242                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4243                                                 tmp->data_size += a_size;
4244                                         } else {
4245                                                 /* send data to client */
4246                                                 __mmplayer_audio_stream_send_data(player, tmp);
4247
4248                                                 if (a_size > tmp->buff_size) {
4249                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4250                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4251                                                         if (tmp->pcm_data == NULL) {
4252                                                                 LOGE("failed to realloc data.");
4253                                                                 goto DONE;
4254                                                         }
4255                                                         tmp->buff_size = a_size;
4256                                                 }
4257                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4258                                                 memcpy(tmp->pcm_data, a_data, a_size);
4259                                                 tmp->data_size = a_size;
4260                                         }
4261                                         goto DONE;
4262                                 }
4263                         } else {
4264                                 LOGE("data is empty in list.");
4265                                 goto DONE;
4266                         }
4267                 }
4268         }
4269
4270         /* create new audio stream data */
4271         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4272         if (a_buffer == NULL) {
4273                 LOGE("failed to alloc data.");
4274                 goto DONE;
4275         }
4276         a_buffer->bitrate = rate;
4277         a_buffer->channel = channel;
4278         a_buffer->depth = depth;
4279         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4280         a_buffer->channel_mask = channel_mask;
4281         a_buffer->data_size = a_size;
4282
4283         if (!player->audio_stream_sink_sync) {
4284                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4285                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4286                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4287                 if (a_buffer->pcm_data == NULL) {
4288                         LOGE("failed to alloc data.");
4289                         g_free(a_buffer);
4290                         goto DONE;
4291                 }
4292                 memcpy(a_buffer->pcm_data, a_data, a_size);
4293                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4294                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4295         } else {
4296                 /* If sync is TRUE, send data directly. */
4297                 a_buffer->pcm_data = a_data;
4298                 __mmplayer_audio_stream_send_data(player, a_buffer);
4299                 g_free(a_buffer);
4300         }
4301
4302 DONE:
4303         gst_buffer_unmap(buffer, &mapinfo);
4304         MMPLAYER_FLEAVE();
4305 }
4306
4307 static void
4308 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4309 {
4310         mm_player_t* player = (mm_player_t*)data;
4311         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4312         GstPad* sinkpad = NULL;
4313         GstElement *queue = NULL, *sink = NULL;
4314
4315         MMPLAYER_FENTER();
4316         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4317
4318         queue = gst_element_factory_make("queue", NULL);
4319         if (queue == NULL) {
4320                 LOGD("fail make queue\n");
4321                 goto ERROR;
4322         }
4323
4324         sink = gst_element_factory_make("fakesink", NULL);
4325         if (sink == NULL) {
4326                 LOGD("fail make fakesink\n");
4327                 goto ERROR;
4328         }
4329
4330         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4331
4332         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4333                 LOGW("failed to link queue & sink\n");
4334                 goto ERROR;
4335         }
4336
4337         sinkpad = gst_element_get_static_pad(queue, "sink");
4338
4339         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4340                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4341                 goto ERROR;
4342         }
4343
4344         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4345
4346         gst_object_unref(sinkpad);
4347         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4348         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4349
4350         gst_element_set_state(sink, GST_STATE_PAUSED);
4351         gst_element_set_state(queue, GST_STATE_PAUSED);
4352
4353         MMPLAYER_SIGNAL_CONNECT(player,
4354                 G_OBJECT(sink),
4355                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4356                 "handoff",
4357                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4358                 (gpointer)player);
4359
4360         MMPLAYER_FLEAVE();
4361         return;
4362
4363 ERROR:
4364         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4365         if (queue) {
4366                 gst_object_unref(GST_OBJECT(queue));
4367                 queue = NULL;
4368         }
4369         if (sink) {
4370                 gst_object_unref(GST_OBJECT(sink));
4371                 sink = NULL;
4372         }
4373         if (sinkpad) {
4374                 gst_object_unref(GST_OBJECT(sinkpad));
4375                 sinkpad = NULL;
4376         }
4377
4378         return;
4379 }
4380
4381 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4382 {
4383         #define MAX_PROPS_LEN 128
4384         gint latency_mode = 0;
4385         gchar *stream_type = NULL;
4386         gchar *latency = NULL;
4387         gint stream_id = 0;
4388         gchar stream_props[MAX_PROPS_LEN] = {0,};
4389         GstStructure *props = NULL;
4390
4391         /* set volume table
4392          * It should be set after player creation through attribute.
4393          * But, it can not be changed during playing.
4394          */
4395         MMPLAYER_FENTER();
4396         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4397         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4398
4399         if (!stream_type) {
4400                 LOGE("stream_type is null.\n");
4401         } else {
4402                 if (player->sound.focus_id)
4403                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4404                                         stream_type, stream_id, player->sound.focus_id);
4405                 else
4406                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4407                                         stream_type, stream_id);
4408                 props = gst_structure_from_string(stream_props, NULL);
4409                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4410                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4411                         stream_type, stream_id, player->sound.focus_id, stream_props);
4412                 gst_structure_free(props);
4413         }
4414
4415         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4416
4417         switch (latency_mode) {
4418         case AUDIO_LATENCY_MODE_LOW:
4419                 latency = g_strndup("low", 3);
4420                 break;
4421         case AUDIO_LATENCY_MODE_MID:
4422                 latency = g_strndup("mid", 3);
4423                 break;
4424         case AUDIO_LATENCY_MODE_HIGH:
4425                 latency = g_strndup("high", 4);
4426                 break;
4427         };
4428
4429         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4430                         "latency", latency,
4431                         NULL);
4432
4433         LOGD("audiosink property - latency=%s \n", latency);
4434
4435         g_free(latency);
4436
4437         MMPLAYER_FLEAVE();
4438 }
4439
4440 static int
4441 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4442 {
4443         MMPlayerGstElement* first_element = NULL;
4444         MMPlayerGstElement* audiobin = NULL;
4445         MMHandleType attrs = 0;
4446         GstPad *pad = NULL;
4447         GstPad *ghostpad = NULL;
4448         GList* element_bucket = NULL;
4449         gboolean link_audio_sink_now = TRUE;
4450         int i = 0;
4451         GstCaps *acaps;
4452
4453         MMPLAYER_FENTER();
4454
4455         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4456
4457         /* alloc handles */
4458         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4459         if (!audiobin) {
4460                 LOGE("failed to allocate memory for audiobin\n");
4461                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4462         }
4463
4464         attrs = MMPLAYER_GET_ATTRS(player);
4465
4466         /* create bin */
4467         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4468         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4469         if (!audiobin[MMPLAYER_A_BIN].gst) {
4470                 LOGE("failed to create audiobin\n");
4471                 goto ERROR;
4472         }
4473
4474         /* take it */
4475         player->pipeline->audiobin = audiobin;
4476
4477         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4478
4479         /* Adding audiotp plugin for reverse trickplay feature */
4480 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4481
4482         /* converter */
4483         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4484
4485         /* replaygain volume */
4486         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4487         if (player->sound.rg_enable)
4488                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4489         else
4490                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4491
4492         /* resampler */
4493         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4494
4495         if (player->set_mode.pcm_extraction) {
4496                 // pcm extraction only and no sound output
4497                 if (player->audio_stream_render_cb_ex) {
4498                         char *caps_str = NULL;
4499                         GstCaps* caps = NULL;
4500                         gchar *format = NULL;
4501
4502                         /* capsfilter */
4503                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4504
4505                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4506
4507                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4508
4509                         caps = gst_caps_new_simple("audio/x-raw",
4510                                         "format", G_TYPE_STRING, format,
4511                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4512                                         "channels", G_TYPE_INT, player->pcm_channel,
4513                                         NULL);
4514                         caps_str = gst_caps_to_string(caps);
4515                         LOGD("new caps : %s\n", caps_str);
4516
4517                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4518
4519                         /* clean */
4520                         gst_caps_unref(caps);
4521                         MMPLAYER_FREEIF(caps_str);
4522
4523                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4524
4525                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4526                         /* raw pad handling signal */
4527                         MMPLAYER_SIGNAL_CONNECT(player,
4528                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4529                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4530                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4531                 } else {
4532                         int dst_samplerate = 0;
4533                         int dst_channels = 0;
4534                         int dst_depth = 0;
4535                         char *caps_str = NULL;
4536                         GstCaps* caps = NULL;
4537
4538                         /* get conf. values */
4539                         mm_attrs_multiple_get(player->attrs,
4540                                                 NULL,
4541                                                 "pcm_extraction_samplerate", &dst_samplerate,
4542                                                 "pcm_extraction_channels", &dst_channels,
4543                                                 "pcm_extraction_depth", &dst_depth,
4544                                                 NULL);
4545
4546                         /* capsfilter */
4547                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4548                         caps = gst_caps_new_simple("audio/x-raw",
4549                                         "rate", G_TYPE_INT, dst_samplerate,
4550                                         "channels", G_TYPE_INT, dst_channels,
4551                                         "depth", G_TYPE_INT, dst_depth,
4552                                         NULL);
4553                         caps_str = gst_caps_to_string(caps);
4554                         LOGD("new caps : %s\n", caps_str);
4555
4556                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4557
4558                         /* clean */
4559                         gst_caps_unref(caps);
4560                         MMPLAYER_FREEIF(caps_str);
4561
4562                         /* fake sink */
4563                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4564
4565                         /* set sync */
4566                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4567                 }
4568         } else {
4569                 // normal playback
4570                 //GstCaps* caps = NULL;
4571                 gint channels = 0;
4572
4573                 /* for logical volume control */
4574                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4575                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4576
4577                 if (player->sound.mute) {
4578                         LOGD("mute enabled\n");
4579                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4580                 }
4581
4582 #if 0
4583                 /*capsfilter */
4584                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4585                 caps = gst_caps_from_string("audio/x-raw-int, "
4586                                         "endianness = (int) LITTLE_ENDIAN, "
4587                                         "signed = (boolean) true, "
4588                                         "width = (int) 16, "
4589                                         "depth = (int) 16");
4590                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4591                 gst_caps_unref(caps);
4592 #endif
4593
4594                 /* check if multi-channels */
4595                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4596                         GstPad *srcpad = NULL;
4597                         GstCaps *caps = NULL;
4598
4599                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4600                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4601                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4602                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4603                                         if (str)
4604                                                 gst_structure_get_int(str, "channels", &channels);
4605                                         gst_caps_unref(caps);
4606                                 }
4607                                 gst_object_unref(srcpad);
4608                         }
4609                 }
4610
4611                 /* audio effect element. if audio effect is enabled */
4612                 if ((strcmp(player->ini.audioeffect_element, ""))
4613                         && (channels <= 2)
4614                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4615                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4616
4617                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4618
4619                         if ((!player->bypass_audio_effect)
4620                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4621                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4622                                         if (!_mmplayer_audio_effect_custom_apply(player))
4623                                                 LOGI("apply audio effect(custom) setting success\n");
4624                                 }
4625                         }
4626
4627                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4628                                 && (player->set_mode.rich_audio))
4629                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4630                 }
4631
4632                 /* create audio sink */
4633                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4634                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4635                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4636
4637                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4638                 if (player->is_360_feature_enabled &&
4639                         player->is_content_spherical &&
4640                         channels == 4 &&
4641                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4642                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4643                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4644
4645                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4646
4647                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4648
4649                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4650                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4651                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4652                         gst_caps_unref(acaps);
4653
4654                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4655                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4656                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4657                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4658
4659                         player->is_openal_plugin_used = TRUE;
4660
4661                         if (player->video360_yaw_radians <= M_PI &&
4662                                         player->video360_yaw_radians >= -M_PI &&
4663                                         player->video360_pitch_radians <= M_PI_2 &&
4664                                         player->video360_pitch_radians >= -M_PI_2) {
4665                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4666                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4667                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4668                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4669                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4670                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4671                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4672                         }
4673                 } else {
4674                         if (player->is_360_feature_enabled && player->is_content_spherical)
4675                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4676                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4677                 }
4678
4679                 /* qos on */
4680                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4681                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4682
4683
4684                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4685                         (player->videodec_linked && player->ini.use_system_clock)) {
4686                         LOGD("system clock will be used.\n");
4687                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4688                 }
4689
4690                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4691                         __mmplayer_gst_set_audiosink_property(player, attrs);
4692         }
4693
4694         if (audiobin[MMPLAYER_A_SINK].gst) {
4695                 GstPad *sink_pad = NULL;
4696                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4697                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4698                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4699                 gst_object_unref(GST_OBJECT(sink_pad));
4700         }
4701
4702         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4703
4704         /* adding created elements to bin */
4705         LOGD("adding created elements to bin\n");
4706         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4707                 LOGE("failed to add elements\n");
4708                 goto ERROR;
4709         }
4710
4711         /* linking elements in the bucket by added order. */
4712         LOGD("Linking elements in the bucket by added order.\n");
4713         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4714                 LOGE("failed to link elements\n");
4715                 goto ERROR;
4716         }
4717
4718         /* get first element's sinkpad for creating ghostpad */
4719         first_element = (MMPlayerGstElement *)element_bucket->data;
4720         if (!first_element) {
4721                 LOGE("failed to get first elem\n");
4722                 goto ERROR;
4723         }
4724
4725         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4726         if (!pad) {
4727                 LOGE("failed to get pad from first element of audiobin\n");
4728                 goto ERROR;
4729         }
4730
4731         ghostpad = gst_ghost_pad_new("sink", pad);
4732         if (!ghostpad) {
4733                 LOGE("failed to create ghostpad\n");
4734                 goto ERROR;
4735         }
4736
4737         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4738                 LOGE("failed to add ghostpad to audiobin\n");
4739                 goto ERROR;
4740         }
4741
4742         gst_object_unref(pad);
4743
4744         g_list_free(element_bucket);
4745         MMPLAYER_FLEAVE();
4746
4747         return MM_ERROR_NONE;
4748
4749 ERROR:
4750
4751         LOGD("ERROR : releasing audiobin\n");
4752
4753         if (pad)
4754                 gst_object_unref(GST_OBJECT(pad));
4755
4756         if (ghostpad)
4757                 gst_object_unref(GST_OBJECT(ghostpad));
4758
4759         if (element_bucket)
4760                 g_list_free(element_bucket);
4761
4762         /* release element which are not added to bin */
4763         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4764                 /* NOTE : skip bin */
4765                 if (audiobin[i].gst) {
4766                         GstObject* parent = NULL;
4767                         parent = gst_element_get_parent(audiobin[i].gst);
4768
4769                         if (!parent) {
4770                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4771                                 audiobin[i].gst = NULL;
4772                         } else
4773                                 gst_object_unref(GST_OBJECT(parent));
4774                 }
4775         }
4776
4777         /* release audiobin with it's childs */
4778         if (audiobin[MMPLAYER_A_BIN].gst)
4779                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4780
4781         MMPLAYER_FREEIF(audiobin);
4782
4783         player->pipeline->audiobin = NULL;
4784
4785         return MM_ERROR_PLAYER_INTERNAL;
4786 }
4787
4788 static GstPadProbeReturn
4789 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4790 {
4791         mm_player_t* player = (mm_player_t*) u_data;
4792         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4793         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4794
4795         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4796
4797         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4798                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4799
4800         return GST_PAD_PROBE_OK;
4801 }
4802
4803 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4804 {
4805         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4806 }
4807
4808 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4809 {
4810         int ret = MM_ERROR_NONE;
4811         GList *l = NULL;
4812         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4813         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4814
4815         MMPLAYER_VIDEO_BO_LOCK(player);
4816
4817         if (player->video_bo_list) {
4818                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4819                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4820                         if (tmp && tmp->bo == bo) {
4821                                 tmp->using = FALSE;
4822                                 LOGD("release bo %p", bo);
4823                                 tbm_bo_unref(tmp->bo);
4824                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4825                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4826                                 return ret;
4827                         }
4828                 }
4829         } else {
4830                 /* hw codec is running or the list was reset for DRC. */
4831                 LOGW("there is no bo list.");
4832         }
4833         MMPLAYER_VIDEO_BO_UNLOCK(player);
4834
4835         LOGW("failed to find bo %p", bo);
4836         return ret;
4837 }
4838
4839 static void
4840 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4841 {
4842         GList *l = NULL;
4843
4844         MMPLAYER_FENTER();
4845         MMPLAYER_RETURN_IF_FAIL(player);
4846
4847         MMPLAYER_VIDEO_BO_LOCK(player);
4848         if (player->video_bo_list) {
4849                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4850                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4851                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4852                         if (tmp) {
4853                                 if (tmp->bo)
4854                                         tbm_bo_unref(tmp->bo);
4855                                 g_free(tmp);
4856                         }
4857                 }
4858                 g_list_free(player->video_bo_list);
4859                 player->video_bo_list = NULL;
4860         }
4861         player->video_bo_size = 0;
4862         MMPLAYER_VIDEO_BO_UNLOCK(player);
4863
4864         MMPLAYER_FLEAVE();
4865         return;
4866 }
4867
4868 static void*
4869 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4870 {
4871         GList *l = NULL;
4872         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4873         gboolean ret = TRUE;
4874
4875         /* check DRC, if it is, destroy the prev bo list to create again */
4876         if (player->video_bo_size != size) {
4877                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4878                 __mmplayer_video_stream_destroy_bo_list(player);
4879                 player->video_bo_size = size;
4880         }
4881
4882         MMPLAYER_VIDEO_BO_LOCK(player);
4883
4884         if ((!player->video_bo_list) ||
4885                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4886
4887                 /* create bo list */
4888                 int idx = 0;
4889                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4890
4891                 if (player->video_bo_list) {
4892                         /* if bo list did not created all, try it again. */
4893                         idx = g_list_length(player->video_bo_list);
4894                         LOGD("bo list exist(len: %d)", idx);
4895                 }
4896
4897                 for (; idx < player->ini.num_of_video_bo; idx++) {
4898                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4899                         if (!bo_info) {
4900                                 LOGE("Fail to alloc bo_info.");
4901                                 break;
4902                         }
4903                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4904                         if (!bo_info->bo) {
4905                                 LOGE("Fail to tbm_bo_alloc.");
4906                                 g_free(bo_info);
4907                                 break;
4908                         }
4909                         bo_info->using = FALSE;
4910                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4911                 }
4912
4913                 /* update video num buffers */
4914                 player->video_num_buffers = idx;
4915                 if (idx == player->ini.num_of_video_bo)
4916                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4917
4918                 if (idx == 0) {
4919                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4920                         return NULL;
4921                 }
4922
4923                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4924         }
4925
4926         while (TRUE) {
4927                 /* get bo from list*/
4928                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4929                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4930                         if (tmp && (tmp->using == FALSE)) {
4931                                 LOGD("found bo %p to use", tmp->bo);
4932                                 tmp->using = TRUE;
4933                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4934                                 return tbm_bo_ref(tmp->bo);
4935                         }
4936                 }
4937                 if (!ret) {
4938                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4939                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4940                         return NULL;
4941                 }
4942
4943                 if (player->ini.video_bo_timeout <= 0) {
4944                         MMPLAYER_VIDEO_BO_WAIT(player);
4945                 } else {
4946                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4947                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4948                 }
4949                 continue;
4950         }
4951 }
4952
4953 static void
4954 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4955 {
4956         mm_player_t* player = (mm_player_t*)data;
4957         MMPLAYER_FENTER();
4958         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4959
4960         /* send prerolled pkt */
4961         player->video_stream_prerolled = FALSE;
4962
4963         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4964
4965         /* not to send prerolled pkt again */
4966         player->video_stream_prerolled = TRUE;
4967 }
4968
4969 static void
4970 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4971 {
4972         mm_player_t* player = (mm_player_t*)data;
4973         GstCaps *caps = NULL;
4974         MMPlayerVideoStreamDataType *stream = NULL;
4975         MMVideoBuffer *video_buffer = NULL;
4976         GstMemory *dataBlock = NULL;
4977         GstMemory *metaBlock = NULL;
4978         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4979         GstStructure *structure = NULL;
4980         const gchar *string_format = NULL;
4981         unsigned int fourcc = 0;
4982
4983         MMPLAYER_FENTER();
4984         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4985
4986         if (player->video_stream_prerolled) {
4987                 player->video_stream_prerolled = FALSE;
4988                 LOGD("skip the prerolled pkt not to send it again");
4989                 return;
4990         }
4991
4992         caps = gst_pad_get_current_caps(pad);
4993         if (caps == NULL) {
4994                 LOGE("Caps is NULL.");
4995                 return;
4996         }
4997
4998         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4999
5000         /* clear stream data structure */
5001         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5002         if (!stream) {
5003                 LOGE("failed to alloc mem for video data");
5004                 return;
5005         }
5006
5007         structure = gst_caps_get_structure(caps, 0);
5008         gst_structure_get_int(structure, "width", &(stream->width));
5009         gst_structure_get_int(structure, "height", &(stream->height));
5010         string_format = gst_structure_get_string(structure, "format");
5011         if (string_format)
5012                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5013         stream->format = util_get_pixtype(fourcc);
5014         gst_caps_unref(caps);
5015         caps = NULL;
5016
5017     /*
5018         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5019                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5020     */
5021
5022         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5023                 LOGE("Wrong condition!!");
5024                 goto ERROR;
5025         }
5026
5027         /* set size and timestamp */
5028         dataBlock = gst_buffer_peek_memory(buffer, 0);
5029         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5030         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5031
5032         /* check zero-copy */
5033         if (player->set_mode.video_zc &&
5034                 player->set_mode.media_packet_video_stream &&
5035                 gst_buffer_n_memory(buffer) > 1) {
5036                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5037                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5038                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5039         }
5040
5041         if (video_buffer) { /* hw codec */
5042                 /* set tbm bo */
5043                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5044                         int i = 0;
5045
5046                         /* copy pointer of tbm bo, stride, elevation */
5047                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5048                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5049                                 i++;
5050                         }
5051                 } else {
5052                         LOGE("Not support video buffer format");
5053                         goto ERROR;
5054                 }
5055                 memcpy(stream->stride, video_buffer->stride_width,
5056                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5057                 memcpy(stream->elevation, video_buffer->stride_height,
5058                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5059
5060                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5061                 stream->internal_buffer = gst_buffer_ref(buffer);
5062         } else { /* sw codec */
5063                 int i = 0;
5064                 int j = 0;
5065                 int k = 0;
5066                 int ret = TBM_SURFACE_ERROR_NONE;
5067                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5068                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5069                 int size = 0;
5070                 unsigned char *src = NULL;
5071                 unsigned char *dest = NULL;
5072                 tbm_bo_handle thandle;
5073                 tbm_surface_h surface;
5074                 tbm_surface_info_s info;
5075                 gboolean gst_ret;
5076
5077                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5078                 if (!gst_ret) {
5079                         LOGE("fail to gst_memory_map");
5080                         goto ERROR;
5081                 }
5082
5083
5084                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5085                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5086
5087                         ret = tbm_surface_get_info(surface, &info);
5088
5089                         if (ret != TBM_SURFACE_ERROR_NONE) {
5090                                 tbm_surface_destroy(surface);
5091                                 goto ERROR;
5092                         }
5093                         tbm_surface_destroy(surface);
5094
5095                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5096                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5097                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5098                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5099                         stream->stride[0] = info.planes[0].stride;
5100                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5101                         stream->stride[1] = info.planes[1].stride;
5102                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5103                         stream->stride[2] = info.planes[2].stride;
5104                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5105                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5106                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5107                         stream->stride[0] = stream->width * 4;
5108                         stream->elevation[0] = stream->height;
5109                         size = stream->stride[0] * stream->height;
5110                 } else {
5111                         LOGE("Not support format %d", stream->format);
5112                         goto ERROR;
5113                 }
5114
5115                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5116                 if (!stream->bo[0]) {
5117                         LOGE("Fail to tbm_bo_alloc!!");
5118                         goto ERROR;
5119                 }
5120
5121                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5122                 if (thandle.ptr && mapinfo.data) {
5123                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5124                                 for (i = 0; i < 3; i++) {
5125                                         src = mapinfo.data + src_offset[i];
5126                                         dest = thandle.ptr + info.planes[i].offset;
5127
5128                                         if (i > 0) k = 1;
5129                                         for (j = 0; j < stream->height>>k; j++) {
5130                                                 memcpy(dest, src, stream->width>>k);
5131                                                 src += src_stride[i];
5132                                                 dest += stream->stride[i];
5133                                         }
5134                                 }
5135                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5136                                 memcpy(thandle.ptr, mapinfo.data, size);
5137                         } else {
5138                                 LOGE("Not support format %d", stream->format);
5139                                 goto ERROR;
5140                         }
5141                 } else {
5142                         LOGE("data pointer is wrong. dest : %p, src : %p",
5143                                         thandle.ptr, mapinfo.data);
5144                         goto ERROR;
5145                 }
5146                 tbm_bo_unmap(stream->bo[0]);
5147         }
5148
5149         if (player->video_stream_cb) { /* This has been already checked at the entry */
5150                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5151                         LOGE("failed to send video stream data.");
5152                         goto ERROR;
5153                 }
5154         }
5155
5156         if (metaBlock)
5157                 gst_memory_unmap(metaBlock, &mapinfo);
5158         else
5159                 gst_memory_unmap(dataBlock, &mapinfo);
5160
5161         return;
5162
5163 ERROR:
5164         LOGE("release video stream resource.");
5165         if (metaBlock) {
5166                 int i = 0;
5167                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5168                         if (stream->bo[i])
5169                                 tbm_bo_unref(stream->bo[i]);
5170                 }
5171                 gst_memory_unmap(metaBlock, &mapinfo);
5172
5173                 /* unref gst buffer */
5174                 if (stream->internal_buffer)
5175                         gst_buffer_unref(stream->internal_buffer);
5176         } else if (dataBlock) {
5177                 if (stream->bo[0])
5178                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5179                 gst_memory_unmap(dataBlock, &mapinfo);
5180         }
5181
5182         g_free(stream);
5183         return;
5184 }
5185
5186 static int
5187 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5188 {
5189         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5190         GList* element_bucket = NULL;
5191
5192         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5193
5194         MMPLAYER_FENTER();
5195
5196         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5197                 LOGD("do not need to add video filters.");
5198                 return MM_ERROR_NONE;
5199         }
5200
5201         /* in case of sw codec except 360 playback,
5202          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5203         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5204         LOGD("using video converter: %s", video_csc);
5205
5206         /* set video rotator */
5207         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5208
5209         *bucket = element_bucket;
5210         MMPLAYER_FLEAVE();
5211         return MM_ERROR_NONE;
5212
5213 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5214         g_list_free(element_bucket);
5215
5216         *bucket = NULL;
5217         MMPLAYER_FLEAVE();
5218         return MM_ERROR_PLAYER_INTERNAL;
5219 }
5220
5221 /**
5222  * This function is to create video pipeline.
5223  *
5224  * @param       player          [in]    handle of player
5225  *              caps            [in]    src caps of decoder
5226  *              surface_type    [in]    surface type for video rendering
5227  *
5228  * @return      This function returns zero on success.
5229  * @remark
5230  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5231  */
5232 /**
5233   * VIDEO PIPELINE
5234   * - video overlay surface(arm/x86) : tizenwlsink
5235   */
5236 static int
5237 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5238 {
5239         GstPad *pad = NULL;
5240         MMHandleType attrs;
5241         GList*element_bucket = NULL;
5242         MMPlayerGstElement* first_element = NULL;
5243         MMPlayerGstElement* videobin = NULL;
5244         gchar *videosink_element = NULL;
5245
5246         MMPLAYER_FENTER();
5247
5248         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5249
5250         /* alloc handles */
5251         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5252         if (!videobin)
5253                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5254
5255         player->pipeline->videobin = videobin;
5256
5257         attrs = MMPLAYER_GET_ATTRS(player);
5258         if (!attrs) {
5259                 LOGE("cannot get content attribute");
5260                 return MM_ERROR_PLAYER_INTERNAL;
5261         }
5262
5263         /* create bin */
5264         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5265         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5266         if (!videobin[MMPLAYER_V_BIN].gst) {
5267                 LOGE("failed to create videobin");
5268                 goto ERROR;
5269         }
5270
5271         int enable_video_decoded_cb = 0;
5272         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5273
5274         if (player->is_360_feature_enabled && player->is_content_spherical) {
5275                 LOGD("video360 elem will be added.");
5276
5277                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5278                                 "video-360", TRUE, player);
5279
5280                 /* Set spatial media metadata and/or user settings to the element.
5281                  * */
5282                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5283                                 "projection-type", player->video360_metadata.projection_type, NULL);
5284
5285                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5286                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5287
5288                 if (player->video360_metadata.full_pano_width_pixels &&
5289                                 player->video360_metadata.full_pano_height_pixels &&
5290                                 player->video360_metadata.cropped_area_image_width &&
5291                                 player->video360_metadata.cropped_area_image_height) {
5292                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5293                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5294                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5295                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5296                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5297                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5298                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5299                                         NULL);
5300                 }
5301
5302                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5303                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5304                                         "horizontal-fov", player->video360_horizontal_fov,
5305                                         "vertical-fov", player->video360_vertical_fov, NULL);
5306                 }
5307
5308                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5309                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5310                                         "zoom", 1.0f / player->video360_zoom, NULL);
5311                 }
5312
5313                 if (player->video360_yaw_radians <= M_PI &&
5314                                 player->video360_yaw_radians >= -M_PI &&
5315                                 player->video360_pitch_radians <= M_PI_2 &&
5316                                 player->video360_pitch_radians >= -M_PI_2) {
5317                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5318                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5319                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5320                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5321                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5322                                         "pose-yaw", player->video360_metadata.init_view_heading,
5323                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5324                 }
5325
5326                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5327                                 "passthrough", !player->is_video360_enabled, NULL);
5328         }
5329
5330         /* set video sink */
5331         switch (surface_type) {
5332         case MM_DISPLAY_SURFACE_OVERLAY:
5333                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5334                         goto ERROR;
5335                 if (strlen(player->ini.videosink_element_overlay) > 0)
5336                         videosink_element = player->ini.videosink_element_overlay;
5337                 else
5338                         goto ERROR;
5339                 break;
5340         case MM_DISPLAY_SURFACE_NULL:
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         case MM_DISPLAY_SURFACE_REMOTE:
5347                 if (strlen(player->ini.videosink_element_fake) > 0)
5348                         videosink_element = player->ini.videosink_element_fake;
5349                 else
5350                         goto ERROR;
5351                 break;
5352         default:
5353                 LOGE("unidentified surface type");
5354                 goto ERROR;
5355         }
5356         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5357
5358         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5359
5360         /* additional setting for sink plug-in */
5361         switch (surface_type) {
5362         case MM_DISPLAY_SURFACE_OVERLAY:
5363         {
5364                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5365                 if (!use_tbm) {
5366                         LOGD("selected videosink name: %s", videosink_element);
5367
5368                         /* support shard memory with S/W codec on HawkP */
5369                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5370                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5371                                         "use-tbm", use_tbm, NULL);
5372                         }
5373                 } else {
5374                         if (attrs) {
5375                                 int gapless = 0;
5376
5377                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5378
5379                                 if (gapless > 0) {
5380                                         LOGD("disable last-sample");
5381                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5382                                 }
5383                         }
5384                 }
5385                 if (player->set_mode.media_packet_video_stream) {
5386                         int enable = 0;
5387                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5388                         if (enable)
5389                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5390
5391                         MMPLAYER_SIGNAL_CONNECT(player,
5392                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5394                                                                         "handoff",
5395                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5396                                                                         (gpointer)player);
5397
5398                         MMPLAYER_SIGNAL_CONNECT(player,
5399                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5400                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5401                                                                         "preroll-handoff",
5402                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5403                                                                         (gpointer)player);
5404                 }
5405                 break;
5406         }
5407         case MM_DISPLAY_SURFACE_REMOTE:
5408         {
5409                 if (player->set_mode.media_packet_video_stream) {
5410                         LOGE("add data probe at videosink");
5411                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5412                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5413
5414                         MMPLAYER_SIGNAL_CONNECT(player,
5415                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5416                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5417                                                                         "handoff",
5418                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5419                                                                         (gpointer)player);
5420
5421                         MMPLAYER_SIGNAL_CONNECT(player,
5422                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5423                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5424                                                                         "preroll-handoff",
5425                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5426                                                                         (gpointer)player);
5427                         if (attrs) {
5428                                 int gapless = 0;
5429
5430                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5431
5432                                 if (gapless > 0) {
5433                                         LOGD("disable last-sample");
5434                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5435                                 }
5436                         }
5437                 }
5438                 break;
5439         }
5440         default:
5441                 break;
5442         }
5443
5444         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5445                 goto ERROR;
5446
5447         if (videobin[MMPLAYER_V_SINK].gst) {
5448                 GstPad *sink_pad = NULL;
5449                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5450                 if (sink_pad) {
5451                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5452                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5453                         gst_object_unref(GST_OBJECT(sink_pad));
5454                 } else
5455                         LOGW("failed to get sink pad from videosink\n");
5456         }
5457
5458         /* store it as it's sink element */
5459         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5460
5461         /* adding created elements to bin */
5462         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5463                 LOGE("failed to add elements\n");
5464                 goto ERROR;
5465         }
5466
5467         /* Linking elements in the bucket by added order */
5468         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5469                 LOGE("failed to link elements\n");
5470                 goto ERROR;
5471         }
5472
5473         /* get first element's sinkpad for creating ghostpad */
5474         if (element_bucket)
5475                 first_element = (MMPlayerGstElement *)element_bucket->data;
5476         if (!first_element) {
5477                 LOGE("failed to get first element from bucket\n");
5478                 goto ERROR;
5479         }
5480
5481         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5482         if (!pad) {
5483                 LOGE("failed to get pad from first element\n");
5484                 goto ERROR;
5485         }
5486
5487         /* create ghostpad */
5488         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5489         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5490                 LOGE("failed to add ghostpad to videobin\n");
5491                 goto ERROR;
5492         }
5493         gst_object_unref(pad);
5494
5495         /* done. free allocated variables */
5496         if (element_bucket)
5497                 g_list_free(element_bucket);
5498
5499         MMPLAYER_FLEAVE();
5500
5501         return MM_ERROR_NONE;
5502
5503 ERROR:
5504         LOGE("ERROR : releasing videobin\n");
5505
5506         g_list_free(element_bucket);
5507
5508         if (pad)
5509                 gst_object_unref(GST_OBJECT(pad));
5510
5511         /* release videobin with it's childs */
5512         if (videobin[MMPLAYER_V_BIN].gst)
5513                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5514
5515
5516         MMPLAYER_FREEIF(videobin);
5517
5518         player->pipeline->videobin = NULL;
5519
5520         return MM_ERROR_PLAYER_INTERNAL;
5521 }
5522
5523 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5524 {
5525         GList *element_bucket = NULL;
5526         MMPlayerGstElement *textbin = player->pipeline->textbin;
5527
5528         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5529         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5530         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5531                                                         "signal-handoffs", FALSE,
5532                                                         NULL);
5533
5534         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5535         MMPLAYER_SIGNAL_CONNECT(player,
5536                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5537                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5538                                                         "handoff",
5539                                                         G_CALLBACK(__mmplayer_update_subtitle),
5540                                                         (gpointer)player);
5541
5542         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5543         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5544         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5545
5546         if (!player->play_subtitle) {
5547                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5548                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5549         }
5550
5551         /* adding created elements to bin */
5552         LOGD("adding created elements to bin\n");
5553         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5554                 LOGE("failed to add elements\n");
5555                 goto ERROR;
5556         }
5557
5558         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5559         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5560         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5561
5562         /* linking elements in the bucket by added order. */
5563         LOGD("Linking elements in the bucket by added order.\n");
5564         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5565                 LOGE("failed to link elements\n");
5566                 goto ERROR;
5567         }
5568
5569         /* done. free allocated variables */
5570         g_list_free(element_bucket);
5571
5572         if (textbin[MMPLAYER_T_QUEUE].gst) {
5573                 GstPad *pad = NULL;
5574                 GstPad *ghostpad = NULL;
5575
5576                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5577                 if (!pad) {
5578                         LOGE("failed to get sink pad of text queue");
5579                         goto ERROR;
5580                 }
5581
5582                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5583                 gst_object_unref(pad);
5584
5585                 if (!ghostpad) {
5586                         LOGE("failed to create ghostpad of textbin\n");
5587                         goto ERROR;
5588                 }
5589
5590                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5591                         LOGE("failed to add ghostpad to textbin\n");
5592                         gst_object_unref(ghostpad);
5593                         goto ERROR;
5594                 }
5595         }
5596
5597         return MM_ERROR_NONE;
5598
5599 ERROR:
5600         g_list_free(element_bucket);
5601
5602         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5603                 LOGE("remove textbin sink from sink list");
5604                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5605         }
5606
5607         /* release element at __mmplayer_gst_create_text_sink_bin */
5608         return MM_ERROR_PLAYER_INTERNAL;
5609 }
5610
5611 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5612 {
5613         MMPlayerGstElement *textbin = NULL;
5614         GList *element_bucket = NULL;
5615         int surface_type = 0;
5616         gint i = 0;
5617
5618         MMPLAYER_FENTER();
5619
5620         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5621
5622         /* alloc handles */
5623         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5624         if (!textbin) {
5625                 LOGE("failed to allocate memory for textbin\n");
5626                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5627         }
5628
5629         /* create bin */
5630         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5631         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5632         if (!textbin[MMPLAYER_T_BIN].gst) {
5633                 LOGE("failed to create textbin\n");
5634                 goto ERROR;
5635         }
5636
5637         /* take it */
5638         player->pipeline->textbin = textbin;
5639
5640         /* fakesink */
5641         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5642         LOGD("surface type for subtitle : %d", surface_type);
5643         switch (surface_type) {
5644         case MM_DISPLAY_SURFACE_OVERLAY:
5645         case MM_DISPLAY_SURFACE_NULL:
5646         case MM_DISPLAY_SURFACE_REMOTE:
5647                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5648                         LOGE("failed to make plain text elements\n");
5649                         goto ERROR;
5650                 }
5651                 break;
5652         default:
5653                 goto ERROR;
5654                 break;
5655         }
5656
5657         MMPLAYER_FLEAVE();
5658
5659         return MM_ERROR_NONE;
5660
5661 ERROR:
5662
5663         LOGD("ERROR : releasing textbin\n");
5664
5665         g_list_free(element_bucket);
5666
5667         /* release signal */
5668         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5669
5670         /* release element which are not added to bin */
5671         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5672                 /* NOTE : skip bin */
5673                 if (textbin[i].gst) {
5674                         GstObject* parent = NULL;
5675                         parent = gst_element_get_parent(textbin[i].gst);
5676
5677                         if (!parent) {
5678                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5679                                 textbin[i].gst = NULL;
5680                         } else {
5681                                 gst_object_unref(GST_OBJECT(parent));
5682                         }
5683                 }
5684         }
5685
5686         /* release textbin with it's childs */
5687         if (textbin[MMPLAYER_T_BIN].gst)
5688                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5689
5690         MMPLAYER_FREEIF(player->pipeline->textbin);
5691         player->pipeline->textbin = NULL;
5692
5693         MMPLAYER_FLEAVE();
5694         return MM_ERROR_PLAYER_INTERNAL;
5695 }
5696
5697
5698 static int
5699 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5700 {
5701         MMPlayerGstElement* mainbin = NULL;
5702         MMPlayerGstElement* textbin = NULL;
5703         MMHandleType attrs = 0;
5704         GstElement *subsrc = NULL;
5705         GstElement *subparse = NULL;
5706         gchar *subtitle_uri = NULL;
5707         const gchar *charset = NULL;
5708         GstPad *pad = NULL;
5709
5710         MMPLAYER_FENTER();
5711
5712         /* get mainbin */
5713         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5714                                                                 player->pipeline &&
5715                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716
5717         mainbin = player->pipeline->mainbin;
5718
5719         attrs = MMPLAYER_GET_ATTRS(player);
5720         if (!attrs) {
5721                 LOGE("cannot get content attribute\n");
5722                 return MM_ERROR_PLAYER_INTERNAL;
5723         }
5724
5725         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5726         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5727                 LOGE("subtitle uri is not proper filepath.\n");
5728                 return MM_ERROR_PLAYER_INVALID_URI;
5729         }
5730
5731         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5732                 LOGE("failed to get storage info of subtitle path");
5733                 return MM_ERROR_PLAYER_INVALID_URI;
5734         }
5735
5736         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5737
5738         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5739         player->subtitle_language_list = NULL;
5740         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5741
5742         /* create the subtitle source */
5743         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5744         if (!subsrc) {
5745                 LOGE("failed to create filesrc element\n");
5746                 goto ERROR;
5747         }
5748         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5749
5750         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5751         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5752
5753         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5754                 LOGW("failed to add queue\n");
5755                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5756                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5757                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5758                 goto ERROR;
5759         }
5760
5761         /* subparse */
5762         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5763         if (!subparse) {
5764                 LOGE("failed to create subparse element\n");
5765                 goto ERROR;
5766         }
5767
5768         charset = util_get_charset(subtitle_uri);
5769         if (charset) {
5770                 LOGD("detected charset is %s\n", charset);
5771                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5772         }
5773
5774         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5775         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5776
5777         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5778                 LOGW("failed to add subparse\n");
5779                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5780                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5781                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5782                 goto ERROR;
5783         }
5784
5785         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5786                 LOGW("failed to link subsrc and subparse\n");
5787                 goto ERROR;
5788         }
5789
5790         player->play_subtitle = TRUE;
5791         player->adjust_subtitle_pos = 0;
5792
5793         LOGD("play subtitle using subtitle file\n");
5794
5795         if (player->pipeline->textbin == NULL) {
5796                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5797                         LOGE("failed to create text sink bin. continuing without text\n");
5798                         goto ERROR;
5799                 }
5800
5801                 textbin = player->pipeline->textbin;
5802
5803                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5804                         LOGW("failed to add textbin\n");
5805
5806                         /* release signal */
5807                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5808
5809                         /* release textbin with it's childs */
5810                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5811                         MMPLAYER_FREEIF(player->pipeline->textbin);
5812                         player->pipeline->textbin = textbin = NULL;
5813                         goto ERROR;
5814                 }
5815
5816                 LOGD("link text input selector and textbin ghost pad");
5817
5818                 player->textsink_linked = 1;
5819                 player->external_text_idx = 0;
5820                 LOGI("player->textsink_linked set to 1\n");
5821         } else {
5822                 textbin = player->pipeline->textbin;
5823                 LOGD("text bin has been created. reuse it.");
5824                 player->external_text_idx = 1;
5825         }
5826
5827         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5828                 LOGW("failed to link subparse and textbin\n");
5829                 goto ERROR;
5830         }
5831
5832         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5833         if (!pad) {
5834                 LOGE("failed to get sink pad from textsink to probe data");
5835                 goto ERROR;
5836         }
5837
5838         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5839                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5840
5841         gst_object_unref(pad);
5842         pad = NULL;
5843
5844         /* create dot. for debugging */
5845         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5846         MMPLAYER_FLEAVE();
5847
5848         return MM_ERROR_NONE;
5849
5850 ERROR:
5851         /* release text pipeline resource */
5852         player->textsink_linked = 0;
5853
5854         /* release signal */
5855         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5856
5857         if (player->pipeline->textbin) {
5858                 LOGE("remove textbin");
5859
5860                 /* release textbin with it's childs */
5861                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5862                 MMPLAYER_FREEIF(player->pipeline->textbin);
5863                 player->pipeline->textbin = NULL;
5864
5865         }
5866
5867         /* release subtitle elem */
5868         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5869         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5870
5871         return MM_ERROR_PLAYER_INTERNAL;
5872 }
5873
5874 gboolean
5875 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5876 {
5877         mm_player_t* player = (mm_player_t*) data;
5878         MMMessageParamType msg = {0, };
5879         GstClockTime duration = 0;
5880         gpointer text = NULL;
5881         guint text_size = 0;
5882         gboolean ret = TRUE;
5883         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5884
5885         MMPLAYER_FENTER();
5886
5887         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5888         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5889
5890         if (player->is_subtitle_force_drop) {
5891                 LOGW("subtitle is dropped forcedly.");
5892                 return ret;
5893         }
5894
5895         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5896         text = mapinfo.data;
5897         text_size = mapinfo.size;
5898         duration = GST_BUFFER_DURATION(buffer);
5899
5900         if (player->set_mode.subtitle_off) {
5901                 LOGD("subtitle is OFF.\n");
5902                 return TRUE;
5903         }
5904
5905         if (!text || (text_size == 0)) {
5906                 LOGD("There is no subtitle to be displayed.\n");
5907                 return TRUE;
5908         }
5909
5910         msg.data = (void *) text;
5911         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5912
5913         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5914
5915         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5916         gst_buffer_unmap(buffer, &mapinfo);
5917
5918         MMPLAYER_FLEAVE();
5919
5920         return ret;
5921 }
5922
5923 static GstPadProbeReturn
5924 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5925 {
5926         mm_player_t *player = (mm_player_t *) u_data;
5927         GstClockTime cur_timestamp = 0;
5928         gint64 adjusted_timestamp = 0;
5929         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5930
5931         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5932
5933         if (player->set_mode.subtitle_off) {
5934                 LOGD("subtitle is OFF.\n");
5935                 return TRUE;
5936         }
5937
5938         if (player->adjust_subtitle_pos == 0) {
5939                 LOGD("nothing to do");
5940                 return TRUE;
5941         }
5942
5943         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5944         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5945
5946         if (adjusted_timestamp < 0) {
5947                 LOGD("adjusted_timestamp under zero");
5948                 MMPLAYER_FLEAVE();
5949                 return FALSE;
5950         }
5951
5952         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5953         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5954                                 GST_TIME_ARGS(cur_timestamp),
5955                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5956
5957         return GST_PAD_PROBE_OK;
5958 }
5959 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5960 {
5961         MMPLAYER_FENTER();
5962
5963         /* check player and subtitlebin are created */
5964         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5965         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5966
5967         if (position == 0) {
5968                 LOGD("nothing to do\n");
5969                 MMPLAYER_FLEAVE();
5970                 return MM_ERROR_NONE;
5971         }
5972
5973         switch (format) {
5974         case MM_PLAYER_POS_FORMAT_TIME:
5975                 {
5976                         /* check current postion */
5977                         player->adjust_subtitle_pos = position;
5978
5979                         LOGD("save adjust_subtitle_pos in player") ;
5980                 }
5981                 break;
5982
5983         default:
5984                 {
5985                         LOGW("invalid format.\n");
5986                         MMPLAYER_FLEAVE();
5987                         return MM_ERROR_INVALID_ARGUMENT;
5988                 }
5989         }
5990
5991         MMPLAYER_FLEAVE();
5992
5993         return MM_ERROR_NONE;
5994 }
5995 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5996 {
5997         MMPLAYER_FENTER();
5998         LOGD("adjusting video_pos in player") ;
5999         int current_pos = 0;
6000         /* check player and videobin are created */
6001         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6002         if (!player->pipeline->videobin ||
6003                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6004                 LOGD("no video pipeline or sink is there");
6005                 return MM_ERROR_PLAYER_INVALID_STATE ;
6006         }
6007         if (offset == 0) {
6008                 LOGD("nothing to do\n");
6009                 MMPLAYER_FLEAVE();
6010                 return MM_ERROR_NONE;
6011         }
6012         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6013                 LOGD("failed to get current position");
6014                 return MM_ERROR_PLAYER_INTERNAL;
6015         }
6016         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6017                 LOGD("enter video delay is valid");
6018         } else {
6019                 LOGD("enter video delay is crossing content boundary");
6020                 return MM_ERROR_INVALID_ARGUMENT ;
6021         }
6022         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6023         LOGD("video delay has been done");
6024         MMPLAYER_FLEAVE();
6025
6026         return MM_ERROR_NONE;
6027 }
6028
6029 static void
6030 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6031 {
6032         GstElement *appsrc = element;
6033         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6034         GstBuffer *buffer = NULL;
6035         GstFlowReturn ret = GST_FLOW_OK;
6036         gint len = size;
6037
6038         MMPLAYER_RETURN_IF_FAIL(element);
6039         MMPLAYER_RETURN_IF_FAIL(buf);
6040
6041         buffer = gst_buffer_new();
6042
6043         if (buf->offset >= buf->len) {
6044                 LOGD("call eos appsrc\n");
6045                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6046                 return;
6047         }
6048
6049         if (buf->len - buf->offset < size)
6050                 len = buf->len - buf->offset;
6051
6052         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6053         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6054         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6055
6056         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6057         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6058
6059         buf->offset += len;
6060 }
6061
6062 static gboolean
6063 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6064 {
6065         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6066
6067         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6068
6069         buf->offset  = (int)size;
6070
6071         return TRUE;
6072 }
6073
6074 static GstBusSyncReply
6075 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6076 {
6077         mm_player_t *player = (mm_player_t *)data;
6078         GstBusSyncReply reply = GST_BUS_DROP;
6079
6080         if (!(player->pipeline && player->pipeline->mainbin)) {
6081                 LOGE("player pipeline handle is null");
6082                 return GST_BUS_PASS;
6083         }
6084
6085         if (!__mmplayer_check_useful_message(player, message)) {
6086                 gst_message_unref(message);
6087                 return GST_BUS_DROP;
6088         }
6089
6090         switch (GST_MESSAGE_TYPE(message)) {
6091         case GST_MESSAGE_STATE_CHANGED:
6092                 /* post directly for fast launch */
6093                 if (player->sync_handler) {
6094                         __mmplayer_gst_callback(message, player);
6095                         reply = GST_BUS_DROP;
6096                 } else
6097                         reply = GST_BUS_PASS;
6098                 break;
6099         case GST_MESSAGE_TAG:
6100                 __mmplayer_gst_extract_tag_from_msg(player, message);
6101
6102                 #if 0 // debug
6103                 {
6104                         GstTagList *tags = NULL;
6105
6106                         gst_message_parse_tag(message, &tags);
6107                         if (tags) {
6108                                 LOGE("TAGS received from element \"%s\".\n",
6109                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6110
6111                                 gst_tag_list_foreach(tags, print_tag, NULL);
6112                                 gst_tag_list_free(tags);
6113                                 tags = NULL;
6114                         }
6115                         break;
6116                 }
6117                 #endif
6118                 break;
6119
6120         case GST_MESSAGE_DURATION_CHANGED:
6121                 __mmplayer_gst_handle_duration(player, message);
6122                 break;
6123         case GST_MESSAGE_ASYNC_DONE:
6124                 /* NOTE:Don't call gst_callback directly
6125                  * because previous frame can be showed even though this message is received for seek.
6126                  */
6127         default:
6128                 reply = GST_BUS_PASS;
6129                 break;
6130         }
6131
6132         if (reply == GST_BUS_DROP)
6133                 gst_message_unref(message);
6134
6135         return reply;
6136 }
6137
6138 static gboolean
6139 __mmplayer_gst_create_decoder(mm_player_t *player,
6140                                                                 MMPlayerTrackType track,
6141                                                                 GstPad* srcpad,
6142                                                                 enum MainElementID elemId,
6143                                                                 const gchar* name)
6144 {
6145         gboolean ret = TRUE;
6146         GstPad *sinkpad = NULL;
6147
6148         MMPLAYER_FENTER();
6149
6150         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6151                                                 player->pipeline &&
6152                                                 player->pipeline->mainbin, FALSE);
6153         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6154         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6155         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6156
6157         GstElement *decodebin = NULL;
6158         GstCaps *dec_caps = NULL;
6159
6160         /* create decodebin */
6161         decodebin = gst_element_factory_make("decodebin", name);
6162
6163         if (!decodebin) {
6164                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6165                 ret = FALSE;
6166                 goto ERROR;
6167         }
6168
6169         /* raw pad handling signal */
6170         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6171                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6172
6173         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6174         before looking for any elements that can handle that stream.*/
6175         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6176                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6177
6178         /* This signal is emitted when a element is added to the bin.*/
6179         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6180                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6181
6182         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6183                 LOGE("failed to add new decodebin\n");
6184                 ret = FALSE;
6185                 goto ERROR;
6186         }
6187
6188         dec_caps = gst_pad_query_caps(srcpad, NULL);
6189         if (dec_caps) {
6190                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6191                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6192                 gst_caps_unref(dec_caps);
6193         }
6194
6195         player->pipeline->mainbin[elemId].id = elemId;
6196         player->pipeline->mainbin[elemId].gst = decodebin;
6197
6198         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6199
6200         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6201                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6202                 gst_object_unref(GST_OBJECT(decodebin));
6203         }
6204
6205         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6206                 LOGE("failed to sync second level decodebin state with parent\n");
6207
6208         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6209
6210 ERROR:
6211         if (sinkpad) {
6212                 gst_object_unref(GST_OBJECT(sinkpad));
6213                 sinkpad = NULL;
6214         }
6215         MMPLAYER_FLEAVE();
6216
6217         return ret;
6218 }
6219
6220 /**
6221  * This function is to create  audio or video pipeline for playing.
6222  *
6223  * @param       player          [in]    handle of player
6224  *
6225  * @return      This function returns zero on success.
6226  * @remark
6227  * @see
6228  */
6229 static int
6230 __mmplayer_gst_create_pipeline(mm_player_t* player)
6231 {
6232         GstBus  *bus = NULL;
6233         MMPlayerGstElement *mainbin = NULL;
6234         MMHandleType attrs = 0;
6235         GstElement* element = NULL;
6236         GstElement* elem_src_audio = NULL;
6237         GstElement* elem_src_subtitle = NULL;
6238         GstElement* es_video_queue = NULL;
6239         GstElement* es_audio_queue = NULL;
6240         GstElement* es_subtitle_queue = NULL;
6241         GList* element_bucket = NULL;
6242         gboolean need_state_holder = TRUE;
6243         gint i = 0;
6244 #ifdef SW_CODEC_ONLY
6245         int surface_type = 0;
6246 #endif
6247         MMPLAYER_FENTER();
6248
6249         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6250
6251         /* get profile attribute */
6252         attrs = MMPLAYER_GET_ATTRS(player);
6253         if (!attrs) {
6254                 LOGE("cannot get content attribute\n");
6255                 goto INIT_ERROR;
6256         }
6257
6258         /* create pipeline handles */
6259         if (player->pipeline) {
6260                 LOGW("pipeline should be released before create new one\n");
6261                 goto INIT_ERROR;
6262         }
6263
6264         player->video360_metadata.is_spherical = -1;
6265         player->is_openal_plugin_used = FALSE;
6266
6267         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6268         if (player->pipeline == NULL)
6269                 goto INIT_ERROR;
6270
6271         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6272
6273         /* create mainbin */
6274         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6275         if (mainbin == NULL)
6276                 goto INIT_ERROR;
6277
6278         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6279
6280         /* create pipeline */
6281         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6282         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6283         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6284                 LOGE("failed to create pipeline\n");
6285                 goto INIT_ERROR;
6286         }
6287         player->demux_pad_index = 0;
6288         player->subtitle_language_list = NULL;
6289
6290         player->is_subtitle_force_drop = FALSE;
6291         player->last_multiwin_status = FALSE;
6292
6293         _mmplayer_track_initialize(player);
6294         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6295
6296         /* create source element */
6297         switch (player->profile.uri_type) {
6298         /* rtsp streamming */
6299         case MM_PLAYER_URI_TYPE_URL_RTSP:
6300                 {
6301                         gchar *user_agent;
6302
6303                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6304
6305                         if (!element) {
6306                                 LOGE("failed to create streaming source element\n");
6307                                 break;
6308                         }
6309
6310                         /* make it zero */
6311                         user_agent = NULL;
6312
6313                         /* get attribute */
6314                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6315
6316                         SECURE_LOGD("user_agent : %s\n", user_agent);
6317
6318                         /* setting property to streaming source */
6319                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6320                         if (user_agent)
6321                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6322
6323                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6324                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6325                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6326                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6327                 }
6328                 break;
6329
6330         /* http streaming*/
6331         case MM_PLAYER_URI_TYPE_URL_HTTP:
6332                 {
6333                         gchar *user_agent, *cookies, **cookie_list;
6334                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6335                         user_agent = cookies = NULL;
6336                         cookie_list = NULL;
6337                         gint mode = MM_PLAYER_PD_MODE_NONE;
6338
6339                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6340
6341                         player->pd_mode = mode;
6342
6343                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6344
6345                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6346                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6347                                 if (!element) {
6348                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6349                                         break;
6350                                 }
6351                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6352
6353                                 /* get attribute */
6354                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6355                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6356
6357                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6358                                         LOGD("get timeout from ini\n");
6359                                         http_timeout = player->ini.http_timeout;
6360                                 }
6361
6362                                 /* get attribute */
6363                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6364                                 SECURE_LOGD("cookies : %s\n", cookies);
6365                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6366                                 LOGD("timeout : %d\n",  http_timeout);
6367
6368                                 /* setting property to streaming source */
6369                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6370                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6371                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6372
6373                                 /* parsing cookies */
6374                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6375                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6376                                         g_strfreev(cookie_list);
6377                                 }
6378                                 if (user_agent)
6379                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6380
6381                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6382                                         LOGW("it's dash. and it's still experimental feature.");
6383                         } else {
6384                                 // progressive download
6385                                 gchar* location = NULL;
6386
6387                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6388                                         gchar *path = NULL;
6389
6390                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6391
6392                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6393
6394                                         LOGD("PD Location : %s\n", path);
6395
6396                                         if (path) {
6397                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6398                                                         LOGE("failed to get storage info");
6399                                                         break;
6400                                                 }
6401                                                 player->pd_file_save_path = g_strdup(path);
6402                                         } else {
6403                                                 LOGE("can't find pd location so, it should be set \n");
6404                                                 break;
6405                                         }
6406                                 }
6407
6408                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6409                                 if (!element) {
6410                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6411                                         break;
6412                                 }
6413
6414                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6415                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6416                                 else
6417                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6418                                 g_object_get(element, "location", &location, NULL);
6419                                 LOGD("PD_LOCATION [%s].\n", location);
6420                                 if (location)
6421                                         g_free(location);
6422                         }
6423                 }
6424                 break;
6425
6426         /* file source */
6427         case MM_PLAYER_URI_TYPE_FILE:
6428                 {
6429                         LOGD("using filesrc for 'file://' handler.\n");
6430                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6431                                 LOGE("failed to get storage info");
6432                                 break;
6433                         }
6434
6435                         element = gst_element_factory_make("filesrc", "source");
6436                         if (!element) {
6437                                 LOGE("failed to create filesrc\n");
6438                                 break;
6439                         }
6440
6441                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6442                 }
6443                 break;
6444
6445         case MM_PLAYER_URI_TYPE_SS:
6446                 {
6447                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6448                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6449                         if (!element) {
6450                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6451                                 break;
6452                         }
6453
6454                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6455                                 LOGD("get timeout from ini\n");
6456                                 http_timeout = player->ini.http_timeout;
6457                         }
6458
6459                         /* setting property to streaming source */
6460                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6461                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6462                 }
6463                 break;
6464         case MM_PLAYER_URI_TYPE_MS_BUFF:
6465                 {
6466                         LOGD("MS buff src is selected\n");
6467
6468                         if (player->v_stream_caps) {
6469                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6470                                 if (!element) {
6471                                         LOGF("failed to create video app source element[appsrc].\n");
6472                                         break;
6473                                 }
6474
6475                                 if (player->a_stream_caps) {
6476                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6477                                         if (!elem_src_audio) {
6478                                                 LOGF("failed to create audio app source element[appsrc].\n");
6479                                                 break;
6480                                         }
6481                                 }
6482                         } else if (player->a_stream_caps) {
6483                                 /* no video, only audio pipeline*/
6484                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6485                                 if (!element) {
6486                                         LOGF("failed to create audio app source element[appsrc].\n");
6487                                         break;
6488                                 }
6489                         }
6490
6491                         if (player->s_stream_caps) {
6492                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6493                                 if (!elem_src_subtitle) {
6494                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6495                                         break;
6496                                 }
6497                         }
6498
6499                         LOGD("setting app sources properties.\n");
6500                         LOGD("location : %s\n", player->profile.uri);
6501
6502                         if (player->v_stream_caps && element) {
6503                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6504                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6505                                                                                                 "caps", player->v_stream_caps, NULL);
6506
6507                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6508                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6509                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6510                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6511
6512                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6513                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6514                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6515                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6516
6517                                 if (player->a_stream_caps && elem_src_audio) {
6518                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6519                                                                                                                         "caps", player->a_stream_caps, NULL);
6520
6521                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6522                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6523                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6524                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6525
6526                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6527                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6528                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6529                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6530                                 }
6531                         } else if (player->a_stream_caps && element) {
6532                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6533                                                                                                 "caps", player->a_stream_caps, NULL);
6534
6535                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6536                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6537                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6538                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6539
6540                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6541                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6542                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6543                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6544                         }
6545
6546                         if (player->s_stream_caps && elem_src_subtitle) {
6547                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6548                                                                                                                  "caps", player->s_stream_caps, NULL);
6549
6550                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6551                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6552                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6553                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6554
6555                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6556
6557                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6558                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6559                         }
6560
6561                         if (player->v_stream_caps && element) {
6562                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6563                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6564                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6565                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6566
6567                                 if (player->a_stream_caps && elem_src_audio) {
6568                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6569                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6570                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6571                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6572                                 }
6573                         } else if (player->a_stream_caps && element) {
6574                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6575                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6576                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6577                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6578                         }
6579
6580                         if (player->s_stream_caps && elem_src_subtitle)
6581                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6582                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6583
6584                         need_state_holder = FALSE;
6585
6586                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6587                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6588                                 LOGE("failed to commit\n");
6589                 }
6590                 break;
6591         /* appsrc */
6592         case MM_PLAYER_URI_TYPE_MEM:
6593                 {
6594                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6595
6596                         LOGD("mem src is selected\n");
6597
6598                         element = gst_element_factory_make("appsrc", "mem-source");
6599                         if (!element) {
6600                                 LOGE("failed to create appsrc element\n");
6601                                 break;
6602                         }
6603
6604                         g_object_set(element, "stream-type", stream_type, NULL);
6605                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6606                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6607
6608                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6609                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6610                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6611                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6612                 }
6613                 break;
6614         case MM_PLAYER_URI_TYPE_URL:
6615                 break;
6616
6617         case MM_PLAYER_URI_TYPE_TEMP:
6618                 break;
6619
6620         case MM_PLAYER_URI_TYPE_NONE:
6621         default:
6622                 break;
6623         }
6624
6625         /* check source element is OK */
6626         if (!element) {
6627                 LOGE("no source element was created.\n");
6628                 goto INIT_ERROR;
6629         }
6630
6631         /* take source element */
6632         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6633         mainbin[MMPLAYER_M_SRC].gst = element;
6634         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6635
6636         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6637                 player->streamer = __mm_player_streaming_create();
6638                 __mm_player_streaming_initialize(player->streamer);
6639         }
6640
6641         if (MMPLAYER_IS_HTTP_PD(player)) {
6642                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6643
6644                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6645                 element = gst_element_factory_make("queue2", "queue2");
6646                 if (!element) {
6647                         LOGE("failed to create http streaming buffer element\n");
6648                         goto INIT_ERROR;
6649                 }
6650
6651                 /* take it */
6652                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6653                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6654                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6655
6656                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6657
6658                 __mm_player_streaming_set_queue2(player->streamer,
6659                                 element,
6660                                 TRUE,
6661                                 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6662                                 pre_buffering_time,
6663                                 1.0,
6664                                 player->ini.http_buffering_limit,
6665                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6666                                 NULL,
6667                                 0);
6668         }
6669         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6670                 if (player->v_stream_caps) {
6671                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6672                         if (!es_video_queue) {
6673                                 LOGE("create es_video_queue for es player failed\n");
6674                                 goto INIT_ERROR;
6675                         }
6676                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6677                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6678                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6679                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6680
6681                         /* Adding audio appsrc to bucket */
6682                         if (player->a_stream_caps && elem_src_audio) {
6683                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6684                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6685                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6686
6687                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6688                                 if (!es_audio_queue) {
6689                                         LOGE("create es_audio_queue for es player failed\n");
6690                                         goto INIT_ERROR;
6691                                 }
6692                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6693
6694                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6695                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6696                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6697                         }
6698                 } else if (player->a_stream_caps) {
6699                         /* Only audio stream, no video */
6700                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6701                         if (!es_audio_queue) {
6702                                 LOGE("create es_audio_queue for es player failed\n");
6703                                 goto INIT_ERROR;
6704                         }
6705                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6706                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6707                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6708                 }
6709
6710                 if (player->s_stream_caps && elem_src_subtitle) {
6711                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6712                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6713                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6714
6715                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6716                         if (!es_subtitle_queue) {
6717                                 LOGE("create es_subtitle_queue for es player failed\n");
6718                                 goto INIT_ERROR;
6719                         }
6720                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6721                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6722                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6723                 }
6724         }
6725
6726         /* create autoplugging element if src element is not a rtsp src */
6727         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6728                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6729                 element = NULL;
6730                 enum MainElementID elemId = MMPLAYER_M_NUM;
6731
6732                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6733                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6734                         elemId = MMPLAYER_M_AUTOPLUG;
6735                         element = __mmplayer_create_decodebin(player);
6736                         if (element) {
6737                                 /* default size of mq in decodebin is 2M
6738                                  * but it can cause blocking issue during seeking depends on content. */
6739                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6740                         }
6741                         need_state_holder = FALSE;
6742                 } else {
6743                         elemId = MMPLAYER_M_TYPEFIND;
6744                         element = gst_element_factory_make("typefind", "typefinder");
6745                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6746                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6747                 }
6748
6749
6750                 /* check autoplug element is OK */
6751                 if (!element) {
6752                         LOGE("can not create element(%d)\n", elemId);
6753                         goto INIT_ERROR;
6754                 }
6755
6756                 mainbin[elemId].id = elemId;
6757                 mainbin[elemId].gst = element;
6758
6759                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6760         }
6761
6762         /* add elements to pipeline */
6763         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6764                 LOGE("Failed to add elements to pipeline\n");
6765                 goto INIT_ERROR;
6766         }
6767
6768
6769         /* linking elements in the bucket by added order. */
6770         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6771                 LOGE("Failed to link some elements\n");
6772                 goto INIT_ERROR;
6773         }
6774
6775
6776         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6777         if (need_state_holder) {
6778                 /* create */
6779                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6780                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6781
6782                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6783                         LOGE("fakesink element could not be created\n");
6784                         goto INIT_ERROR;
6785                 }
6786                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6787
6788                 /* take ownership of fakesink. we are reusing it */
6789                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6790
6791                 /* add */
6792                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6793                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6794                         LOGE("failed to add fakesink to bin\n");
6795                         goto INIT_ERROR;
6796                 }
6797         }
6798
6799         /* now we have completed mainbin. take it */
6800         player->pipeline->mainbin = mainbin;
6801
6802         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6803                 GstPad *srcpad = NULL;
6804
6805                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6806                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6807                         if (srcpad) {
6808                                 __mmplayer_gst_create_decoder(player,
6809                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6810                                                                                                 srcpad,
6811                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6812                                                                                                 "video_decodebin");
6813
6814                                 gst_object_unref(GST_OBJECT(srcpad));
6815                                 srcpad = NULL;
6816                         }
6817                 }
6818
6819                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6820                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6821                         if (srcpad) {
6822                                 __mmplayer_gst_create_decoder(player,
6823                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6824                                                                                                 srcpad,
6825                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6826                                                                                                 "audio_decodebin");
6827
6828                                 gst_object_unref(GST_OBJECT(srcpad));
6829                                 srcpad = NULL;
6830                         } // else error
6831                 } //  else error
6832
6833                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6834                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6835         }
6836
6837         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6838         if (__mmplayer_check_subtitle(player)) {
6839                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6840                         LOGE("fail to create text pipeline");
6841         }
6842
6843         /* connect bus callback */
6844         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6845         if (!bus) {
6846                 LOGE("cannot get bus from pipeline.\n");
6847                 goto INIT_ERROR;
6848         }
6849
6850         /* set sync handler to get tag synchronously */
6851         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6852
6853         /* finished */
6854         gst_object_unref(GST_OBJECT(bus));
6855         g_list_free(element_bucket);
6856
6857         /* create gst bus_msb_cb thread */
6858         g_mutex_init(&player->bus_msg_thread_mutex);
6859         g_cond_init(&player->bus_msg_thread_cond);
6860         player->bus_msg_thread_exit = FALSE;
6861         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6862         player->bus_msg_thread =
6863                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6864         if (!player->bus_msg_thread) {
6865                 LOGE("failed to create gst BUS msg thread");
6866                 g_mutex_clear(&player->bus_msg_thread_mutex);
6867                 g_cond_clear(&player->bus_msg_thread_cond);
6868                 goto INIT_ERROR;
6869         }
6870
6871         MMPLAYER_FLEAVE();
6872
6873         return MM_ERROR_NONE;
6874
6875 INIT_ERROR:
6876         __mmplayer_gst_destroy_pipeline(player);
6877         g_list_free(element_bucket);
6878
6879         if (mainbin) {
6880                 /* release element which are not added to bin */
6881                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6882                         /* NOTE : skip pipeline */
6883                         if (mainbin[i].gst) {
6884                                 GstObject* parent = NULL;
6885                                 parent = gst_element_get_parent(mainbin[i].gst);
6886
6887                                 if (!parent) {
6888                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6889                                         mainbin[i].gst = NULL;
6890                                 } else
6891                                         gst_object_unref(GST_OBJECT(parent));
6892                         }
6893                 }
6894
6895                 /* release pipeline with it's childs */
6896                 if (mainbin[MMPLAYER_M_PIPE].gst)
6897                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6898
6899                 MMPLAYER_FREEIF(mainbin);
6900         }
6901
6902         MMPLAYER_FREEIF(player->pipeline);
6903         return MM_ERROR_PLAYER_INTERNAL;
6904 }
6905
6906 static void
6907 __mmplayer_reset_gapless_state(mm_player_t* player)
6908 {
6909         MMPLAYER_FENTER();
6910         MMPLAYER_RETURN_IF_FAIL(player
6911                 && player->pipeline
6912                 && player->pipeline->audiobin
6913                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6914
6915         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6916
6917         MMPLAYER_FLEAVE();
6918         return;
6919 }
6920
6921 static int
6922 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6923 {
6924         gint timeout = 0;
6925         int ret = MM_ERROR_NONE;
6926
6927         MMPLAYER_FENTER();
6928
6929         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6930
6931         /* cleanup stuffs */
6932         MMPLAYER_FREEIF(player->type);
6933         player->have_dynamic_pad = FALSE;
6934         player->no_more_pad = FALSE;
6935         player->num_dynamic_pad = 0;
6936         player->demux_pad_index = 0;
6937         player->use_deinterleave = FALSE;
6938         player->max_audio_channels = 0;
6939         player->video_share_api_delta = 0;
6940         player->video_share_clock_delta = 0;
6941         player->video_hub_download_mode = 0;
6942
6943         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6944         player->subtitle_language_list = NULL;
6945         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6946
6947         __mmplayer_reset_gapless_state(player);
6948
6949         if (player->streamer) {
6950                 __mm_player_streaming_deinitialize(player->streamer);
6951                 __mm_player_streaming_destroy(player->streamer);
6952                 player->streamer = NULL;
6953         }
6954
6955         /* cleanup unlinked mime type */
6956         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6957         MMPLAYER_FREEIF(player->unlinked_video_mime);
6958         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6959
6960         /* cleanup running stuffs */
6961         __mmplayer_cancel_eos_timer(player);
6962
6963         /* cleanup gst stuffs */
6964         if (player->pipeline) {
6965                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6966                 GstTagList* tag_list = player->pipeline->tag_list;
6967
6968                 /* first we need to disconnect all signal hander */
6969                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6970
6971                 if (mainbin) {
6972                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6973                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6974                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6975                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6976                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6977                         gst_object_unref(bus);
6978
6979                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6980                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6981                         if (ret != MM_ERROR_NONE) {
6982                                 LOGE("fail to change state to NULL\n");
6983                                 return MM_ERROR_PLAYER_INTERNAL;
6984                         }
6985
6986                         LOGW("succeeded in chaning state to NULL\n");
6987
6988                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6989
6990                         /* free fakesink */
6991                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6992                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6993
6994                         /* free avsysaudiosink
6995                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6996                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6997                         */
6998                         MMPLAYER_FREEIF(audiobin);
6999                         MMPLAYER_FREEIF(videobin);
7000                         MMPLAYER_FREEIF(textbin);
7001                         MMPLAYER_FREEIF(mainbin);
7002                 }
7003
7004                 if (tag_list)
7005                         gst_tag_list_free(tag_list);
7006
7007                 MMPLAYER_FREEIF(player->pipeline);
7008         }
7009         MMPLAYER_FREEIF(player->album_art);
7010
7011         if (player->v_stream_caps) {
7012                 gst_caps_unref(player->v_stream_caps);
7013                 player->v_stream_caps = NULL;
7014         }
7015         if (player->a_stream_caps) {
7016                 gst_caps_unref(player->a_stream_caps);
7017                 player->a_stream_caps = NULL;
7018         }
7019
7020         if (player->s_stream_caps) {
7021                 gst_caps_unref(player->s_stream_caps);
7022                 player->s_stream_caps = NULL;
7023         }
7024         _mmplayer_track_destroy(player);
7025
7026         if (player->sink_elements)
7027                 g_list_free(player->sink_elements);
7028         player->sink_elements = NULL;
7029
7030         if (player->bufmgr) {
7031                 tbm_bufmgr_deinit(player->bufmgr);
7032                 player->bufmgr = NULL;
7033         }
7034
7035         LOGW("finished destroy pipeline\n");
7036
7037         MMPLAYER_FLEAVE();
7038
7039         return ret;
7040 }
7041
7042 static int __gst_realize(mm_player_t* player)
7043 {
7044         gint timeout = 0;
7045         int ret = MM_ERROR_NONE;
7046
7047         MMPLAYER_FENTER();
7048
7049         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7050
7051         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7052
7053         ret = __mmplayer_gst_create_pipeline(player);
7054         if (ret) {
7055                 LOGE("failed to create pipeline\n");
7056                 return ret;
7057         }
7058
7059         /* set pipeline state to READY */
7060         /* NOTE : state change to READY must be performed sync. */
7061         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7062         ret = __mmplayer_gst_set_state(player,
7063                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7064
7065         if (ret != MM_ERROR_NONE) {
7066                 /* return error if failed to set state */
7067                 LOGE("failed to set READY state");
7068                 return ret;
7069         }
7070
7071         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7072
7073         /* create dot before error-return. for debugging */
7074         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7075
7076         MMPLAYER_FLEAVE();
7077
7078         return ret;
7079 }
7080
7081 static int __gst_unrealize(mm_player_t* player)
7082 {
7083         int ret = MM_ERROR_NONE;
7084
7085         MMPLAYER_FENTER();
7086
7087         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7088
7089         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7090         MMPLAYER_PRINT_STATE(player);
7091
7092         /* release miscellaneous information */
7093         __mmplayer_release_misc(player);
7094
7095         /* destroy pipeline */
7096         ret = __mmplayer_gst_destroy_pipeline(player);
7097         if (ret != MM_ERROR_NONE) {
7098                 LOGE("failed to destory pipeline\n");
7099                 return ret;
7100         }
7101
7102         /* release miscellaneous information.
7103            these info needs to be released after pipeline is destroyed. */
7104         __mmplayer_release_misc_post(player);
7105
7106         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7107
7108         MMPLAYER_FLEAVE();
7109
7110         return ret;
7111 }
7112
7113 static int __gst_pending_seek(mm_player_t* player)
7114 {
7115         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7116         int ret = MM_ERROR_NONE;
7117
7118         MMPLAYER_FENTER();
7119
7120         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7121
7122         if (!player->pending_seek.is_pending) {
7123                 LOGD("pending seek is not reserved. nothing to do.\n");
7124                 return ret;
7125         }
7126
7127         /* check player state if player could pending seek or not. */
7128         current_state = MMPLAYER_CURRENT_STATE(player);
7129
7130         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7131                 LOGW("try to pending seek in %s state, try next time. \n",
7132                         MMPLAYER_STATE_GET_NAME(current_state));
7133                 return ret;
7134         }
7135
7136         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7137
7138         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7139
7140         if (MM_ERROR_NONE != ret)
7141                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7142
7143         player->pending_seek.is_pending = FALSE;
7144
7145         MMPLAYER_FLEAVE();
7146
7147         return ret;
7148 }
7149
7150 static int __gst_start(mm_player_t* player)
7151 {
7152         gboolean sound_extraction = 0;
7153         int ret = MM_ERROR_NONE;
7154         gboolean async = FALSE;
7155
7156         MMPLAYER_FENTER();
7157
7158         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7159
7160         /* get sound_extraction property */
7161         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7162
7163         /* NOTE : if SetPosition was called before Start. do it now */
7164         /* streaming doesn't support it. so it should be always sync */
7165         /* !!create one more api to check if there is pending seek rather than checking variables */
7166         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7167                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7168                 ret = __gst_pause(player, FALSE);
7169                 if (ret != MM_ERROR_NONE) {
7170                         LOGE("failed to set state to PAUSED for pending seek\n");
7171                         return ret;
7172                 }
7173
7174                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7175
7176                 if (sound_extraction) {
7177                         LOGD("setting pcm extraction\n");
7178
7179                         ret = __mmplayer_set_pcm_extraction(player);
7180                         if (MM_ERROR_NONE != ret) {
7181                                 LOGW("failed to set pcm extraction\n");
7182                                 return ret;
7183                         }
7184                 } else {
7185                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7186                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7187                 }
7188         }
7189
7190         LOGD("current state before doing transition");
7191         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7192         MMPLAYER_PRINT_STATE(player);
7193
7194         /* set pipeline state to PLAYING  */
7195         if (player->es_player_push_mode)
7196                 async = TRUE;
7197         /* set pipeline state to PLAYING  */
7198         ret = __mmplayer_gst_set_state(player,
7199                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7200
7201         if (ret == MM_ERROR_NONE) {
7202                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7203         } else {
7204                 LOGE("failed to set state to PLAYING");
7205                 return ret;
7206         }
7207
7208         /* generating debug info before returning error */
7209         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7210
7211         MMPLAYER_FLEAVE();
7212
7213         return ret;
7214 }
7215
7216 static int __gst_stop(mm_player_t* player)
7217 {
7218         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7219         MMHandleType attrs = 0;
7220         gboolean rewind = FALSE;
7221         gint timeout = 0;
7222         int ret = MM_ERROR_NONE;
7223         gboolean async = FALSE;
7224
7225         MMPLAYER_FENTER();
7226
7227         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7229
7230         LOGD("current state before doing transition");
7231         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7232         MMPLAYER_PRINT_STATE(player);
7233
7234         attrs = MMPLAYER_GET_ATTRS(player);
7235         if (!attrs) {
7236                 LOGE("cannot get content attribute\n");
7237                 return MM_ERROR_PLAYER_INTERNAL;
7238         }
7239
7240         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7241         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7242
7243         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7244                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7245                 rewind = TRUE;
7246
7247         if (player->es_player_push_mode)
7248                 async = TRUE;
7249         /* set gst state */
7250         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7251
7252         /* return if set_state has failed */
7253         if (ret != MM_ERROR_NONE) {
7254                 LOGE("failed to set state.\n");
7255                 return ret;
7256         }
7257
7258         /* rewind */
7259         if (rewind) {
7260                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7261                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7262                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7263                         LOGW("failed to rewind\n");
7264                         ret = MM_ERROR_PLAYER_SEEK;
7265                 }
7266         }
7267
7268         /* initialize */
7269         player->sent_bos = FALSE;
7270
7271         if (player->es_player_push_mode) //for cloudgame
7272                 timeout = 0;
7273
7274         /* wait for seek to complete */
7275         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7276         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7277                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7278         } else {
7279                 LOGE("fail to stop player.\n");
7280                 ret = MM_ERROR_PLAYER_INTERNAL;
7281                 __mmplayer_dump_pipeline_state(player);
7282         }
7283
7284         /* generate dot file if enabled */
7285         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7286
7287         MMPLAYER_FLEAVE();
7288
7289         return ret;
7290 }
7291
7292 int __gst_pause(mm_player_t* player, gboolean async)
7293 {
7294         int ret = MM_ERROR_NONE;
7295
7296         MMPLAYER_FENTER();
7297
7298         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7299         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7300
7301         LOGD("current state before doing transition");
7302         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7303         MMPLAYER_PRINT_STATE(player);
7304
7305         /* set pipeline status to PAUSED */
7306         ret = __mmplayer_gst_set_state(player,
7307                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7308
7309         if (FALSE == async) {
7310                 if (ret != MM_ERROR_NONE) {
7311                         GstMessage *msg = NULL;
7312                         GTimer *timer = NULL;
7313                         gdouble MAX_TIMEOUT_SEC = 3;
7314
7315                         LOGE("failed to set state to PAUSED");
7316
7317                         if (player->msg_posted) {
7318                                 LOGE("error msg is already posted.");
7319                                 return ret;
7320                         }
7321
7322                         timer = g_timer_new();
7323                         g_timer_start(timer);
7324
7325                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7326
7327                         do {
7328                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7329                                 if (msg) {
7330                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7331                                                 GError *error = NULL;
7332
7333                                                 /* parse error code */
7334                                                 gst_message_parse_error(msg, &error, NULL);
7335
7336                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7337                                                         /* Note : the streaming error from the streaming source is handled
7338                                                          *   using __mmplayer_handle_streaming_error.
7339                                                          */
7340                                                         __mmplayer_handle_streaming_error(player, msg);
7341
7342                                                 } else if (error) {
7343                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7344
7345                                                         if (error->domain == GST_STREAM_ERROR)
7346                                                                 ret = __gst_handle_stream_error(player, error, msg);
7347                                                         else if (error->domain == GST_RESOURCE_ERROR)
7348                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7349                                                         else if (error->domain == GST_LIBRARY_ERROR)
7350                                                                 ret = __gst_handle_library_error(player, error->code);
7351                                                         else if (error->domain == GST_CORE_ERROR)
7352                                                                 ret = __gst_handle_core_error(player, error->code);
7353
7354                                                         g_error_free(error);
7355                                                 }
7356                                                 player->msg_posted = TRUE;
7357                                         }
7358                                         gst_message_unref(msg);
7359                                 }
7360                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7361                         /* clean */
7362                         gst_object_unref(bus);
7363                         g_timer_stop(timer);
7364                         g_timer_destroy(timer);
7365
7366                         return ret;
7367
7368                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7369                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7370
7371                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7372
7373                 } else if (ret == MM_ERROR_NONE) {
7374
7375                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7376                 }
7377         }
7378
7379         /* generate dot file before returning error */
7380         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7381
7382         MMPLAYER_FLEAVE();
7383
7384         return ret;
7385 }
7386
7387 int __gst_resume(mm_player_t* player, gboolean async)
7388 {
7389         int ret = MM_ERROR_NONE;
7390         gint timeout = 0;
7391
7392         MMPLAYER_FENTER();
7393
7394         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7395                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7396
7397         LOGD("current state before doing transition");
7398         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7399         MMPLAYER_PRINT_STATE(player);
7400
7401         /* generate dot file before returning error */
7402         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7403
7404         if (async)
7405                 LOGD("do async state transition to PLAYING.\n");
7406
7407         /* set pipeline state to PLAYING */
7408         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7409
7410         ret = __mmplayer_gst_set_state(player,
7411                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7412         if (ret != MM_ERROR_NONE) {
7413                 LOGE("failed to set state to PLAYING\n");
7414                 return ret;
7415         } else {
7416                 if (async == FALSE) {
7417                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7418                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7419                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7420                 }
7421         }
7422
7423         /* generate dot file before returning error */
7424         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7425
7426         MMPLAYER_FLEAVE();
7427
7428         return ret;
7429 }
7430
7431 static int
7432 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7433 {
7434         unsigned long dur_msec = 0;
7435         gint64 dur_nsec = 0;
7436         gint64 pos_nsec = 0;
7437         gboolean ret = TRUE;
7438         gboolean accurated = FALSE;
7439         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7440
7441         MMPLAYER_FENTER();
7442         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7443         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7444
7445         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7446                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7447                 goto PENDING;
7448
7449         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7450                 /* check duration */
7451                 /* NOTE : duration cannot be zero except live streaming.
7452                  *              Since some element could have some timing problemn with quering duration, try again.
7453                  */
7454                 if (!player->duration) {
7455                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7456                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7457                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7458                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7459                                         player->pending_seek.is_pending = TRUE;
7460                                         player->pending_seek.format = format;
7461                                         player->pending_seek.pos = position;
7462                                         player->doing_seek = FALSE;
7463                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7464                                         return MM_ERROR_NONE;
7465                                 } else {
7466                                         goto SEEK_ERROR;
7467                                 }
7468                         }
7469                         player->duration = dur_nsec;
7470                 }
7471
7472                 if (player->duration) {
7473                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7474                 } else {
7475                         LOGE("could not get the duration. fail to seek.\n");
7476                         goto SEEK_ERROR;
7477                 }
7478         }
7479         LOGD("playback rate: %f\n", player->playback_rate);
7480
7481         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7482         if (accurated)
7483                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7484         else
7485                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7486
7487         /* do seek */
7488         switch (format) {
7489         case MM_PLAYER_POS_FORMAT_TIME:
7490         {
7491                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7492                         GstQuery *query = NULL;
7493                         gboolean seekable = FALSE;
7494
7495                         /* check position is valid or not */
7496                         if (position > dur_msec)
7497                                 goto INVALID_ARGS;
7498
7499                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7500                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7501                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7502                                 gst_query_unref(query);
7503
7504                                 if (!seekable) {
7505                                         LOGW("non-seekable content");
7506                                         player->doing_seek = FALSE;
7507                                         return MM_ERROR_PLAYER_NO_OP;
7508                                 }
7509                         } else {
7510                                 LOGW("failed to get seeking query");
7511                                 gst_query_unref(query); /* keep seeking operation */
7512                         }
7513
7514                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7515
7516                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7517                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7518                            This causes problem is position calculation during normal pause resume scenarios also.
7519                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7520                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7521                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7522                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7523                                         LOGW("getting current position failed in seek\n");
7524
7525                                 player->last_position = pos_nsec;
7526                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7527                         }
7528
7529                         if (player->doing_seek) {
7530                                 LOGD("not completed seek");
7531                                 return MM_ERROR_PLAYER_DOING_SEEK;
7532                         }
7533                 }
7534
7535                 if (!internal_called)
7536                         player->doing_seek = TRUE;
7537
7538                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7539
7540                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7541                         gint64 cur_time = 0;
7542
7543                         /* get current position */
7544                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7545
7546                         /* flush */
7547                         GstEvent *event = gst_event_new_seek(1.0,
7548                                                         GST_FORMAT_TIME,
7549                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7550                                                         GST_SEEK_TYPE_SET, cur_time,
7551                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7552                         if (event)
7553                                 __gst_send_event_to_sink(player, event);
7554
7555                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7556                                 __gst_pause(player, FALSE);
7557                 }
7558
7559                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7560                         that's why set position through property. */
7561                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7562                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7563                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7564                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7565
7566                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7567                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7568                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7569                         player->doing_seek = FALSE;
7570                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7571                 } else {
7572                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7573                                                         GST_FORMAT_TIME, seek_flags,
7574                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7575                 }
7576
7577                 if (!ret) {
7578                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7579                         goto SEEK_ERROR;
7580                 }
7581         }
7582         break;
7583
7584         case MM_PLAYER_POS_FORMAT_PERCENT:
7585         {
7586                 LOGD("seeking to(%lu)%% \n", position);
7587
7588                 if (player->doing_seek) {
7589                         LOGD("not completed seek");
7590                         return MM_ERROR_PLAYER_DOING_SEEK;
7591                 }
7592
7593                 if (!internal_called)
7594                         player->doing_seek = TRUE;
7595
7596                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7597                 pos_nsec = (gint64)((position * player->duration) / 100);
7598                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7599                                                 GST_FORMAT_TIME, seek_flags,
7600                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7601                 if (!ret) {
7602                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7603                         goto SEEK_ERROR;
7604                 }
7605         }
7606         break;
7607
7608         default:
7609                 goto INVALID_ARGS;
7610         }
7611
7612         /* NOTE : store last seeking point to overcome some bad operation
7613           *     (returning zero when getting current position) of some elements
7614           */
7615         player->last_position = pos_nsec;
7616
7617         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7618         if (player->playback_rate > 1.0)
7619                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7620
7621         MMPLAYER_FLEAVE();
7622         return MM_ERROR_NONE;
7623
7624 PENDING:
7625         player->pending_seek.is_pending = TRUE;
7626         player->pending_seek.format = format;
7627         player->pending_seek.pos = position;
7628
7629         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7630                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7631
7632         return MM_ERROR_NONE;
7633
7634 INVALID_ARGS:
7635         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7636         return MM_ERROR_INVALID_ARGUMENT;
7637
7638 SEEK_ERROR:
7639         player->doing_seek = FALSE;
7640         return MM_ERROR_PLAYER_SEEK;
7641 }
7642
7643 #define TRICKPLAY_OFFSET GST_MSECOND
7644
7645 static int
7646 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7647 {
7648         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7649         gint64 pos_msec = 0;
7650         gboolean ret = TRUE;
7651
7652         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7653                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7654
7655         current_state = MMPLAYER_CURRENT_STATE(player);
7656
7657         /* NOTE : query position except paused state to overcome some bad operation
7658          * please refer to below comments in details
7659          */
7660         if (current_state != MM_PLAYER_STATE_PAUSED)
7661                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7662
7663         /* NOTE : get last point to overcome some bad operation of some elements
7664          *(returning zero when getting current position in paused state
7665          * and when failed to get postion during seeking
7666          */
7667         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7668                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7669
7670                 if (player->playback_rate < 0.0)
7671                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7672                 else
7673                         pos_msec = player->last_position;
7674
7675                 if (!ret)
7676                         pos_msec = player->last_position;
7677                 else
7678                         player->last_position = pos_msec;
7679
7680                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7681
7682         } else {
7683                 if (player->duration > 0 && pos_msec > player->duration)
7684                         pos_msec = player->duration;
7685
7686                 player->last_position = pos_msec;
7687         }
7688
7689         switch (format) {
7690         case MM_PLAYER_POS_FORMAT_TIME:
7691                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7692                 break;
7693
7694         case MM_PLAYER_POS_FORMAT_PERCENT:
7695         {
7696                 if (player->duration <= 0) {
7697                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7698                         *position = 0;
7699                 } else {
7700                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7701                         *position = pos_msec * 100 / player->duration;
7702                 }
7703                 break;
7704         }
7705         default:
7706                 return MM_ERROR_PLAYER_INTERNAL;
7707         }
7708
7709         return MM_ERROR_NONE;
7710 }
7711
7712
7713 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7714 {
7715 #define STREAMING_IS_FINISHED   0
7716 #define BUFFERING_MAX_PER       100
7717 #define DEFAULT_PER_VALUE       -1
7718 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7719
7720         MMPlayerGstElement *mainbin = NULL;
7721         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7722         gint64 buffered_total = 0;
7723         unsigned long position = 0;
7724         gint buffered_sec = -1;
7725         GstBufferingMode mode = GST_BUFFERING_STREAM;
7726         gint64 content_size_time = player->duration;
7727         guint64 content_size_bytes = player->http_content_size;
7728
7729         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7730                                                 player->pipeline &&
7731                                                 player->pipeline->mainbin,
7732                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7733
7734         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7735
7736         *start_pos = 0;
7737         *stop_pos = 0;
7738
7739         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7740                 /* and rtsp is not ready yet. */
7741                 LOGW("it's only used for http streaming case.\n");
7742                 return MM_ERROR_PLAYER_NO_OP;
7743         }
7744
7745         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7746                 LOGW("Time format is not supported yet.\n");
7747                 return MM_ERROR_INVALID_ARGUMENT;
7748         }
7749
7750         if (content_size_time <= 0 || content_size_bytes <= 0) {
7751                 LOGW("there is no content size.");
7752                 return MM_ERROR_NONE;
7753         }
7754
7755         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7756                 LOGW("fail to get current position.");
7757                 return MM_ERROR_NONE;
7758         }
7759
7760         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7761                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7762
7763         mainbin = player->pipeline->mainbin;
7764         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7765
7766         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7767                 GstQuery *query = NULL;
7768                 gint byte_in_rate = 0, byte_out_rate = 0;
7769                 gint64 estimated_total = 0;
7770
7771                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7772                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7773                         LOGW("fail to get buffering query from queue2");
7774                         if (query)
7775                                 gst_query_unref(query);
7776                         return MM_ERROR_NONE;
7777                 }
7778
7779                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7780                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7781
7782                 if (mode == GST_BUFFERING_STREAM) {
7783                         /* using only queue in case of push mode(ts / mp3) */
7784                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7785                                 GST_FORMAT_BYTES, &buffered_total)) {
7786                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7787                                 stop_per = 100 * buffered_total / content_size_bytes;
7788                         }
7789                 } else {
7790                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7791                         guint idx = 0;
7792                         guint num_of_ranges = 0;
7793                         gint64 start_byte = 0, stop_byte = 0;
7794
7795                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7796                         if (estimated_total != STREAMING_IS_FINISHED) {
7797                                 /* buffered size info from queue2 */
7798                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7799                                 for (idx = 0; idx < num_of_ranges; idx++) {
7800                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7801                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7802
7803                                         buffered_total += (stop_byte - start_byte);
7804                                 }
7805                         } else
7806                                 stop_per = BUFFERING_MAX_PER;
7807                 }
7808                 gst_query_unref(query);
7809         }
7810
7811         if (stop_per == DEFAULT_PER_VALUE) {
7812                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7813                 if (dur_sec > 0) {
7814                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7815
7816                         /* buffered size info from multiqueue */
7817                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7818                                 guint curr_size_bytes = 0;
7819                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7820                                         "curr-size-bytes", &curr_size_bytes, NULL);
7821                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7822                                 buffered_total += curr_size_bytes;
7823                         }
7824
7825                         if (avg_byterate > 0)
7826                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7827                         else if (player->total_maximum_bitrate > 0)
7828                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7829                         else if (player->total_bitrate > 0)
7830                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7831
7832                         if (buffered_sec >= 0)
7833                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7834                 }
7835         }
7836
7837         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7838         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7839
7840         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7841                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7842
7843         return MM_ERROR_NONE;
7844 }
7845
7846 static int
7847 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7848 {
7849         MMPLAYER_FENTER();
7850
7851         if (!player) {
7852                 LOGW("set_message_callback is called with invalid player handle\n");
7853                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7854         }
7855
7856         player->msg_cb = callback;
7857         player->msg_cb_param = user_param;
7858
7859         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7860
7861         MMPLAYER_FLEAVE();
7862
7863         return MM_ERROR_NONE;
7864 }
7865
7866 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7867 {
7868         int ret = MM_ERROR_PLAYER_INVALID_URI;
7869         char *path = NULL;
7870
7871         MMPLAYER_FENTER();
7872
7873         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7874         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7875         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7876
7877         memset(data, 0, sizeof(MMPlayerParseProfile));
7878
7879         if ((path = strstr(uri, "es_buff://"))) {
7880                 if (strlen(path)) {
7881                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7883                         ret = MM_ERROR_NONE;
7884                 }
7885         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7886                 if (strlen(path)) {
7887                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7888                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7889                         ret = MM_ERROR_NONE;
7890                 }
7891         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7892                 if (strlen(path)) {
7893                         gchar *tmp = NULL;
7894                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7895                         tmp = g_ascii_strdown(uri, strlen(uri));
7896
7897                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7898                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7899                         else
7900                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7901
7902                         ret = MM_ERROR_NONE;
7903                         g_free(tmp);
7904                 }
7905         } else if ((path = strstr(uri, "rtspu://"))) {
7906                 if (strlen(path)) {
7907                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7908                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7909                         ret = MM_ERROR_NONE;
7910                 }
7911         } else if ((path = strstr(uri, "rtspr://"))) {
7912                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7913                 char *separater = strstr(path, "*");
7914
7915                 if (separater) {
7916                         int urgent_len = 0;
7917                         char *urgent = separater + strlen("*");
7918
7919                         if ((urgent_len = strlen(urgent))) {
7920                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7921                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7922                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7923                                 ret = MM_ERROR_NONE;
7924                         }
7925                 }
7926         } else if ((path = strstr(uri, "mms://"))) {
7927                 if (strlen(path)) {
7928                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7929                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7930                         ret = MM_ERROR_NONE;
7931                 }
7932         } else if ((path = strstr(uri, "mem://"))) {
7933                 if (strlen(path)) {
7934                         int mem_size = 0;
7935                         char *buffer = NULL;
7936                         char *seperator = strchr(path, ',');
7937                         char ext[100] = {0,}, size[100] = {0,};
7938
7939                         if (seperator) {
7940                                 if ((buffer = strstr(path, "ext="))) {
7941                                         buffer += strlen("ext=");
7942
7943                                         if (strlen(buffer)) {
7944                                                 strncpy(ext, buffer, 99);
7945
7946                                                 if ((seperator = strchr(ext, ','))
7947                                                         || (seperator = strchr(ext, ' '))
7948                                                         || (seperator = strchr(ext, '\0'))) {
7949                                                         seperator[0] = '\0';
7950                                                 }
7951                                         }
7952                                 }
7953
7954                                 if ((buffer = strstr(path, "size="))) {
7955                                         buffer += strlen("size=");
7956
7957                                         if (strlen(buffer) > 0) {
7958                                                 strncpy(size, buffer, 99);
7959
7960                                                 if ((seperator = strchr(size, ','))
7961                                                         || (seperator = strchr(size, ' '))
7962                                                         || (seperator = strchr(size, '\0'))) {
7963                                                         seperator[0] = '\0';
7964                                                 }
7965
7966                                                 mem_size = atoi(size);
7967                                         }
7968                                 }
7969                         }
7970
7971                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7972                         if (mem_size && param) {
7973                                 if (data->input_mem.buf)
7974                                         free(data->input_mem.buf);
7975                                 data->input_mem.buf = malloc(mem_size);
7976
7977                                 if (data->input_mem.buf) {
7978                                         memcpy(data->input_mem.buf, param, mem_size);
7979                                         data->input_mem.len = mem_size;
7980                                         ret = MM_ERROR_NONE;
7981                                 } else {
7982                                         LOGE("failed to alloc mem %d", mem_size);
7983                                         ret = MM_ERROR_PLAYER_INTERNAL;
7984                                 }
7985
7986                                 data->input_mem.offset = 0;
7987                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7988                         }
7989                 }
7990         } else {
7991                 gchar *location = NULL;
7992                 GError *err = NULL;
7993
7994                 if ((path = strstr(uri, "file://"))) {
7995
7996                         location = g_filename_from_uri(uri, NULL, &err);
7997
7998                         if (!location || (err != NULL)) {
7999                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8000                                  (err != NULL) ? err->message : "unknown error");
8001
8002                           if (err) g_error_free(err);
8003                           if (location) g_free(location);
8004
8005                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8006                           goto exit;
8007                         }
8008
8009                         LOGD("path from uri: %s", location);
8010                 }
8011
8012                 path = (location != NULL) ? (location) : ((char*)uri);
8013                 int file_stat = MM_ERROR_NONE;
8014
8015                 file_stat = util_exist_file_path(path);
8016
8017                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8018                 if (file_stat == MM_ERROR_NONE) {
8019                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8020
8021                         if (util_is_sdp_file(path)) {
8022                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8023                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8024                         } else {
8025                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8026                         }
8027                         ret = MM_ERROR_NONE;
8028                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8029                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8030                 } else {
8031                         LOGE("invalid uri, could not play..\n");
8032                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8033                 }
8034
8035                 if (location) g_free(location);
8036         }
8037
8038 exit:
8039         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8040                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8041         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8042                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8043
8044         /* dump parse result */
8045         SECURE_LOGW("incomming uri : %s\n", uri);
8046         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8047                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8048
8049         MMPLAYER_FLEAVE();
8050
8051         return ret;
8052 }
8053
8054 gboolean
8055 __mmplayer_can_do_interrupt(mm_player_t *player)
8056 {
8057         if (!player || !player->pipeline || !player->attrs) {
8058                 LOGW("not initialized");
8059                 goto FAILED;
8060         }
8061
8062         if (player->set_mode.pcm_extraction) {
8063                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8064                 goto FAILED;
8065         }
8066
8067         /* check if seeking */
8068         if (player->doing_seek) {
8069                 MMMessageParamType msg_param;
8070                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8071                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8072                 player->doing_seek = FALSE;
8073                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8074                 goto FAILED;
8075         }
8076
8077         /* check other thread */
8078         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8079                 LOGW("locked already, cmd state : %d", player->cmd);
8080
8081                 /* check application command */
8082                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8083                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8084
8085                         /* lock will be released at mrp_resource_release_cb() */
8086                         MMPLAYER_CMD_LOCK(player);
8087                         goto INTERRUPT;
8088                 }
8089                 LOGW("nothing to do");
8090                 goto FAILED;
8091         } else {
8092                 LOGW("can interrupt immediately");
8093                 goto INTERRUPT;
8094         }
8095
8096 FAILED:    /* with CMD UNLOCKED */
8097         return FALSE;
8098
8099 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8100         return TRUE;
8101 }
8102
8103 static int
8104 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8105                 void *user_data)
8106 {
8107         mm_player_t *player = NULL;
8108
8109         MMPLAYER_FENTER();
8110
8111         if (user_data == NULL) {
8112                 LOGE("- user_data is null\n");
8113                 return FALSE;
8114         }
8115         player = (mm_player_t *)user_data;
8116
8117         /* do something to release resource here.
8118          * player stop and interrupt forwarding */
8119         if (!__mmplayer_can_do_interrupt(player)) {
8120                 LOGW("no need to interrupt, so leave");
8121         } else {
8122                 MMMessageParamType msg = {0, };
8123                 unsigned long pos = 0;
8124
8125                 player->interrupted_by_resource = TRUE;
8126
8127                 /* get last play position */
8128                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8129                         LOGW("failed to get play position.");
8130                 } else {
8131                         msg.union_type = MM_MSG_UNION_TIME;
8132                         msg.time.elapsed = (unsigned int)pos;
8133                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8134                 }
8135                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8136                 if (_mmplayer_unrealize((MMHandleType)player))
8137                         LOGW("failed to unrealize");
8138
8139                 /* lock is called in __mmplayer_can_do_interrupt() */
8140                 MMPLAYER_CMD_UNLOCK(player);
8141         }
8142
8143         if (res == player->video_overlay_resource)
8144                 player->video_overlay_resource = FALSE;
8145         else
8146                 player->video_decoder_resource = FALSE;
8147
8148         MMPLAYER_FLEAVE();
8149
8150         return FALSE;
8151 }
8152
8153 int
8154 _mmplayer_create_player(MMHandleType handle)
8155 {
8156         int ret = MM_ERROR_PLAYER_INTERNAL;
8157         bool enabled = false;
8158
8159         mm_player_t* player = MM_PLAYER_CAST(handle);
8160
8161         MMPLAYER_FENTER();
8162
8163         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8164
8165         /* initialize player state */
8166         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8167         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8168         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8169         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8170
8171         /* check current state */
8172         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8173
8174         /* construct attributes */
8175         player->attrs = _mmplayer_construct_attribute(handle);
8176
8177         if (!player->attrs) {
8178                 LOGE("Failed to construct attributes\n");
8179                 return ret;
8180         }
8181
8182         /* initialize gstreamer with configured parameter */
8183         if (!__mmplayer_init_gstreamer(player)) {
8184                 LOGE("Initializing gstreamer failed\n");
8185                 _mmplayer_deconstruct_attribute(handle);
8186                 return ret;
8187         }
8188
8189         /* create lock. note that g_tread_init() has already called in gst_init() */
8190         g_mutex_init(&player->fsink_lock);
8191
8192         /* create update tag lock */
8193         g_mutex_init(&player->update_tag_lock);
8194
8195         /* create next play mutex */
8196         g_mutex_init(&player->next_play_thread_mutex);
8197
8198         /* create next play cond */
8199         g_cond_init(&player->next_play_thread_cond);
8200
8201         /* create next play thread */
8202         player->next_play_thread =
8203                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8204         if (!player->next_play_thread) {
8205                 LOGE("failed to create next play thread");
8206                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8207                 g_mutex_clear(&player->next_play_thread_mutex);
8208                 g_cond_clear(&player->next_play_thread_cond);
8209                 goto ERROR;
8210         }
8211
8212         ret = _mmplayer_initialize_video_capture(player);
8213         if (ret != MM_ERROR_NONE) {
8214                 LOGE("failed to initialize video capture\n");
8215                 goto ERROR;
8216         }
8217
8218         /* initialize resource manager */
8219         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8220                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8221                         &player->resource_manager)) {
8222                 LOGE("failed to initialize resource manager\n");
8223                 goto ERROR;
8224         }
8225
8226         if (MMPLAYER_IS_HTTP_PD(player)) {
8227                 player->pd_downloader = NULL;
8228                 player->pd_file_save_path = NULL;
8229         }
8230
8231         /* create video bo lock and cond */
8232         g_mutex_init(&player->video_bo_mutex);
8233         g_cond_init(&player->video_bo_cond);
8234
8235         /* create media stream callback mutex */
8236         g_mutex_init(&player->media_stream_cb_lock);
8237
8238         /* create subtitle info lock and cond */
8239         g_mutex_init(&player->subtitle_info_mutex);
8240         g_cond_init(&player->subtitle_info_cond);
8241
8242         player->streaming_type = STREAMING_SERVICE_NONE;
8243
8244         /* give default value of audio effect setting */
8245         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8246         player->sound.rg_enable = false;
8247         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8248
8249         player->play_subtitle = FALSE;
8250         player->use_deinterleave = FALSE;
8251         player->max_audio_channels = 0;
8252         player->video_share_api_delta = 0;
8253         player->video_share_clock_delta = 0;
8254         player->has_closed_caption = FALSE;
8255         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8256         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8257         player->pending_resume = FALSE;
8258         if (player->ini.dump_element_keyword[0][0] == '\0')
8259                 player->ini.set_dump_element_flag = FALSE;
8260         else
8261                 player->ini.set_dump_element_flag = TRUE;
8262
8263         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8264         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8265         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8266
8267         /* Set video360 settings to their defaults for just-created player.
8268          * */
8269
8270         player->is_360_feature_enabled = FALSE;
8271         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8272                 LOGI("spherical feature info: %d", enabled);
8273                 if (enabled)
8274                         player->is_360_feature_enabled = TRUE;
8275         } else {
8276                 LOGE("failed to get spherical feature info");
8277         }
8278
8279         player->is_content_spherical = FALSE;
8280         player->is_video360_enabled = TRUE;
8281         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8282         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8283         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8284         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8285         player->video360_zoom = 1.0f;
8286         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8287         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8288
8289         /* set player state to null */
8290         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8291         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8292
8293         return MM_ERROR_NONE;
8294
8295 ERROR:
8296         /* free lock */
8297         g_mutex_clear(&player->fsink_lock);
8298
8299         /* free update tag lock */
8300         g_mutex_clear(&player->update_tag_lock);
8301
8302         /* free next play thread */
8303         if (player->next_play_thread) {
8304                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8305                 player->next_play_thread_exit = TRUE;
8306                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8307                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8308
8309                 g_thread_join(player->next_play_thread);
8310                 player->next_play_thread = NULL;
8311
8312                 g_mutex_clear(&player->next_play_thread_mutex);
8313                 g_cond_clear(&player->next_play_thread_cond);
8314         }
8315
8316         /* release attributes */
8317         _mmplayer_deconstruct_attribute(handle);
8318
8319         MMPLAYER_FLEAVE();
8320
8321         return ret;
8322 }
8323
8324 static gboolean
8325 __mmplayer_init_gstreamer(mm_player_t* player)
8326 {
8327         static gboolean initialized = FALSE;
8328         static const int max_argc = 50;
8329         gint* argc = NULL;
8330         gchar** argv = NULL;
8331         gchar** argv2 = NULL;
8332         GError *err = NULL;
8333         int i = 0;
8334         int arg_count = 0;
8335
8336         if (initialized) {
8337                 LOGD("gstreamer already initialized.\n");
8338                 return TRUE;
8339         }
8340
8341         /* alloc */
8342         argc = malloc(sizeof(int));
8343         argv = malloc(sizeof(gchar*) * max_argc);
8344         argv2 = malloc(sizeof(gchar*) * max_argc);
8345
8346         if (!argc || !argv || !argv2)
8347                 goto ERROR;
8348
8349         memset(argv, 0, sizeof(gchar*) * max_argc);
8350         memset(argv2, 0, sizeof(gchar*) * max_argc);
8351
8352         /* add initial */
8353         *argc = 1;
8354         argv[0] = g_strdup("mmplayer");
8355
8356         /* add gst_param */
8357         for (i = 0; i < 5; i++) {
8358                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8359                 if (strlen(player->ini.gst_param[i]) > 0) {
8360                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8361                         (*argc)++;
8362                 }
8363         }
8364
8365         /* we would not do fork for scanning plugins */
8366         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8367         (*argc)++;
8368
8369         /* check disable registry scan */
8370         if (player->ini.skip_rescan) {
8371                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8372                 (*argc)++;
8373         }
8374
8375         /* check disable segtrap */
8376         if (player->ini.disable_segtrap) {
8377                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8378                 (*argc)++;
8379         }
8380
8381         LOGD("initializing gstreamer with following parameter\n");
8382         LOGD("argc : %d\n", *argc);
8383         arg_count = *argc;
8384
8385         for (i = 0; i < arg_count; i++) {
8386                 argv2[i] = argv[i];
8387                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8388         }
8389
8390         /* initializing gstreamer */
8391         if (!gst_init_check(argc, &argv, &err)) {
8392                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8393                 if (err)
8394                         g_error_free(err);
8395
8396                 goto ERROR;
8397         }
8398         /* release */
8399         for (i = 0; i < arg_count; i++) {
8400                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8401                 MMPLAYER_FREEIF(argv2[i]);
8402         }
8403
8404         MMPLAYER_FREEIF(argv);
8405         MMPLAYER_FREEIF(argv2);
8406         MMPLAYER_FREEIF(argc);
8407
8408         /* done */
8409         initialized = TRUE;
8410
8411         return TRUE;
8412
8413 ERROR:
8414
8415         /* release */
8416         for (i = 0; i < arg_count; i++) {
8417                 LOGD("free[%d] : %s\n", i, argv2[i]);
8418                 MMPLAYER_FREEIF(argv2[i]);
8419         }
8420
8421         MMPLAYER_FREEIF(argv);
8422         MMPLAYER_FREEIF(argv2);
8423         MMPLAYER_FREEIF(argc);
8424
8425         return FALSE;
8426 }
8427
8428 int
8429 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8430 {
8431         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8432
8433         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8434                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8435                 MMPLAYER_FREEIF(player->pd_file_save_path);
8436         }
8437
8438         return MM_ERROR_NONE;
8439 }
8440
8441 static void
8442 __mmplayer_check_async_state_transition(mm_player_t* player)
8443 {
8444         GstState element_state = GST_STATE_VOID_PENDING;
8445         GstState element_pending_state = GST_STATE_VOID_PENDING;
8446         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8447         GstElement * element = NULL;
8448         gboolean async = FALSE;
8449
8450         /* check player handle */
8451         MMPLAYER_RETURN_IF_FAIL(player &&
8452                                                 player->pipeline &&
8453                                                 player->pipeline->mainbin &&
8454                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8455
8456         if (player->attrs)
8457                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8458
8459         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8460                 LOGD("don't need to check the pipeline state");
8461                 return;
8462         }
8463
8464         MMPLAYER_PRINT_STATE(player);
8465
8466         /* wait for state transition */
8467         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8468         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8469
8470         if (ret == GST_STATE_CHANGE_FAILURE) {
8471                 LOGE(" [%s] state : %s   pending : %s \n",
8472                         GST_ELEMENT_NAME(element),
8473                         gst_element_state_get_name(element_state),
8474                         gst_element_state_get_name(element_pending_state));
8475
8476                 /* dump state of all element */
8477                 __mmplayer_dump_pipeline_state(player);
8478
8479                 return;
8480         }
8481
8482         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8483         return;
8484 }
8485
8486 int
8487 _mmplayer_destroy(MMHandleType handle)
8488 {
8489         mm_player_t* player = MM_PLAYER_CAST(handle);
8490
8491         MMPLAYER_FENTER();
8492
8493         /* check player handle */
8494         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8495
8496         /* destroy can called at anytime */
8497         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8498
8499         /* check async state transition */
8500         __mmplayer_check_async_state_transition(player);
8501
8502         __mmplayer_destroy_streaming_ext(player);
8503
8504         /* release next play thread */
8505         if (player->next_play_thread) {
8506                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8507                 player->next_play_thread_exit = TRUE;
8508                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8509                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8510
8511                 LOGD("waitting for next play thread exit\n");
8512                 g_thread_join(player->next_play_thread);
8513                 g_mutex_clear(&player->next_play_thread_mutex);
8514                 g_cond_clear(&player->next_play_thread_cond);
8515                 LOGD("next play thread released\n");
8516         }
8517
8518         _mmplayer_release_video_capture(player);
8519
8520         /* de-initialize resource manager */
8521         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8522                         player->resource_manager))
8523                 LOGE("failed to deinitialize resource manager\n");
8524
8525         /* release pipeline */
8526         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8527                 LOGE("failed to destory pipeline\n");
8528                 return MM_ERROR_PLAYER_INTERNAL;
8529         }
8530
8531         /* release subtitle info lock and cond */
8532         g_mutex_clear(&player->subtitle_info_mutex);
8533         g_cond_clear(&player->subtitle_info_cond);
8534
8535         __mmplayer_release_dump_list(player->dump_list);
8536
8537         /* release miscellaneous information */
8538         __mmplayer_release_misc(player);
8539
8540         /* release miscellaneous information.
8541            these info needs to be released after pipeline is destroyed. */
8542         __mmplayer_release_misc_post(player);
8543
8544         /* release attributes */
8545         _mmplayer_deconstruct_attribute(handle);
8546
8547         /* release lock */
8548         g_mutex_clear(&player->fsink_lock);
8549
8550         /* release lock */
8551         g_mutex_clear(&player->update_tag_lock);
8552
8553         /* release video bo lock and cond */
8554         g_mutex_clear(&player->video_bo_mutex);
8555         g_cond_clear(&player->video_bo_cond);
8556
8557         /* release media stream callback lock */
8558         g_mutex_clear(&player->media_stream_cb_lock);
8559
8560         MMPLAYER_FLEAVE();
8561
8562         return MM_ERROR_NONE;
8563 }
8564
8565 int
8566 __mmplayer_realize_streaming_ext(mm_player_t* player)
8567 {
8568         int ret = MM_ERROR_NONE;
8569
8570         MMPLAYER_FENTER();
8571         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8572
8573         if (MMPLAYER_IS_HTTP_PD(player)) {
8574                 gboolean bret = FALSE;
8575
8576                 player->pd_downloader = _mmplayer_create_pd_downloader();
8577                 if (!player->pd_downloader) {
8578                         LOGE("Unable to create PD Downloader...");
8579                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8580                 }
8581
8582                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8583
8584                 if (FALSE == bret) {
8585                         LOGE("Unable to create PD Downloader...");
8586                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8587                 }
8588         }
8589
8590         MMPLAYER_FLEAVE();
8591         return ret;
8592 }
8593
8594 int
8595 _mmplayer_realize(MMHandleType hplayer)
8596 {
8597         mm_player_t* player = (mm_player_t*)hplayer;
8598         char *uri = NULL;
8599         void *param = NULL;
8600         MMHandleType attrs = 0;
8601         int ret = MM_ERROR_NONE;
8602
8603         MMPLAYER_FENTER();
8604
8605         /* check player handle */
8606         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8607
8608         /* check current state */
8609         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8610
8611         attrs = MMPLAYER_GET_ATTRS(player);
8612         if (!attrs) {
8613                 LOGE("fail to get attributes.\n");
8614                 return MM_ERROR_PLAYER_INTERNAL;
8615         }
8616         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8617         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8618
8619         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8620                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8621
8622                 if (ret != MM_ERROR_NONE) {
8623                         LOGE("failed to parse profile\n");
8624                         return ret;
8625                 }
8626         }
8627
8628         if (uri && (strstr(uri, "es_buff://"))) {
8629                 if (strstr(uri, "es_buff://push_mode"))
8630                         player->es_player_push_mode = TRUE;
8631                 else
8632                         player->es_player_push_mode = FALSE;
8633         }
8634
8635         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8636                 LOGW("mms protocol is not supported format.\n");
8637                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8638         }
8639
8640         if (MMPLAYER_IS_STREAMING(player))
8641                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8642         else
8643                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8644
8645         player->smooth_streaming = FALSE;
8646         player->videodec_linked  = 0;
8647         player->videosink_linked = 0;
8648         player->audiodec_linked  = 0;
8649         player->audiosink_linked = 0;
8650         player->textsink_linked = 0;
8651         player->is_external_subtitle_present = FALSE;
8652         player->is_external_subtitle_added_now = FALSE;
8653         /* set the subtitle ON default */
8654         player->is_subtitle_off = FALSE;
8655
8656         /* realize pipeline */
8657         ret = __gst_realize(player);
8658         if (ret != MM_ERROR_NONE)
8659                 LOGE("fail to realize the player.\n");
8660         else
8661                 ret = __mmplayer_realize_streaming_ext(player);
8662
8663         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8664         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8665
8666         MMPLAYER_FLEAVE();
8667
8668         return ret;
8669 }
8670
8671 int
8672 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8673 {
8674         MMPLAYER_FENTER();
8675         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676
8677         /* destroy can called at anytime */
8678         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8679                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8680
8681         MMPLAYER_FLEAVE();
8682         return MM_ERROR_NONE;
8683 }
8684
8685 int
8686 _mmplayer_unrealize(MMHandleType hplayer)
8687 {
8688         mm_player_t* player = (mm_player_t*)hplayer;
8689         int ret = MM_ERROR_NONE;
8690
8691         MMPLAYER_FENTER();
8692
8693         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8694
8695         MMPLAYER_CMD_UNLOCK(player);
8696         /* destroy the gst bus msg thread which is created during realize.
8697            this funct have to be called before getting cmd lock. */
8698         _mmplayer_bus_msg_thread_destroy(player);
8699         MMPLAYER_CMD_LOCK(player);
8700
8701         /* check current state */
8702         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8703
8704         /* check async state transition */
8705         __mmplayer_check_async_state_transition(player);
8706
8707         __mmplayer_unrealize_streaming_ext(player);
8708
8709         /* unrealize pipeline */
8710         ret = __gst_unrealize(player);
8711
8712         /* set asm stop if success */
8713         if (MM_ERROR_NONE == ret) {
8714                 if (!player->interrupted_by_resource) {
8715                         if (player->video_decoder_resource != NULL) {
8716                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8717                                                 player->video_decoder_resource);
8718                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8719                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8720                                 else
8721                                         player->video_decoder_resource = NULL;
8722                         }
8723
8724                         if (player->video_overlay_resource != NULL) {
8725                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8726                                                 player->video_overlay_resource);
8727                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8728                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8729                                 else
8730                                         player->video_overlay_resource = NULL;
8731                         }
8732
8733                         ret = mm_resource_manager_commit(player->resource_manager);
8734                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8735                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8736                 }
8737         } else
8738                 LOGE("failed and don't change asm state to stop");
8739
8740         MMPLAYER_FLEAVE();
8741
8742         return ret;
8743 }
8744
8745 int
8746 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8747 {
8748         mm_player_t* player = (mm_player_t*)hplayer;
8749
8750         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8751
8752         return __gst_set_message_callback(player, callback, user_param);
8753 }
8754
8755 int
8756 _mmplayer_get_state(MMHandleType hplayer, int* state)
8757 {
8758         mm_player_t *player = (mm_player_t*)hplayer;
8759
8760         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8761
8762         *state = MMPLAYER_CURRENT_STATE(player);
8763
8764         return MM_ERROR_NONE;
8765 }
8766
8767
8768 int
8769 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8770 {
8771         mm_player_t* player = (mm_player_t*) hplayer;
8772         GstElement* vol_element = NULL;
8773         int i = 0;
8774
8775         MMPLAYER_FENTER();
8776
8777         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8778
8779         LOGD("volume [L]=%f:[R]=%f\n",
8780                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8781
8782         /* invalid factor range or not */
8783         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8784                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8785                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8786                         return MM_ERROR_INVALID_ARGUMENT;
8787                 }
8788         }
8789
8790         /* not support to set other value into each channel */
8791         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8792                 return MM_ERROR_INVALID_ARGUMENT;
8793
8794         /* Save volume to handle. Currently the first array element will be saved. */
8795         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8796
8797         /* check pipeline handle */
8798         if (!player->pipeline || !player->pipeline->audiobin) {
8799                 LOGD("audiobin is not created yet\n");
8800                 LOGD("but, current stored volume will be set when it's created.\n");
8801
8802                 /* NOTE : stored volume will be used in create_audiobin
8803                  * returning MM_ERROR_NONE here makes application to able to
8804                  * set volume at anytime.
8805                  */
8806                 return MM_ERROR_NONE;
8807         }
8808
8809         /* setting volume to volume element */
8810         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8811
8812         if (vol_element) {
8813                 LOGD("volume is set [%f]\n", player->sound.volume);
8814                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8815         }
8816
8817         MMPLAYER_FLEAVE();
8818
8819         return MM_ERROR_NONE;
8820 }
8821
8822
8823 int
8824 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8825 {
8826         mm_player_t* player = (mm_player_t*) hplayer;
8827         int i = 0;
8828
8829         MMPLAYER_FENTER();
8830
8831         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8832         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8833
8834         /* returning stored volume */
8835         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8836                 volume->level[i] = player->sound.volume;
8837
8838         MMPLAYER_FLEAVE();
8839
8840         return MM_ERROR_NONE;
8841 }
8842
8843 int
8844 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8845 {
8846         mm_player_t* player = (mm_player_t*) hplayer;
8847         GstElement* vol_element = NULL;
8848
8849         MMPLAYER_FENTER();
8850
8851         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8852
8853         /* mute value shoud 0 or 1 */
8854         if (mute != 0 && mute != 1) {
8855                 LOGE("bad mute value\n");
8856
8857                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8858                 return MM_ERROR_INVALID_ARGUMENT;
8859         }
8860
8861         player->sound.mute = mute;
8862
8863         /* just hold mute value if pipeline is not ready */
8864         if (!player->pipeline || !player->pipeline->audiobin) {
8865                 LOGD("pipeline is not ready. holding mute value\n");
8866                 return MM_ERROR_NONE;
8867         }
8868
8869         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8870
8871         /* NOTE : volume will only created when the bt is enabled */
8872         if (vol_element) {
8873                 LOGD("mute : %d\n", mute);
8874                 g_object_set(vol_element, "mute", mute, NULL);
8875         } else
8876                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8877
8878         MMPLAYER_FLEAVE();
8879
8880         return MM_ERROR_NONE;
8881 }
8882
8883 int
8884 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8885 {
8886         mm_player_t* player = (mm_player_t*) hplayer;
8887
8888         MMPLAYER_FENTER();
8889
8890         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8891         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8892
8893         /* just hold mute value if pipeline is not ready */
8894         if (!player->pipeline || !player->pipeline->audiobin) {
8895                 LOGD("pipeline is not ready. returning stored value\n");
8896                 *pmute = player->sound.mute;
8897                 return MM_ERROR_NONE;
8898         }
8899
8900         *pmute = player->sound.mute;
8901
8902         MMPLAYER_FLEAVE();
8903
8904         return MM_ERROR_NONE;
8905 }
8906
8907 int
8908 _mmplayer_set_videostream_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->video_stream_changed_cb = callback;
8917         player->video_stream_changed_cb_user_param = user_param;
8918         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8919
8920         MMPLAYER_FLEAVE();
8921
8922         return MM_ERROR_NONE;
8923 }
8924
8925 int
8926 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback 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_changed_cb = callback;
8935         player->audio_stream_changed_cb_user_param = user_param;
8936         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8937
8938         MMPLAYER_FLEAVE();
8939
8940         return MM_ERROR_NONE;
8941 }
8942
8943 int
8944 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8945 {
8946         mm_player_t* player = (mm_player_t*) hplayer;
8947
8948         MMPLAYER_FENTER();
8949
8950         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8951
8952         player->audio_stream_render_cb_ex = callback;
8953         player->audio_stream_cb_user_param = user_param;
8954         player->audio_stream_sink_sync = sync;
8955         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);
8956
8957         MMPLAYER_FLEAVE();
8958
8959         return MM_ERROR_NONE;
8960 }
8961
8962 int
8963 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8964 {
8965         mm_player_t* player = (mm_player_t*) hplayer;
8966
8967         MMPLAYER_FENTER();
8968
8969         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8970
8971         if (callback && !player->bufmgr)
8972                 player->bufmgr = tbm_bufmgr_init(-1);
8973
8974         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8975         player->video_stream_cb = callback;
8976         player->video_stream_cb_user_param = user_param;
8977
8978         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8979
8980         MMPLAYER_FLEAVE();
8981
8982         return MM_ERROR_NONE;
8983 }
8984
8985 int
8986 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8987 {
8988         mm_player_t* player = (mm_player_t*) hplayer;
8989
8990         MMPLAYER_FENTER();
8991
8992         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8993
8994         player->audio_stream_cb = callback;
8995         player->audio_stream_cb_user_param = user_param;
8996         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8997
8998         MMPLAYER_FLEAVE();
8999
9000         return MM_ERROR_NONE;
9001 }
9002
9003 static int
9004 __mmplayer_start_streaming_ext(mm_player_t *player)
9005 {
9006         gint ret = MM_ERROR_NONE;
9007
9008         MMPLAYER_FENTER();
9009         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9010
9011         if (MMPLAYER_IS_HTTP_PD(player)) {
9012                 if (!player->pd_downloader) {
9013                         ret = __mmplayer_realize_streaming_ext(player);
9014
9015                         if (ret != MM_ERROR_NONE) {
9016                                 LOGE("failed to realize streaming ext\n");
9017                                 return ret;
9018                         }
9019                 }
9020
9021                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9022                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9023                         if (!ret) {
9024                                 LOGE("ERROR while starting PD...\n");
9025                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9026                         }
9027                         ret = MM_ERROR_NONE;
9028                 }
9029         }
9030
9031         MMPLAYER_FLEAVE();
9032         return ret;
9033 }
9034
9035 int
9036 _mmplayer_start(MMHandleType hplayer)
9037 {
9038         mm_player_t* player = (mm_player_t*) hplayer;
9039         gint ret = MM_ERROR_NONE;
9040
9041         MMPLAYER_FENTER();
9042
9043         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9044
9045         /* check current state */
9046         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9047
9048         /* NOTE : we should check and create pipeline again if not created as we destroy
9049          * whole pipeline when stopping in streamming playback
9050          */
9051         if (!player->pipeline) {
9052                 ret = __gst_realize(player);
9053                 if (MM_ERROR_NONE != ret) {
9054                         LOGE("failed to realize before starting. only in streamming\n");
9055                         /* unlock */
9056                         return ret;
9057                 }
9058         }
9059
9060         ret = __mmplayer_start_streaming_ext(player);
9061         if (ret != MM_ERROR_NONE) {
9062                 LOGE("failed to start streaming ext 0x%X", ret);
9063                 return ret;
9064         }
9065
9066         /* start pipeline */
9067         ret = __gst_start(player);
9068         if (ret != MM_ERROR_NONE)
9069                 LOGE("failed to start player.\n");
9070
9071         MMPLAYER_FLEAVE();
9072
9073         return ret;
9074 }
9075
9076 /* NOTE: post "not supported codec message" to application
9077  * when one codec is not found during AUTOPLUGGING in MSL.
9078  * So, it's separated with error of __mmplayer_gst_callback().
9079  * And, if any codec is not found, don't send message here.
9080  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9081  */
9082 int
9083 __mmplayer_handle_missed_plugin(mm_player_t* player)
9084 {
9085         MMMessageParamType msg_param;
9086         memset(&msg_param, 0, sizeof(MMMessageParamType));
9087         gboolean post_msg_direct = FALSE;
9088
9089         MMPLAYER_FENTER();
9090
9091         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9092
9093         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9094                         player->not_supported_codec, player->can_support_codec);
9095
9096         if (player->not_found_demuxer) {
9097                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9098                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9099
9100                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9101                 MMPLAYER_FREEIF(msg_param.data);
9102
9103                 return MM_ERROR_NONE;
9104         }
9105
9106         if (player->not_supported_codec) {
9107                 if (player->can_support_codec) {
9108                         // There is one codec to play
9109                         post_msg_direct = TRUE;
9110                 } else {
9111                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9112                                 post_msg_direct = TRUE;
9113                 }
9114
9115                 if (post_msg_direct) {
9116                         MMMessageParamType msg_param;
9117                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9118
9119                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9120                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9121
9122                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9123                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9124                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9125                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9126
9127                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9128                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9129                         }
9130
9131                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9132
9133                         MMPLAYER_FREEIF(msg_param.data);
9134
9135                         return MM_ERROR_NONE;
9136                 } else {
9137                         // no any supported codec case
9138                         LOGW("not found any codec, posting error code to application.\n");
9139
9140                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9141                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9142                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9143                         } else {
9144                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9145                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9146                         }
9147
9148                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9149
9150                         MMPLAYER_FREEIF(msg_param.data);
9151                 }
9152         }
9153
9154         MMPLAYER_FLEAVE();
9155
9156         return MM_ERROR_NONE;
9157 }
9158
9159 static void __mmplayer_check_pipeline(mm_player_t* player)
9160 {
9161         GstState element_state = GST_STATE_VOID_PENDING;
9162         GstState element_pending_state = GST_STATE_VOID_PENDING;
9163         gint timeout = 0;
9164         int ret = MM_ERROR_NONE;
9165
9166         if (player->gapless.reconfigure) {
9167                 LOGW("pipeline is under construction.\n");
9168
9169                 MMPLAYER_PLAYBACK_LOCK(player);
9170                 MMPLAYER_PLAYBACK_UNLOCK(player);
9171
9172                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9173
9174                 /* wait for state transition */
9175                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9176
9177                 if (ret == GST_STATE_CHANGE_FAILURE)
9178                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9179         }
9180 }
9181
9182 /* NOTE : it should be able to call 'stop' anytime*/
9183 int
9184 _mmplayer_stop(MMHandleType hplayer)
9185 {
9186         mm_player_t* player = (mm_player_t*)hplayer;
9187         int ret = MM_ERROR_NONE;
9188
9189         MMPLAYER_FENTER();
9190
9191         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9192
9193         /* check current state */
9194         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9195
9196         /* check pipline building state */
9197         __mmplayer_check_pipeline(player);
9198         __mmplayer_reset_gapless_state(player);
9199
9200         /* NOTE : application should not wait for EOS after calling STOP */
9201         __mmplayer_cancel_eos_timer(player);
9202
9203         __mmplayer_unrealize_streaming_ext(player);
9204
9205         /* reset */
9206         player->doing_seek = FALSE;
9207
9208         /* stop pipeline */
9209         ret = __gst_stop(player);
9210
9211         if (ret != MM_ERROR_NONE)
9212                 LOGE("failed to stop player.\n");
9213
9214         MMPLAYER_FLEAVE();
9215
9216         return ret;
9217 }
9218
9219 int
9220 _mmplayer_pause(MMHandleType hplayer)
9221 {
9222         mm_player_t* player = (mm_player_t*)hplayer;
9223         gint64 pos_msec = 0;
9224         gboolean async = FALSE;
9225         gint ret = MM_ERROR_NONE;
9226
9227         MMPLAYER_FENTER();
9228
9229         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9230
9231         /* check current state */
9232         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9233
9234         /* check pipline building state */
9235         __mmplayer_check_pipeline(player);
9236
9237         switch (MMPLAYER_CURRENT_STATE(player)) {
9238         case MM_PLAYER_STATE_READY:
9239                 {
9240                         /* check prepare async or not.
9241                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9242                          */
9243                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9244                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9245
9246                         /* Changing back sync of rtspsrc to async */
9247                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9248                                 LOGD("async prepare working mode for rtsp");
9249                                 async = TRUE;
9250                         }
9251                 }
9252                 break;
9253
9254         case MM_PLAYER_STATE_PLAYING:
9255                 {
9256                         /* NOTE : store current point to overcome some bad operation
9257                         *(returning zero when getting current position in paused state) of some
9258                         * elements
9259                         */
9260                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9261                                 LOGW("getting current position failed in paused\n");
9262
9263                         player->last_position = pos_msec;
9264
9265                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9266                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9267                            This causes problem is position calculation during normal pause resume scenarios also.
9268                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9269                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9270                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9271                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9272                         }
9273                 }
9274                 break;
9275         }
9276
9277         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9278                 LOGD("doing async pause in case of ms buff src");
9279                 async = TRUE;
9280         }
9281
9282         /* pause pipeline */
9283         ret = __gst_pause(player, async);
9284
9285         if (ret != MM_ERROR_NONE)
9286                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9287
9288         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9289                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9290                         LOGE("failed to update display_rotation");
9291         }
9292
9293         MMPLAYER_FLEAVE();
9294
9295         return ret;
9296 }
9297
9298 int
9299 _mmplayer_resume(MMHandleType hplayer)
9300 {
9301         mm_player_t* player = (mm_player_t*)hplayer;
9302         int ret = MM_ERROR_NONE;
9303         gboolean async = FALSE;
9304
9305         MMPLAYER_FENTER();
9306
9307         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9308
9309         /* Changing back sync mode rtspsrc to async */
9310         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9311                 LOGD("async resume for rtsp case");
9312                 async = TRUE;
9313         }
9314
9315         /* check current state */
9316         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9317
9318         ret = __gst_resume(player, async);
9319
9320         if (ret != MM_ERROR_NONE)
9321                 LOGE("failed to resume player.\n");
9322
9323         MMPLAYER_FLEAVE();
9324
9325         return ret;
9326 }
9327
9328 static int
9329 __mmplayer_set_pcm_extraction(mm_player_t* player)
9330 {
9331         gint64 start_nsec = 0;
9332         gint64 end_nsec = 0;
9333         gint64 dur_nsec = 0;
9334         gint64 dur_msec = 0;
9335         int required_start = 0;
9336         int required_end = 0;
9337         int ret = 0;
9338
9339         MMPLAYER_FENTER();
9340
9341         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9342
9343         mm_attrs_multiple_get(player->attrs,
9344                 NULL,
9345                 "pcm_extraction_start_msec", &required_start,
9346                 "pcm_extraction_end_msec", &required_end,
9347                 NULL);
9348
9349         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9350
9351         if (required_start == 0 && required_end == 0) {
9352                 LOGD("extracting entire stream");
9353                 return MM_ERROR_NONE;
9354         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9355                 LOGD("invalid range for pcm extraction");
9356                 return MM_ERROR_INVALID_ARGUMENT;
9357         }
9358
9359         /* get duration */
9360         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9361         if (!ret) {
9362                 LOGE("failed to get duration");
9363                 return MM_ERROR_PLAYER_INTERNAL;
9364         }
9365         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9366
9367         if (dur_msec < required_end) {
9368                 // FIXME
9369                 LOGD("invalid end pos for pcm extraction");
9370                 return MM_ERROR_INVALID_ARGUMENT;
9371         }
9372
9373         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9374         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9375
9376         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9377                                         1.0,
9378                                         GST_FORMAT_TIME,
9379                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9380                                         GST_SEEK_TYPE_SET, start_nsec,
9381                                         GST_SEEK_TYPE_SET, end_nsec))) {
9382                 LOGE("failed to seek for pcm extraction\n");
9383
9384                 return MM_ERROR_PLAYER_SEEK;
9385         }
9386
9387         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9388
9389         MMPLAYER_FLEAVE();
9390
9391         return MM_ERROR_NONE;
9392 }
9393
9394 int
9395 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9396 {
9397         mm_player_t* player = (mm_player_t*)hplayer;
9398         gint64 pos_msec = 0;
9399         int ret = MM_ERROR_NONE;
9400         int mute = FALSE;
9401         signed long long start = 0, stop = 0;
9402         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9403         MMPLAYER_FENTER();
9404
9405         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9406         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9407
9408         /* The sound of video is not supported under 0.0 and over 2.0. */
9409         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9410                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9411                         mute = TRUE;
9412         }
9413         _mmplayer_set_mute(hplayer, mute);
9414
9415         if (player->playback_rate == rate)
9416                 return MM_ERROR_NONE;
9417
9418         /* If the position is reached at start potion during fast backward, EOS is posted.
9419          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9420          * */
9421         player->playback_rate = rate;
9422
9423         current_state = MMPLAYER_CURRENT_STATE(player);
9424
9425         if (current_state != MM_PLAYER_STATE_PAUSED)
9426                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9427
9428         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9429
9430         if ((current_state == MM_PLAYER_STATE_PAUSED)
9431                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9432                 LOGW("returning last point : %lld\n", player->last_position);
9433                 pos_msec = player->last_position;
9434         }
9435
9436         if (rate >= 0) {
9437                 start = pos_msec;
9438                 stop = GST_CLOCK_TIME_NONE;
9439         } else {
9440                 start = GST_CLOCK_TIME_NONE;
9441                 stop = pos_msec;
9442         }
9443
9444         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9445                                 player->playback_rate,
9446                                 GST_FORMAT_TIME,
9447                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9448                                 GST_SEEK_TYPE_SET, start,
9449                                 GST_SEEK_TYPE_SET, stop)) {
9450                 LOGE("failed to set speed playback\n");
9451                 return MM_ERROR_PLAYER_SEEK;
9452         }
9453
9454         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9455
9456         MMPLAYER_FLEAVE();
9457
9458         return MM_ERROR_NONE;;
9459 }
9460
9461 int
9462 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9463 {
9464         mm_player_t* player = (mm_player_t*)hplayer;
9465         int ret = MM_ERROR_NONE;
9466
9467         MMPLAYER_FENTER();
9468
9469         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9470
9471         /* check pipline building state */
9472         __mmplayer_check_pipeline(player);
9473
9474         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9475
9476         MMPLAYER_FLEAVE();
9477
9478         return ret;
9479 }
9480
9481 int
9482 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9483 {
9484         mm_player_t* player = (mm_player_t*)hplayer;
9485         int ret = MM_ERROR_NONE;
9486
9487         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9488
9489         ret = __gst_get_position(player, format, position);
9490
9491         return ret;
9492 }
9493
9494 int
9495 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9496 {
9497         mm_player_t* player = (mm_player_t*)hplayer;
9498         int ret = MM_ERROR_NONE;
9499
9500         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9501
9502         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9503
9504         return ret;
9505 }
9506
9507 int
9508 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9509 {
9510         mm_player_t* player = (mm_player_t*)hplayer;
9511         int ret = MM_ERROR_NONE;
9512
9513         MMPLAYER_FENTER();
9514
9515         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9516
9517         ret = __gst_adjust_subtitle_position(player, format, position);
9518
9519         MMPLAYER_FLEAVE();
9520
9521         return ret;
9522 }
9523 int
9524 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9525 {
9526         mm_player_t* player = (mm_player_t*)hplayer;
9527         int ret = MM_ERROR_NONE;
9528
9529         MMPLAYER_FENTER();
9530
9531         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9532
9533         ret = __gst_adjust_video_position(player, offset);
9534
9535         MMPLAYER_FLEAVE();
9536
9537         return ret;
9538 }
9539
9540 static gboolean
9541 __mmplayer_is_midi_type(gchar* str_caps)
9542 {
9543         if ((g_strrstr(str_caps, "audio/midi")) ||
9544                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9545                 (g_strrstr(str_caps, "application/x-smaf")) ||
9546                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9547                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9548                 (g_strrstr(str_caps, "audio/xmf")) ||
9549                 (g_strrstr(str_caps, "audio/mxmf"))) {
9550                 LOGD("midi\n");
9551                 return TRUE;
9552         }
9553
9554         return FALSE;
9555 }
9556
9557 static gboolean
9558 __mmplayer_is_only_mp3_type(gchar *str_caps)
9559 {
9560         if (g_strrstr(str_caps, "application/x-id3") ||
9561                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9562                 return TRUE;
9563         return FALSE;
9564 }
9565
9566 static void
9567 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9568 {
9569         GstStructure* caps_structure = NULL;
9570         gint samplerate = 0;
9571         gint channels = 0;
9572
9573         MMPLAYER_FENTER();
9574         MMPLAYER_RETURN_IF_FAIL(player && caps);
9575
9576         caps_structure = gst_caps_get_structure(caps, 0);
9577
9578         /* set stream information */
9579         gst_structure_get_int(caps_structure, "rate", &samplerate);
9580         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9581
9582         gst_structure_get_int(caps_structure, "channels", &channels);
9583         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9584
9585         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9586 }
9587
9588 static void
9589 __mmplayer_update_content_type_info(mm_player_t* player)
9590 {
9591         MMPLAYER_FENTER();
9592         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9593
9594         if (__mmplayer_is_midi_type(player->type)) {
9595                 player->bypass_audio_effect = TRUE;
9596         } else if (g_strrstr(player->type, "application/x-hls")) {
9597                 /* If it can't know exact type when it parses uri because of redirection case,
9598                  * it will be fixed by typefinder or when doing autoplugging.
9599                  */
9600                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9601                 if (player->streamer) {
9602                         player->streamer->is_adaptive_streaming = TRUE;
9603                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9604                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9605                 }
9606         } else if (g_strrstr(player->type, "application/dash+xml")) {
9607                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9608         }
9609
9610         MMPLAYER_FLEAVE();
9611 }
9612
9613 static void
9614 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9615 GstCaps *caps, gpointer data)
9616 {
9617         mm_player_t* player = (mm_player_t*)data;
9618         GstPad* pad = NULL;
9619
9620         MMPLAYER_FENTER();
9621
9622         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9623
9624         /* store type string */
9625         MMPLAYER_FREEIF(player->type);
9626         player->type = gst_caps_to_string(caps);
9627         if (player->type) {
9628                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9629                                 player, player->type, probability, gst_caps_get_size(caps));
9630         }
9631
9632         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9633                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9634                 LOGE("not support media format\n");
9635
9636                 if (player->msg_posted == FALSE) {
9637                         MMMessageParamType msg_param;
9638                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9639
9640                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9641                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9642
9643                         /* don't post more if one was sent already */
9644                         player->msg_posted = TRUE;
9645                 }
9646                 return;
9647         }
9648
9649         __mmplayer_update_content_type_info(player);
9650
9651         pad = gst_element_get_static_pad(tf, "src");
9652         if (!pad) {
9653                 LOGE("fail to get typefind src pad.\n");
9654                 return;
9655         }
9656
9657         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9658                 gboolean async = FALSE;
9659                 LOGE("failed to autoplug %s\n", player->type);
9660
9661                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9662
9663                 if (async && player->msg_posted == FALSE)
9664                         __mmplayer_handle_missed_plugin(player);
9665
9666                 goto DONE;
9667         }
9668
9669 DONE:
9670         gst_object_unref(GST_OBJECT(pad));
9671
9672         MMPLAYER_FLEAVE();
9673
9674         return;
9675 }
9676
9677 static GstElement *
9678 __mmplayer_create_decodebin(mm_player_t* player)
9679 {
9680         GstElement *decodebin = NULL;
9681
9682         MMPLAYER_FENTER();
9683
9684         /* create decodebin */
9685         decodebin = gst_element_factory_make("decodebin", NULL);
9686
9687         if (!decodebin) {
9688                 LOGE("fail to create decodebin\n");
9689                 goto ERROR;
9690         }
9691
9692         /* raw pad handling signal */
9693         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9694                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9695
9696         /* no-more-pad pad handling signal */
9697         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9698                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9699
9700         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9701                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9702
9703         /* This signal is emitted when a pad for which there is no further possible
9704            decoding is added to the decodebin.*/
9705         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9706                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9707
9708         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9709            before looking for any elements that can handle that stream.*/
9710         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9711                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9712
9713         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9714            before looking for any elements that can handle that stream.*/
9715         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9716                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9717
9718         /* This signal is emitted once decodebin has finished decoding all the data.*/
9719         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9720                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9721
9722         /* This signal is emitted when a element is added to the bin.*/
9723         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9724                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9725
9726 ERROR:
9727         return decodebin;
9728 }
9729
9730 static gboolean
9731 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9732 {
9733         MMPlayerGstElement* mainbin = NULL;
9734         GstElement* decodebin = NULL;
9735         GstElement* queue2 = NULL;
9736         GstPad* sinkpad = NULL;
9737         GstPad* qsrcpad = NULL;
9738         gint64 dur_bytes = 0L;
9739
9740         guint max_buffer_size_bytes = 0;
9741         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9742
9743         MMPLAYER_FENTER();
9744         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9745
9746         mainbin = player->pipeline->mainbin;
9747
9748         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9749                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9750                 LOGD("creating http streaming buffering queue(queue2)\n");
9751
9752                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9753                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9754                 } else {
9755                         queue2 = gst_element_factory_make("queue2", "queue2");
9756                         if (!queue2) {
9757                                 LOGE("failed to create buffering queue element\n");
9758                                 goto ERROR;
9759                         }
9760
9761                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9762                                 LOGE("failed to add buffering queue\n");
9763                                 goto ERROR;
9764                         }
9765
9766                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9767                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9768
9769                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9770                                 LOGE("failed to link buffering queue\n");
9771                                 goto ERROR;
9772                         }
9773
9774                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9775                                 LOGE("fail to get duration.\n");
9776
9777                         LOGD("dur_bytes = %lld\n", dur_bytes);
9778
9779                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9780
9781                         if (dur_bytes > 0) {
9782                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9783                                         type = MUXED_BUFFER_TYPE_FILE;
9784                                 } else {
9785                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9786                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9787                                 }
9788                         } else {
9789                                 dur_bytes = 0;
9790                         }
9791
9792                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9793                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9794                         if (!g_strrstr(player->type, "video/mpegts")) {
9795                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9796                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9797
9798                                 // FIXME : pass ini setting directly. is this ok?
9799                                 __mm_player_streaming_set_queue2(player->streamer,
9800                                                                                                 queue2,
9801                                                                                                 FALSE,
9802                                                                                                 max_buffer_size_bytes,
9803                                                                                                 player->ini.http_buffering_time,
9804                                                                                                 1.0,                                                            // no meaning
9805                                                                                                 player->ini.http_buffering_limit,       // no meaning
9806                                                                                                 type,
9807                                                                                                 player->http_file_buffering_path,
9808                                                                                                 (guint64)dur_bytes);
9809                         }
9810
9811                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9812                                 LOGE("failed to sync queue2 state with parent\n");
9813                                 goto ERROR;
9814                         }
9815
9816                         srcpad = qsrcpad;
9817
9818                         gst_object_unref(GST_OBJECT(sinkpad));
9819
9820                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9821                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9822                 }
9823         }
9824
9825         /* create decodebin */
9826         decodebin = __mmplayer_create_decodebin(player);
9827
9828         if (!decodebin) {
9829                 LOGE("can not create autoplug element\n");
9830                 goto ERROR;
9831         }
9832
9833         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9834                 LOGE("failed to add decodebin\n");
9835                 goto ERROR;
9836         }
9837
9838         /* to force caps on the decodebin element and avoid reparsing stuff by
9839         * typefind. It also avoids a deadlock in the way typefind activates pads in
9840         * the state change */
9841         g_object_set(decodebin, "sink-caps", caps, NULL);
9842
9843         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9844
9845         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9846                 LOGE("failed to link decodebin\n");
9847                 goto ERROR;
9848         }
9849
9850         gst_object_unref(GST_OBJECT(sinkpad));
9851
9852         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9853         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9854
9855         /* set decodebin property about buffer in streaming playback. *
9856          * in case of HLS/DASH, it does not need to have big buffer        *
9857          * because it is kind of adaptive streaming.                  */
9858         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9859                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9860                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9861                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9862
9863                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9864                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9865                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9866                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9867                 }
9868
9869                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9870                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9871                                                                                         "low-percent", 1,   // 1%
9872                                                                                         "max-size-bytes", max_size_bytes,
9873                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9874                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9875         }
9876
9877         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9878                 LOGE("failed to sync decodebin state with parent\n");
9879                 goto ERROR;
9880         }
9881
9882         MMPLAYER_FLEAVE();
9883
9884         return TRUE;
9885
9886 ERROR:
9887
9888         if (sinkpad)
9889                 gst_object_unref(GST_OBJECT(sinkpad));
9890
9891         if (queue2) {
9892                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9893                  * You need to explicitly set elements to the NULL state before
9894                  * dropping the final reference, to allow them to clean up.
9895                  */
9896                 gst_element_set_state(queue2, GST_STATE_NULL);
9897
9898                 /* And, it still has a parent "player".
9899                  * You need to let the parent manage the object instead of unreffing the object directly.
9900                  */
9901                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9902                 gst_object_unref(queue2);
9903                 queue2 = NULL;
9904         }
9905
9906         if (decodebin) {
9907                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9908                  * You need to explicitly set elements to the NULL state before
9909                  * dropping the final reference, to allow them to clean up.
9910                  */
9911                 gst_element_set_state(decodebin, GST_STATE_NULL);
9912
9913                 /* And, it still has a parent "player".
9914                  * You need to let the parent manage the object instead of unreffing the object directly.
9915                  */
9916
9917                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9918                 gst_object_unref(decodebin);
9919                 decodebin = NULL;
9920         }
9921
9922         return FALSE;
9923 }
9924
9925 static int
9926 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9927 {
9928         MMPLAYER_FENTER();
9929
9930         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9931         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9932
9933         LOGD("class : %s, mime : %s \n", factory_class, mime);
9934
9935         /* add missing plugin */
9936         /* NOTE : msl should check missing plugin for image mime type.
9937          * Some motion jpeg clips can have playable audio track.
9938          * So, msl have to play audio after displaying popup written video format not supported.
9939          */
9940         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9941                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9942                         LOGD("not found demuxer\n");
9943                         player->not_found_demuxer = TRUE;
9944                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9945
9946                         goto DONE;
9947                 }
9948         }
9949
9950         if (!g_strrstr(factory_class, "Demuxer")) {
9951                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9952                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9953                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9954
9955                         /* check that clip have multi tracks or not */
9956                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9957                                 LOGD("video plugin is already linked\n");
9958                         } else {
9959                                 LOGW("add VIDEO to missing plugin\n");
9960                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9961                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9962                         }
9963                 } else if (g_str_has_prefix(mime, "audio")) {
9964                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9965                                 LOGD("audio plugin is already linked\n");
9966                         } else {
9967                                 LOGW("add AUDIO to missing plugin\n");
9968                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9969                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9970                         }
9971                 }
9972         }
9973
9974 DONE:
9975         MMPLAYER_FLEAVE();
9976
9977         return MM_ERROR_NONE;
9978 }
9979
9980
9981 static void
9982 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
9983 {
9984         mm_player_t* player = (mm_player_t*)data;
9985
9986         MMPLAYER_FENTER();
9987
9988         MMPLAYER_RETURN_IF_FAIL(player);
9989
9990         /* remove fakesink. */
9991         if (!__mmplayer_gst_remove_fakesink(player,
9992                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9993                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9994                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9995                  * source element are not same. To overcome this situation, this function will called
9996                  * several places and several times. Therefore, this is not an error case.
9997                  */
9998                 return;
9999         }
10000
10001         LOGD("[handle: %p] pipeline has completely constructed", player);
10002
10003         if ((player->ini.async_start) &&
10004                 (player->msg_posted == FALSE) &&
10005                 (player->cmd >= MMPLAYER_COMMAND_START))
10006                 __mmplayer_handle_missed_plugin(player);
10007
10008         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10009 }
10010
10011 static gboolean
10012 __mmplayer_verify_next_play_path(mm_player_t *player)
10013 {
10014         MMHandleType attrs = 0;
10015         MMPlayerParseProfile profile;
10016         gint uri_idx = 0, check_cnt = 0;
10017         char *uri = NULL;
10018         gint mode = MM_PLAYER_PD_MODE_NONE;
10019         gint video = 0;
10020         gint count = 0;
10021         gint gapless = 0;
10022         guint num_of_list = 0;
10023         static int profile_tv = -1;
10024
10025         MMPLAYER_FENTER();
10026
10027         LOGD("checking for gapless play");
10028
10029         if (player->pipeline->textbin) {
10030                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10031                 goto ERROR;
10032         }
10033
10034         attrs = MMPLAYER_GET_ATTRS(player);
10035         if (!attrs) {
10036                 LOGE("fail to get attributes.\n");
10037                 goto ERROR;
10038         }
10039
10040         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10041
10042         if (__builtin_expect(profile_tv == -1, 0)) {
10043                 char *profileName;
10044                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10045                 switch (*profileName) {
10046                 case 't':
10047                 case 'T':
10048                         profile_tv = 1;
10049                         break;
10050                 default:
10051                         profile_tv = 0;
10052                 }
10053                 free(profileName);
10054         }
10055         /* gapless playback is not supported in case of video at TV profile. */
10056         if (profile_tv && video) {
10057                 LOGW("not support video gapless playback");
10058                 goto ERROR;
10059         }
10060
10061         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10062                 if (mode == TRUE) {
10063                         LOGW("pd mode\n");
10064                         goto ERROR;
10065                 }
10066         }
10067
10068         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10069                 LOGE("can not get play count\n");
10070
10071         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10072                 LOGE("can not get gapless mode\n");
10073
10074         if (video && !gapless) {
10075                 LOGW("not enabled video gapless playback");
10076                 goto ERROR;
10077         }
10078
10079         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10080                 gapless = 1;
10081
10082         if (!gapless) {
10083                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10084                 goto ERROR;
10085         }
10086
10087         num_of_list = g_list_length(player->uri_info.uri_list);
10088
10089         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10090
10091         if (num_of_list == 0) {
10092                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10093                         LOGE("can not get profile_uri\n");
10094                         goto ERROR;
10095                 }
10096
10097                 if (!uri) {
10098                         LOGE("uri list is empty.\n");
10099                         goto ERROR;
10100                 }
10101
10102                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10103                 LOGD("add original path : %s ", uri);
10104
10105                 num_of_list = 1;
10106                 uri = NULL;
10107         }
10108
10109         uri_idx = player->uri_info.uri_idx;
10110
10111         while (TRUE) {
10112                 check_cnt++;
10113
10114                 if (check_cnt > num_of_list) {
10115                         LOGE("there is no valid uri.");
10116                         goto ERROR;
10117                 }
10118
10119                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10120
10121                 if (uri_idx < num_of_list-1) {
10122                         uri_idx++;
10123                 } else {
10124                         if ((count <= 1) && (count != -1)) {
10125                                 LOGD("no repeat.");
10126                                 goto ERROR;
10127                         } else if (count > 1) {
10128                                 /* decrease play count */
10129                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10130                                 count--;
10131
10132                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10133
10134                                 /* commit attribute */
10135                                 if (mmf_attrs_commit(attrs))
10136                                         LOGE("failed to commit attribute\n");
10137                         }
10138
10139                         /* count < 0 : repeat continually */
10140                         uri_idx = 0;
10141                 }
10142
10143                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10144                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10145
10146                 if (uri == NULL) {
10147                         LOGW("next uri does not exist\n");
10148                         continue;
10149                 }
10150
10151                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10152                         LOGE("failed to parse profile\n");
10153                         continue;
10154                 }
10155
10156                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10157                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10158                         LOGW("uri type is not supported(%d).", profile.uri_type);
10159                         continue;
10160                 }
10161
10162                 break;
10163         }
10164
10165         player->uri_info.uri_idx = uri_idx;
10166         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10167
10168         if (mmf_attrs_commit(player->attrs)) {
10169                 LOGE("failed to commit.\n");
10170                 goto ERROR;
10171         }
10172
10173         LOGD("next uri %s(%d)\n", uri, uri_idx);
10174
10175         return TRUE;
10176
10177 ERROR:
10178
10179         LOGE("unable to play next path. EOS will be posted soon.\n");
10180         return FALSE;
10181 }
10182
10183 static void
10184 __mmplayer_initialize_next_play(mm_player_t *player)
10185 {
10186         int i;
10187
10188         MMPLAYER_FENTER();
10189
10190         player->smooth_streaming = FALSE;
10191         player->videodec_linked = 0;
10192         player->audiodec_linked = 0;
10193         player->videosink_linked = 0;
10194         player->audiosink_linked = 0;
10195         player->textsink_linked = 0;
10196         player->is_external_subtitle_present = FALSE;
10197         player->is_external_subtitle_added_now = FALSE;
10198         player->not_supported_codec = MISSING_PLUGIN_NONE;
10199         player->can_support_codec = FOUND_PLUGIN_NONE;
10200         player->pending_seek.is_pending = FALSE;
10201         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10202         player->pending_seek.pos = 0;
10203         player->msg_posted = FALSE;
10204         player->has_many_types = FALSE;
10205         player->no_more_pad = FALSE;
10206         player->not_found_demuxer = 0;
10207         player->doing_seek = FALSE;
10208         player->max_audio_channels = 0;
10209         player->is_subtitle_force_drop = FALSE;
10210         player->play_subtitle = FALSE;
10211         player->adjust_subtitle_pos = 0;
10212
10213         player->total_bitrate = 0;
10214         player->total_maximum_bitrate = 0;
10215
10216         _mmplayer_track_initialize(player);
10217         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10218
10219         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10220                 player->bitrate[i] = 0;
10221                 player->maximum_bitrate[i] = 0;
10222         }
10223
10224         if (player->v_stream_caps) {
10225                 gst_caps_unref(player->v_stream_caps);
10226                 player->v_stream_caps = NULL;
10227         }
10228
10229         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10230
10231         /* clean found parsers */
10232         if (player->parsers) {
10233                 GList *parsers = player->parsers;
10234                 for (; parsers; parsers = g_list_next(parsers)) {
10235                         gchar *name = parsers->data;
10236                         MMPLAYER_FREEIF(name);
10237                 }
10238                 g_list_free(player->parsers);
10239                 player->parsers = NULL;
10240         }
10241
10242         /* clean found audio decoders */
10243         if (player->audio_decoders) {
10244                 GList *a_dec = player->audio_decoders;
10245                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10246                         gchar *name = a_dec->data;
10247                         MMPLAYER_FREEIF(name);
10248                 }
10249                 g_list_free(player->audio_decoders);
10250                 player->audio_decoders = NULL;
10251         }
10252
10253         MMPLAYER_FLEAVE();
10254 }
10255
10256 static void
10257 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10258 {
10259         MMPlayerGstElement *mainbin = NULL;
10260         MMMessageParamType msg_param = {0,};
10261         GstElement *element = NULL;
10262         MMHandleType attrs = 0;
10263         char *uri = NULL;
10264         enum MainElementID elemId = MMPLAYER_M_NUM;
10265
10266         MMPLAYER_FENTER();
10267
10268         if ((player == NULL) ||
10269                 (player->pipeline == NULL) ||
10270                 (player->pipeline->mainbin == NULL)) {
10271                 LOGE("player is null.\n");
10272                 goto ERROR;
10273         }
10274
10275         mainbin = player->pipeline->mainbin;
10276         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10277
10278         attrs = MMPLAYER_GET_ATTRS(player);
10279         if (!attrs) {
10280                 LOGE("fail to get attributes.\n");
10281                 goto ERROR;
10282         }
10283
10284         /* Initialize Player values */
10285         __mmplayer_initialize_next_play(player);
10286
10287         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10288
10289         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10290                 LOGE("failed to parse profile\n");
10291                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10292                 goto ERROR;
10293         }
10294
10295         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10296                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10297                 LOGE("it's dash or hls. not support.");
10298                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10299                 goto ERROR;
10300         }
10301
10302         /* setup source */
10303         switch (player->profile.uri_type) {
10304         /* file source */
10305         case MM_PLAYER_URI_TYPE_FILE:
10306         {
10307                 LOGD("using filesrc for 'file://' handler.\n");
10308                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10309                         LOGE("failed to get storage info");
10310                         break;
10311                 }
10312
10313                 element = gst_element_factory_make("filesrc", "source");
10314
10315                 if (!element) {
10316                         LOGE("failed to create filesrc\n");
10317                         break;
10318                 }
10319
10320                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10321                 break;
10322         }
10323         case MM_PLAYER_URI_TYPE_URL_HTTP:
10324         {
10325                 gchar *user_agent, *cookies, **cookie_list;
10326                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10327                 user_agent = cookies = NULL;
10328                 cookie_list = NULL;
10329
10330                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10331                 if (!element) {
10332                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10333                         break;
10334                 }
10335                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10336
10337                 /* get attribute */
10338                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10339                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10340
10341                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10342                         LOGD("get timeout from ini\n");
10343                         http_timeout = player->ini.http_timeout;
10344                 }
10345
10346                 /* get attribute */
10347                 SECURE_LOGD("location : %s\n", player->profile.uri);
10348                 SECURE_LOGD("cookies : %s\n", cookies);
10349                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10350                 LOGD("timeout : %d\n", http_timeout);
10351
10352                 /* setting property to streaming source */
10353                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10354                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10355                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10356
10357                 /* parsing cookies */
10358                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10359                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10360                 if (user_agent)
10361                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10362                 break;
10363         }
10364         default:
10365                 LOGE("not support uri type %d\n", player->profile.uri_type);
10366                 break;
10367         }
10368
10369         if (!element) {
10370                 LOGE("no source element was created.\n");
10371                 goto ERROR;
10372         }
10373
10374         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10375                 LOGE("failed to add source element to pipeline\n");
10376                 gst_object_unref(GST_OBJECT(element));
10377                 element = NULL;
10378                 goto ERROR;
10379         }
10380
10381         /* take source element */
10382         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10383         mainbin[MMPLAYER_M_SRC].gst = element;
10384
10385         element = NULL;
10386
10387         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10388                 if (player->streamer == NULL) {
10389                         player->streamer = __mm_player_streaming_create();
10390                         __mm_player_streaming_initialize(player->streamer);
10391                 }
10392
10393                 elemId = MMPLAYER_M_TYPEFIND;
10394                 element = gst_element_factory_make("typefind", "typefinder");
10395                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10396                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10397         } else {
10398                 elemId = MMPLAYER_M_AUTOPLUG;
10399                 element = __mmplayer_create_decodebin(player);
10400         }
10401
10402         /* check autoplug element is OK */
10403         if (!element) {
10404                 LOGE("can not create element(%d)\n", elemId);
10405                 goto ERROR;
10406         }
10407
10408         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10409                 LOGE("failed to add sinkbin to pipeline\n");
10410                 gst_object_unref(GST_OBJECT(element));
10411                 element = NULL;
10412                 goto ERROR;
10413         }
10414
10415         mainbin[elemId].id = elemId;
10416         mainbin[elemId].gst = element;
10417
10418         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10419                 LOGE("Failed to link src - autoplug(or typefind)\n");
10420                 goto ERROR;
10421         }
10422
10423         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10424                 LOGE("Failed to change state of src element\n");
10425                 goto ERROR;
10426         }
10427
10428         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10429                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10430                         LOGE("Failed to change state of decodebin\n");
10431                         goto ERROR;
10432                 }
10433         } else {
10434                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10435                         LOGE("Failed to change state of src element\n");
10436                         goto ERROR;
10437                 }
10438         }
10439
10440         player->gapless.stream_changed = TRUE;
10441         player->gapless.running = TRUE;
10442         MMPLAYER_FLEAVE();
10443         return;
10444
10445 ERROR:
10446         if (player) {
10447                 MMPLAYER_PLAYBACK_UNLOCK(player);
10448
10449                 if (!player->msg_posted) {
10450                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10451                         player->msg_posted = TRUE;
10452                 }
10453         }
10454         return;
10455 }
10456
10457 static gboolean
10458 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10459 {
10460         mm_player_selector_t *selector = &player->selector[type];
10461         MMPlayerGstElement *sinkbin = NULL;
10462         enum MainElementID selectorId = MMPLAYER_M_NUM;
10463         enum MainElementID sinkId = MMPLAYER_M_NUM;
10464         GstPad *srcpad = NULL;
10465         GstPad *sinkpad = NULL;
10466         gboolean send_notice = FALSE;
10467
10468         MMPLAYER_FENTER();
10469         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10470
10471         LOGD("type %d", type);
10472
10473         switch (type) {
10474         case MM_PLAYER_TRACK_TYPE_AUDIO:
10475                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10476                 sinkId = MMPLAYER_A_BIN;
10477                 sinkbin = player->pipeline->audiobin;
10478                 break;
10479         case MM_PLAYER_TRACK_TYPE_VIDEO:
10480                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10481                 sinkId = MMPLAYER_V_BIN;
10482                 sinkbin = player->pipeline->videobin;
10483                 send_notice = TRUE;
10484                 break;
10485         case MM_PLAYER_TRACK_TYPE_TEXT:
10486                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10487                 sinkId = MMPLAYER_T_BIN;
10488                 sinkbin = player->pipeline->textbin;
10489                 break;
10490         default:
10491                 LOGE("requested type is not supportable");
10492                 return FALSE;
10493                 break;
10494         }
10495
10496         if (player->pipeline->mainbin[selectorId].gst) {
10497                 gint n;
10498
10499                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10500
10501                 if (selector->event_probe_id != 0)
10502                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10503                 selector->event_probe_id = 0;
10504
10505                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10506                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10507
10508                         if (srcpad && sinkpad) {
10509                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10510                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10511                                 gst_pad_unlink(srcpad, sinkpad);
10512
10513                                 /* send custom event to sink pad to handle it at video sink */
10514                                 if (send_notice) {
10515                                         LOGD("send custom event to sinkpad");
10516                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10517                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10518                                         gst_pad_send_event(sinkpad, event);
10519                                 }
10520                         }
10521
10522                         gst_object_unref(sinkpad);
10523                         sinkpad = NULL;
10524                 }
10525                 gst_object_unref(srcpad);
10526                 srcpad = NULL;
10527
10528                 LOGD("selector release");
10529
10530                 /* release and unref requests pad from the selector */
10531                 for (n = 0; n < selector->channels->len; n++) {
10532                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10533                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10534                 }
10535                 g_ptr_array_set_size(selector->channels, 0);
10536
10537                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10538                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10539
10540                 player->pipeline->mainbin[selectorId].gst = NULL;
10541                 selector = NULL;
10542         }
10543
10544         return TRUE;
10545 }
10546
10547 static void
10548 __mmplayer_deactivate_old_path(mm_player_t *player)
10549 {
10550         MMPLAYER_FENTER();
10551         MMPLAYER_RETURN_IF_FAIL(player);
10552
10553         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10554                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10555                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10556                 LOGE("deactivate selector error");
10557                 goto ERROR;
10558         }
10559
10560         _mmplayer_track_destroy(player);
10561         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10562
10563         if (player->streamer) {
10564                 __mm_player_streaming_deinitialize(player->streamer);
10565                 __mm_player_streaming_destroy(player->streamer);
10566                 player->streamer = NULL;
10567         }
10568
10569         MMPLAYER_PLAYBACK_LOCK(player);
10570         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10571
10572         MMPLAYER_FLEAVE();
10573         return;
10574
10575 ERROR:
10576
10577         if (!player->msg_posted) {
10578                 MMMessageParamType msg = {0,};
10579
10580                 /*post error*/
10581                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10582                 LOGE("next_uri_play> deactivate error");
10583
10584                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10585                 player->msg_posted = TRUE;
10586         }
10587         return;
10588 }
10589
10590 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10591 {
10592         int result = MM_ERROR_NONE;
10593         mm_player_t* player = (mm_player_t*) hplayer;
10594         MMPLAYER_FENTER();
10595
10596         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10597
10598         if (file_path) {
10599                 player->http_file_buffering_path = (gchar*)file_path;
10600                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10601         }
10602         MMPLAYER_FLEAVE();
10603         return result;
10604 }
10605
10606 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10607 {
10608         int result = MM_ERROR_NONE;
10609         mm_player_t* player = (mm_player_t*) hplayer;
10610         MMPLAYER_FENTER();
10611
10612         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10613
10614         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10615         if (mmf_attrs_commit(player->attrs)) {
10616                 LOGE("failed to commit the original uri.\n");
10617                 result = MM_ERROR_PLAYER_INTERNAL;
10618         } else {
10619                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10620                         LOGE("failed to add the original uri in the uri list.\n");
10621         }
10622
10623         MMPLAYER_FLEAVE();
10624         return result;
10625 }
10626
10627 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10628 {
10629         mm_player_t* player = (mm_player_t*) hplayer;
10630         guint num_of_list = 0;
10631
10632         MMPLAYER_FENTER();
10633
10634         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10635         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10636
10637         if (player->pipeline && player->pipeline->textbin) {
10638                 LOGE("subtitle path is enabled.\n");
10639                 return MM_ERROR_PLAYER_INVALID_STATE;
10640         }
10641
10642         num_of_list = g_list_length(player->uri_info.uri_list);
10643
10644         if (is_first_path == TRUE) {
10645                 if (num_of_list == 0) {
10646                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10647                         LOGD("add original path : %s", uri);
10648                 } else {
10649                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10650                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10651
10652                         LOGD("change original path : %s", uri);
10653                 }
10654         } else {
10655                 MMHandleType attrs = 0;
10656                 attrs = MMPLAYER_GET_ATTRS(player);
10657
10658                 if (num_of_list == 0) {
10659                         char *original_uri = NULL;
10660
10661                         if (attrs) {
10662                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10663
10664                                 if (!original_uri) {
10665                                         LOGE("there is no original uri.");
10666                                         return MM_ERROR_PLAYER_INVALID_STATE;
10667                                 }
10668
10669                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10670                                 player->uri_info.uri_idx = 0;
10671
10672                                 LOGD("add original path at first : %s(%d)", original_uri);
10673                         }
10674                 }
10675
10676                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10677                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10678         }
10679
10680         MMPLAYER_FLEAVE();
10681         return MM_ERROR_NONE;
10682 }
10683
10684 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10685 {
10686         mm_player_t* player = (mm_player_t*) hplayer;
10687         char *next_uri = NULL;
10688         guint num_of_list = 0;
10689
10690         MMPLAYER_FENTER();
10691         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10692
10693         num_of_list = g_list_length(player->uri_info.uri_list);
10694
10695         if (num_of_list > 0) {
10696                 gint uri_idx = player->uri_info.uri_idx;
10697
10698                 if (uri_idx < num_of_list-1)
10699                         uri_idx++;
10700                 else
10701                         uri_idx = 0;
10702
10703                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10704                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10705
10706                 *uri = g_strdup(next_uri);
10707         }
10708
10709         MMPLAYER_FLEAVE();
10710         return MM_ERROR_NONE;
10711 }
10712
10713 static void
10714 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10715 GstCaps *caps, gpointer data)
10716 {
10717         mm_player_t* player = (mm_player_t*)data;
10718         const gchar* klass = NULL;
10719         const gchar* mime = NULL;
10720         gchar* caps_str = NULL;
10721
10722         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10723         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10724         caps_str = gst_caps_to_string(caps);
10725
10726         LOGW("unknown type of caps : %s from %s",
10727                                         caps_str, GST_ELEMENT_NAME(elem));
10728
10729         MMPLAYER_FREEIF(caps_str);
10730
10731         /* There is no available codec. */
10732         __mmplayer_check_not_supported_codec(player, klass, mime);
10733 }
10734
10735 static gboolean
10736 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10737 GstCaps * caps,  gpointer data)
10738 {
10739         mm_player_t* player = (mm_player_t*)data;
10740         const char* mime = NULL;
10741         gboolean ret = TRUE;
10742
10743         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10744         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10745
10746         if (g_str_has_prefix(mime, "audio")) {
10747                 GstStructure* caps_structure = NULL;
10748                 gint samplerate = 0;
10749                 gint channels = 0;
10750                 gchar *caps_str = NULL;
10751
10752                 caps_structure = gst_caps_get_structure(caps, 0);
10753                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10754                 gst_structure_get_int(caps_structure, "channels", &channels);
10755
10756                 if ((channels > 0 && samplerate == 0)) {
10757                         LOGD("exclude audio...");
10758                         ret = FALSE;
10759                 }
10760
10761                 caps_str = gst_caps_to_string(caps);
10762                 /* set it directly because not sent by TAG */
10763                 if (g_strrstr(caps_str, "mobile-xmf"))
10764                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10765                 MMPLAYER_FREEIF(caps_str);
10766         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10767                 MMMessageParamType msg_param;
10768                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10769                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10770                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10771                 LOGD("video file is not supported on this device");
10772                 ret = FALSE;
10773         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10774                 LOGD("already video linked");
10775                 ret = FALSE;
10776         } else {
10777                 LOGD("found new stream");
10778         }
10779
10780         return ret;
10781 }
10782
10783 static int
10784 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10785 {
10786         int ret = MM_ERROR_NONE;
10787         int idx = 0;
10788         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10789
10790         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10791                 GstStructure* str = NULL;
10792                 gint channels = 0;
10793                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10794
10795                 LOGD("audio codec type: %d", codec_type);
10796                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10797                         /* sw codec will be skipped */
10798                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10799                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10800                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10801                                         ret = MM_ERROR_PLAYER_INTERNAL;
10802                                         goto DONE;
10803                                 }
10804                         }
10805                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10806                         /* hw codec will be skipped */
10807                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10808                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10809                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10810                                 ret = MM_ERROR_PLAYER_INTERNAL;
10811                                 goto DONE;
10812                         }
10813                 }
10814
10815                 str = gst_caps_get_structure(caps, 0);
10816                 if (str) {
10817                         gst_structure_get_int(str, "channels", &channels);
10818
10819                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10820                         if (player->max_audio_channels < channels)
10821                                 player->max_audio_channels = channels;
10822                 }
10823                 /* set stream information */
10824                 if (!player->audiodec_linked)
10825                         __mmplayer_set_audio_attrs(player, caps);
10826
10827                 /* update codec info */
10828                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10829                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10830                 player->audiodec_linked = 1;
10831
10832         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10833
10834                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10835
10836                 LOGD("video codec type: %d", codec_type);
10837                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10838                         /* sw codec is skipped */
10839                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10840                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10841                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10842                                         ret = MM_ERROR_PLAYER_INTERNAL;
10843                                         goto DONE;
10844                                 }
10845                         }
10846                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10847                         /* hw codec is skipped */
10848                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10849                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10850                                 ret = MM_ERROR_PLAYER_INTERNAL;
10851                                 goto DONE;
10852                         }
10853                 }
10854
10855                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10856                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10857
10858                         /* mark video decoder for acquire */
10859                         if (player->video_decoder_resource == NULL) {
10860                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10861                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10862                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10863                                                 &player->video_decoder_resource)
10864                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10865                                         LOGE("could not mark video_decoder resource for acquire");
10866                                         ret = MM_ERROR_PLAYER_INTERNAL;
10867                                         goto DONE;
10868                                 }
10869                         } else {
10870                                 LOGW("video decoder resource is already acquired, skip it.");
10871                                 ret = MM_ERROR_PLAYER_INTERNAL;
10872                                 goto DONE;
10873                         }
10874
10875                         player->interrupted_by_resource = FALSE;
10876                         /* acquire resources for video playing */
10877                         if (mm_resource_manager_commit(player->resource_manager)
10878                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10879                                 LOGE("could not acquire resources for video decoding\n");
10880                                 ret = MM_ERROR_PLAYER_INTERNAL;
10881                                 goto DONE;
10882                         }
10883                 }
10884
10885                 /* update codec info */
10886                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10887                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10888                 player->videodec_linked = 1;
10889         }
10890
10891 DONE:
10892         return ret;
10893 }
10894
10895 static gint
10896 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10897 GstCaps* caps, GstElementFactory* factory, gpointer data)
10898 {
10899         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10900          We are defining our own and will be removed when it actually exposed */
10901         typedef enum {
10902                 GST_AUTOPLUG_SELECT_TRY,
10903                 GST_AUTOPLUG_SELECT_EXPOSE,
10904                 GST_AUTOPLUG_SELECT_SKIP
10905         } GstAutoplugSelectResult;
10906
10907         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10908         mm_player_t* player = (mm_player_t*)data;
10909
10910         gchar* factory_name = NULL;
10911         gchar* caps_str = NULL;
10912         const gchar* klass = NULL;
10913         gint idx = 0;
10914
10915         factory_name = GST_OBJECT_NAME(factory);
10916         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10917         caps_str = gst_caps_to_string(caps);
10918
10919         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10920
10921         /* store type string */
10922         if (player->type == NULL) {
10923                 player->type = gst_caps_to_string(caps);
10924                 __mmplayer_update_content_type_info(player);
10925         }
10926
10927         /* filtering exclude keyword */
10928         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10929                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10930                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10931                                         factory_name, player->ini.exclude_element_keyword[idx]);
10932
10933                         result = GST_AUTOPLUG_SELECT_SKIP;
10934                         goto DONE;
10935                 }
10936         }
10937
10938         /* exclude webm format */
10939         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10940          * because webm format is not supportable.
10941          * If webm is disabled in "autoplug-continue", there is no state change
10942          * failure or error because the decodebin will expose the pad directly.
10943          * It make MSL invoke _prepare_async_callback.
10944          * So, we need to disable webm format in "autoplug-select" */
10945         if (caps_str && strstr(caps_str, "webm")) {
10946                 LOGW("webm is not supported");
10947                 result = GST_AUTOPLUG_SELECT_SKIP;
10948                 goto DONE;
10949         }
10950
10951         /* check factory class for filtering */
10952         /* NOTE : msl don't need to use image plugins.
10953          * So, those plugins should be skipped for error handling.
10954          */
10955         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10956                 LOGD("skipping [%s] by not required\n", factory_name);
10957                 result = GST_AUTOPLUG_SELECT_SKIP;
10958                 goto DONE;
10959         }
10960
10961         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10962                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10963                 // TO CHECK : subtitle if needed, add subparse exception.
10964                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10965                 result = GST_AUTOPLUG_SELECT_SKIP;
10966                 goto DONE;
10967         }
10968
10969         if (g_strrstr(factory_name, "mpegpsdemux")) {
10970                 LOGD("skipping PS container - not support\n");
10971                 result = GST_AUTOPLUG_SELECT_SKIP;
10972                 goto DONE;
10973         }
10974
10975         if (g_strrstr(factory_name, "mssdemux"))
10976                 player->smooth_streaming = TRUE;
10977
10978         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10979                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10980                 gint stype = 0;
10981                 gint width = 0;
10982                 GstStructure *str = NULL;
10983                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10984
10985                 /* don't make video because of not required */
10986                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10987                         (player->set_mode.media_packet_video_stream == FALSE)) {
10988                         LOGD("no video because it's not required. -> return expose");
10989                         result = GST_AUTOPLUG_SELECT_EXPOSE;
10990                         goto DONE;
10991                 }
10992
10993                 /* get w/h for omx state-tune */
10994                 /* FIXME: deprecated? */
10995                 str = gst_caps_get_structure(caps, 0);
10996                 gst_structure_get_int(str, "width", &width);
10997
10998                 if (width != 0) {
10999                         if (player->v_stream_caps) {
11000                                 gst_caps_unref(player->v_stream_caps);
11001                                 player->v_stream_caps = NULL;
11002                         }
11003
11004                         player->v_stream_caps = gst_caps_copy(caps);
11005                         LOGD("take caps for video state tune");
11006                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11007                 }
11008         }
11009
11010         if (g_strrstr(klass, "Codec/Decoder")) {
11011                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11012                         LOGD("skipping %s codec", factory_name);
11013                         result = GST_AUTOPLUG_SELECT_SKIP;
11014                         goto DONE;
11015                 }
11016         }
11017
11018 DONE:
11019         MMPLAYER_FREEIF(caps_str);
11020
11021         return result;
11022 }
11023
11024 static void
11025 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11026 gpointer data)
11027 {
11028         //mm_player_t* player = (mm_player_t*)data;
11029         GstCaps* caps = NULL;
11030
11031         LOGD("[Decodebin2] pad-removed signal\n");
11032
11033         caps = gst_pad_query_caps(new_pad, NULL);
11034         if (caps) {
11035                 gchar* caps_str = NULL;
11036                 caps_str = gst_caps_to_string(caps);
11037
11038                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11039
11040                 MMPLAYER_FREEIF(caps_str);
11041                 gst_caps_unref(caps);
11042         }
11043 }
11044
11045 static void
11046 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11047 {
11048         mm_player_t* player = (mm_player_t*)data;
11049         GstIterator *iter = NULL;
11050         GValue item = { 0, };
11051         GstPad *pad = NULL;
11052         gboolean done = FALSE;
11053         gboolean is_all_drained = TRUE;
11054
11055         MMPLAYER_FENTER();
11056         MMPLAYER_RETURN_IF_FAIL(player);
11057
11058         LOGD("__mmplayer_gst_decode_drained");
11059
11060         if (player->use_deinterleave == TRUE) {
11061                 LOGD("group playing mode.");
11062                 return;
11063         }
11064
11065         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11066                 LOGW("Fail to get cmd lock");
11067                 return;
11068         }
11069
11070         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11071                 !__mmplayer_verify_next_play_path(player)) {
11072                 LOGD("decoding is finished.");
11073                 __mmplayer_reset_gapless_state(player);
11074                 MMPLAYER_CMD_UNLOCK(player);
11075                 return;
11076         }
11077
11078         player->gapless.reconfigure = TRUE;
11079
11080         /* check decodebin src pads whether they received EOS or not */
11081         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11082
11083         while (!done) {
11084                 switch (gst_iterator_next(iter, &item)) {
11085                 case GST_ITERATOR_OK:
11086                         pad = g_value_get_object(&item);
11087                         if (pad && !GST_PAD_IS_EOS(pad)) {
11088                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11089                                 is_all_drained = FALSE;
11090                                 break;
11091                         }
11092                         g_value_reset(&item);
11093                         break;
11094                 case GST_ITERATOR_RESYNC:
11095                         gst_iterator_resync(iter);
11096                         break;
11097                 case GST_ITERATOR_ERROR:
11098                 case GST_ITERATOR_DONE:
11099                         done = TRUE;
11100                         break;
11101                 }
11102         }
11103         g_value_unset(&item);
11104         gst_iterator_free(iter);
11105
11106         if (!is_all_drained) {
11107                 LOGD("Wait util the all pads get EOS.");
11108                 MMPLAYER_CMD_UNLOCK(player);
11109                 MMPLAYER_FLEAVE();
11110                 return;
11111         }
11112
11113         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11114         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11115
11116         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11117         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11118         __mmplayer_deactivate_old_path(player);
11119         MMPLAYER_CMD_UNLOCK(player);
11120
11121         MMPLAYER_FLEAVE();
11122 }
11123
11124 static void
11125 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11126 {
11127         mm_player_t* player = (mm_player_t*)data;
11128         const gchar* klass = NULL;
11129         gchar* factory_name = NULL;
11130
11131         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11132         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11133
11134         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11135
11136         if (__mmplayer_add_dump_buffer_probe(player, element))
11137                 LOGD("add buffer probe");
11138
11139         //<-
11140         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11141                 gchar* selected = NULL;
11142                 selected = g_strdup(GST_ELEMENT_NAME(element));
11143                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11144         }
11145         //-> temp code
11146
11147         if (g_strrstr(klass, "Parser")) {
11148                 gchar* selected = NULL;
11149
11150                 selected = g_strdup(factory_name);
11151                 player->parsers = g_list_append(player->parsers, selected);
11152         }
11153
11154         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11155                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11156                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11157
11158                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11159                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11160
11161                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11162                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11163                                                 "max-video-width", player->adaptive_info.limit.width,
11164                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11165
11166         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11167                 /* FIXIT : first value will be overwritten if there's more
11168                  * than 1 demuxer/parser
11169                  */
11170
11171                 //LOGD("plugged element is demuxer. take it\n");
11172                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11173                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11174
11175                 /*Added for multi audio support */ // Q. del?
11176                 if (g_strrstr(klass, "Demux")) {
11177                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11178                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11179                 }
11180         }
11181
11182         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11183                 int surface_type = 0;
11184
11185                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11186         }
11187
11188         // to support trust-zone only
11189         if (g_strrstr(factory_name, "asfdemux")) {
11190                 LOGD("set file-location %s\n", player->profile.uri);
11191                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11192
11193                 if (player->video_hub_download_mode == TRUE)
11194                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11195         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11196                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11197                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11198         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11199                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11200                         (__mmplayer_is_only_mp3_type(player->type))) {
11201                         LOGD("[mpegaudioparse] set streaming pull mode.");
11202                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11203                 }
11204         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11205                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11206         }
11207
11208         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11209                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11210                 LOGD("plugged element is multiqueue. take it\n");
11211
11212                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11213                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11214
11215                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11216                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11217                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11218                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11219                         __mm_player_streaming_set_multiqueue(player->streamer,
11220                                 element,
11221                                 TRUE,
11222                                 player->ini.http_buffering_time,
11223                                 1.0,
11224                                 player->ini.http_buffering_limit);
11225
11226                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11227                 }
11228         }
11229
11230         return;
11231 }
11232
11233 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11234 {
11235         MMPLAYER_FENTER();
11236         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11237
11238         if (MMPLAYER_IS_STREAMING(player))
11239                 return FALSE;
11240
11241         /* This callback can be set to music player only. */
11242         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11243                 LOGW("audio callback is not supported for video");
11244                 return FALSE;
11245         }
11246
11247         if (player->audio_stream_cb) {
11248                 GstPad *pad = NULL;
11249
11250                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11251
11252                 if (!pad) {
11253                         LOGE("failed to get sink pad from audiosink to probe data\n");
11254                         return FALSE;
11255                 }
11256                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11257                         __mmplayer_audio_stream_probe, player, NULL);
11258
11259                 gst_object_unref(pad);
11260
11261                 pad = NULL;
11262         } else {
11263                 LOGE("There is no audio callback to configure.\n");
11264                 return FALSE;
11265         }
11266
11267         MMPLAYER_FLEAVE();
11268
11269         return TRUE;
11270 }
11271
11272 static void
11273 __mmplayer_release_misc(mm_player_t* player)
11274 {
11275         int i;
11276         bool cur_mode = player->set_mode.rich_audio;
11277         MMPLAYER_FENTER();
11278
11279         MMPLAYER_RETURN_IF_FAIL(player);
11280
11281         player->video_stream_cb = NULL;
11282         player->video_stream_cb_user_param = NULL;
11283         player->video_stream_prerolled = FALSE;
11284
11285         player->audio_stream_cb = NULL;
11286         player->audio_stream_render_cb_ex = NULL;
11287         player->audio_stream_cb_user_param = NULL;
11288         player->audio_stream_sink_sync = false;
11289
11290         player->video_stream_changed_cb = NULL;
11291         player->video_stream_changed_cb_user_param = NULL;
11292
11293         player->audio_stream_changed_cb = NULL;
11294         player->audio_stream_changed_cb_user_param = NULL;
11295
11296         player->sent_bos = FALSE;
11297         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11298
11299         player->doing_seek = FALSE;
11300
11301         player->total_bitrate = 0;
11302         player->total_maximum_bitrate = 0;
11303
11304         player->not_found_demuxer = 0;
11305
11306         player->last_position = 0;
11307         player->duration = 0;
11308         player->http_content_size = 0;
11309         player->not_supported_codec = MISSING_PLUGIN_NONE;
11310         player->can_support_codec = FOUND_PLUGIN_NONE;
11311         player->pending_seek.is_pending = FALSE;
11312         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11313         player->pending_seek.pos = 0;
11314         player->msg_posted = FALSE;
11315         player->has_many_types = FALSE;
11316         player->max_audio_channels = 0;
11317         player->video_share_api_delta = 0;
11318         player->video_share_clock_delta = 0;
11319         player->is_subtitle_force_drop = FALSE;
11320         player->play_subtitle = FALSE;
11321         player->adjust_subtitle_pos = 0;
11322         player->last_multiwin_status = FALSE;
11323         player->has_closed_caption = FALSE;
11324         player->set_mode.media_packet_video_stream = FALSE;
11325         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11326         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11327         /* recover mode */
11328         player->set_mode.rich_audio = cur_mode;
11329
11330         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11331                 player->bitrate[i] = 0;
11332                 player->maximum_bitrate[i] = 0;
11333         }
11334
11335         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11336
11337         /* remove media stream cb(appsrc cb) */
11338         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11339                 player->media_stream_buffer_status_cb[i] = NULL;
11340                 player->media_stream_seek_data_cb[i] = NULL;
11341                 player->buffer_cb_user_param[i] = NULL;
11342                 player->seek_cb_user_param[i] = NULL;
11343         }
11344         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11345
11346         /* free memory related to audio effect */
11347         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11348
11349         if (player->adaptive_info.var_list) {
11350                 g_list_free_full(player->adaptive_info.var_list, g_free);
11351                 player->adaptive_info.var_list = NULL;
11352         }
11353
11354         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11355         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11356         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11357
11358         /* Reset video360 settings to their defaults in case if the pipeline is to be
11359          * re-created.
11360          * */
11361         player->video360_metadata.is_spherical = -1;
11362         player->is_openal_plugin_used = FALSE;
11363
11364         player->is_content_spherical = FALSE;
11365         player->is_video360_enabled = TRUE;
11366         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11367         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11368         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11369         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11370         player->video360_zoom = 1.0f;
11371         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11372         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11373
11374         player->sound.rg_enable = false;
11375
11376         MMPLAYER_FLEAVE();
11377 }
11378
11379 static void
11380 __mmplayer_release_misc_post(mm_player_t* player)
11381 {
11382         char *original_uri = NULL;
11383         MMPLAYER_FENTER();
11384
11385         /* player->pipeline is already released before. */
11386
11387         MMPLAYER_RETURN_IF_FAIL(player);
11388
11389         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11390
11391         /* clean found parsers */
11392         if (player->parsers) {
11393                 GList *parsers = player->parsers;
11394                 for (; parsers; parsers = g_list_next(parsers)) {
11395                         gchar *name = parsers->data;
11396                         MMPLAYER_FREEIF(name);
11397                 }
11398                 g_list_free(player->parsers);
11399                 player->parsers = NULL;
11400         }
11401
11402         /* clean found audio decoders */
11403         if (player->audio_decoders) {
11404                 GList *a_dec = player->audio_decoders;
11405                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11406                         gchar *name = a_dec->data;
11407                         MMPLAYER_FREEIF(name);
11408                 }
11409                 g_list_free(player->audio_decoders);
11410                 player->audio_decoders = NULL;
11411         }
11412
11413         /* clean the uri list except original uri */
11414         if (player->uri_info.uri_list) {
11415                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11416
11417                 if (player->attrs) {
11418                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11419                         LOGD("restore original uri = %s\n", original_uri);
11420
11421                         if (mmf_attrs_commit(player->attrs))
11422                                 LOGE("failed to commit the original uri.\n");
11423                 }
11424
11425                 GList *uri_list = player->uri_info.uri_list;
11426                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11427                         gchar *uri = uri_list->data;
11428                         MMPLAYER_FREEIF(uri);
11429                 }
11430                 g_list_free(player->uri_info.uri_list);
11431                 player->uri_info.uri_list = NULL;
11432         }
11433
11434         /* clear the audio stream buffer list */
11435         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11436
11437         /* clear the video stream bo list */
11438         __mmplayer_video_stream_destroy_bo_list(player);
11439         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11440
11441         if (player->profile.input_mem.buf) {
11442                 free(player->profile.input_mem.buf);
11443                 player->profile.input_mem.buf = NULL;
11444         }
11445         player->profile.input_mem.len = 0;
11446         player->profile.input_mem.offset = 0;
11447
11448         player->uri_info.uri_idx = 0;
11449         MMPLAYER_FLEAVE();
11450 }
11451
11452 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11453 {
11454         GstElement *element = NULL;
11455         GstPad *sinkpad;
11456
11457         LOGD("creating %s to plug\n", name);
11458
11459         element = gst_element_factory_make(name, NULL);
11460         if (!element) {
11461                 LOGE("failed to create queue\n");
11462                 return NULL;
11463         }
11464
11465         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11466                 LOGE("failed to set state READY to %s\n", name);
11467                 gst_object_unref(element);
11468                 return NULL;
11469         }
11470
11471         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11472                 LOGE("failed to add %s\n", name);
11473                 gst_object_unref(element);
11474                 return NULL;
11475         }
11476
11477         sinkpad = gst_element_get_static_pad(element, "sink");
11478
11479         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11480                 LOGE("failed to link %s\n", name);
11481                 gst_object_unref(sinkpad);
11482                 gst_object_unref(element);
11483                 return NULL;
11484         }
11485
11486         LOGD("linked %s to pipeline successfully\n", name);
11487
11488         gst_object_unref(sinkpad);
11489
11490         return element;
11491 }
11492
11493 gboolean
11494 __mmplayer_check_subtitle(mm_player_t* player)
11495 {
11496         MMHandleType attrs = 0;
11497         char *subtitle_uri = NULL;
11498
11499         MMPLAYER_FENTER();
11500
11501         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11502
11503         /* get subtitle attribute */
11504         attrs = MMPLAYER_GET_ATTRS(player);
11505         if (!attrs)
11506                 return FALSE;
11507
11508         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11509         if (!subtitle_uri || !strlen(subtitle_uri))
11510                 return FALSE;
11511
11512         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11513         player->is_external_subtitle_present = TRUE;
11514
11515         MMPLAYER_FLEAVE();
11516
11517         return TRUE;
11518 }
11519
11520 static gboolean
11521 __mmplayer_can_extract_pcm(mm_player_t* player)
11522 {
11523         MMHandleType attrs = 0;
11524         gboolean sound_extraction = FALSE;
11525
11526         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11527
11528         attrs = MMPLAYER_GET_ATTRS(player);
11529         if (!attrs) {
11530                 LOGE("fail to get attributes.");
11531                 return FALSE;
11532         }
11533
11534         /* get sound_extraction property */
11535         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11536
11537         if (!sound_extraction) {
11538                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11539                 return FALSE;
11540         }
11541
11542         return TRUE;
11543 }
11544
11545 static gboolean
11546 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11547 {
11548         LOGD("\n");
11549         MMMessageParamType msg_param;
11550         gchar *msg_src_element = NULL;
11551         GstStructure *s = NULL;
11552         guint error_id = 0;
11553         gchar *error_string = NULL;
11554
11555         MMPLAYER_FENTER();
11556
11557         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11558         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11559
11560         s = gst_structure_copy(gst_message_get_structure(message));
11561
11562
11563         if (!gst_structure_get_uint(s, "error_id", &error_id))
11564                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11565
11566         switch (error_id) {
11567         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11568                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11569                 break;
11570         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11571                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11572                 break;
11573         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11574                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11575                 break;
11576         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11577                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11578                 break;
11579         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11580                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11581                 break;
11582         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11583                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11584                 break;
11585         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11586                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11587                 break;
11588         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11589                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11590                 break;
11591         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11592                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11593                 break;
11594         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11595                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11596                 break;
11597         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11598                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11599                 break;
11600         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11601                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11602                 break;
11603         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11604                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11605                 break;
11606         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11607                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11608                 break;
11609         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11610                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11611                 break;
11612         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11613                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11614                 break;
11615         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11616                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11617                 break;
11618         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11619                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11620                 break;
11621         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11622                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11623                 break;
11624         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11625                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11626                 break;
11627         case MMPLAYER_STREAMING_ERROR_GONE:
11628                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11629                 break;
11630         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11631                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11632                 break;
11633         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11634                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11635                 break;
11636         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11637                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11638                 break;
11639         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11640                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11641                 break;
11642         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11643                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11644                 break;
11645         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11646                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11647                 break;
11648         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11649                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11650                 break;
11651         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11652                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11653                 break;
11654         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11655                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11656                 break;
11657         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11658                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11659                 break;
11660         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11661                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11662                 break;
11663         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11664                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11665                 break;
11666         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11667                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11668                 break;
11669         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11670                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11671                 break;
11672         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11673                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11674                 break;
11675         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11676                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11677                 break;
11678         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11679                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11680                 break;
11681         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11682                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11683                 break;
11684         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11685                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11686                 break;
11687         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11688                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11689                 break;
11690         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11691                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11692                 break;
11693         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11694                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11695                 break;
11696         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11697                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11698                 break;
11699         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11700                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11701                 break;
11702         default:
11703                 {
11704                         gst_structure_free(s);
11705                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11706                 }
11707         }
11708
11709         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11710         if (error_string)
11711                 msg_param.data = (void *) error_string;
11712
11713         if (message->src) {
11714                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11715
11716                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11717                         msg_src_element, msg_param.code, (char*)msg_param.data);
11718         }
11719
11720         /* post error to application */
11721         if (!player->msg_posted) {
11722                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11723
11724                 /* don't post more if one was sent already */
11725                 player->msg_posted = TRUE;
11726         } else
11727                 LOGD("skip error post because it's sent already.\n");
11728
11729         gst_structure_free(s);
11730         MMPLAYER_FLEAVE();
11731         g_free(error_string);
11732
11733         return TRUE;
11734
11735 }
11736
11737 static void
11738 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11739 {
11740         MMPLAYER_RETURN_IF_FAIL(player);
11741
11742         /* post now if delay is zero */
11743         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11744                 LOGD("eos delay is zero. posting EOS now\n");
11745                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11746
11747                 if (player->set_mode.pcm_extraction)
11748                         __mmplayer_cancel_eos_timer(player);
11749
11750                 return;
11751         }
11752
11753         /* cancel if existing */
11754         __mmplayer_cancel_eos_timer(player);
11755
11756         /* init new timeout */
11757         /* NOTE : consider give high priority to this timer */
11758         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11759
11760         player->eos_timer = g_timeout_add(delay_in_ms,
11761                 __mmplayer_eos_timer_cb, player);
11762
11763         player->global_default = g_main_context_default();
11764         LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11765
11766         /* check timer is valid. if not, send EOS now */
11767         if (player->eos_timer == 0) {
11768                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11769                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11770         }
11771 }
11772
11773 static void
11774 __mmplayer_cancel_eos_timer(mm_player_t* player)
11775 {
11776         MMPLAYER_RETURN_IF_FAIL(player);
11777
11778         if (player->eos_timer) {
11779                 LOGD("cancel eos timer");
11780                 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11781                 player->eos_timer = 0;
11782         }
11783
11784         return;
11785 }
11786
11787 static gboolean
11788 __mmplayer_eos_timer_cb(gpointer u_data)
11789 {
11790         mm_player_t* player = NULL;
11791         MMHandleType attrs = 0;
11792         int count = 0;
11793
11794         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11795
11796         player = (mm_player_t*) u_data;
11797         attrs = MMPLAYER_GET_ATTRS(player);
11798
11799         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11800
11801         if (count == -1) {
11802                 gint ret_value = 0;
11803                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11804                 if (ret_value != MM_ERROR_NONE)
11805                         LOGE("seeking to 0 failed in repeat play");
11806         } else {
11807                 /* posting eos */
11808                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11809         }
11810
11811         /* we are returning FALSE as we need only one posting */
11812         return FALSE;
11813 }
11814
11815 /* sending event to one of sinkelements */
11816 static gboolean
11817 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11818 {
11819         GstEvent * event2 = NULL;
11820         GList *sinks = NULL;
11821         gboolean res = FALSE;
11822         MMPLAYER_FENTER();
11823
11824         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11825         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11826
11827         /* While adding subtitles in live feeds seek is getting called.
11828            Adding defensive check in framework layer.*/
11829         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11830                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11831                         LOGE("Should not send seek event during live playback");
11832                         return TRUE;
11833                 }
11834         }
11835
11836         if (player->play_subtitle)
11837                 event2 = gst_event_copy((const GstEvent *)event);
11838
11839         sinks = player->sink_elements;
11840         while (sinks) {
11841                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11842
11843                 if (GST_IS_ELEMENT(sink)) {
11844                         /* keep ref to the event */
11845                         gst_event_ref(event);
11846
11847                         if ((res = gst_element_send_event(sink, event))) {
11848                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11849                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11850
11851                                 /* rtsp case, asyn_done is not called after seek during pause state */
11852                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11853                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11854                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11855                                                         LOGD("RTSP seek completed, after pause state..\n");
11856                                                         player->doing_seek = FALSE;
11857                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11858                                                 }
11859
11860                                         }
11861                                 }
11862
11863                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11864                                         sinks = g_list_next(sinks);
11865                                         continue;
11866                                 } else {
11867                                         break;
11868                                 }
11869                         }
11870
11871                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11872                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11873                 }
11874
11875                 sinks = g_list_next(sinks);
11876         }
11877
11878         /* Note : Textbin is not linked to the video or audio bin.
11879          * It needs to send the event to the text sink seperatelly.
11880          */
11881          if (player->play_subtitle && player->pipeline) {
11882                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11883
11884                 if (GST_IS_ELEMENT(text_sink)) {
11885                         /* keep ref to the event */
11886                         gst_event_ref(event2);
11887
11888                         if ((res = gst_element_send_event(text_sink, event2)))
11889                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11890                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11891                         else
11892                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11893                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11894
11895                         gst_event_unref(event2);
11896                 }
11897          }
11898
11899         gst_event_unref(event);
11900
11901         MMPLAYER_FLEAVE();
11902
11903         return res;
11904 }
11905
11906 static void
11907 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11908 {
11909         MMPLAYER_FENTER();
11910
11911         MMPLAYER_RETURN_IF_FAIL(player);
11912         MMPLAYER_RETURN_IF_FAIL(sink);
11913
11914         player->sink_elements =
11915                 g_list_append(player->sink_elements, sink);
11916
11917         MMPLAYER_FLEAVE();
11918 }
11919
11920 static void
11921 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11922 {
11923         MMPLAYER_FENTER();
11924
11925         MMPLAYER_RETURN_IF_FAIL(player);
11926         MMPLAYER_RETURN_IF_FAIL(sink);
11927
11928         player->sink_elements =
11929                         g_list_remove(player->sink_elements, sink);
11930
11931         MMPLAYER_FLEAVE();
11932 }
11933
11934 static gboolean
11935 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11936                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11937                         gint64 cur, GstSeekType stop_type, gint64 stop)
11938 {
11939         GstEvent* event = NULL;
11940         gboolean result = FALSE;
11941
11942         MMPLAYER_FENTER();
11943
11944         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11945
11946         if (player->pipeline && player->pipeline->textbin)
11947                 __mmplayer_drop_subtitle(player, FALSE);
11948
11949         event = gst_event_new_seek(rate, format, flags, cur_type,
11950                 cur, stop_type, stop);
11951
11952         result = __gst_send_event_to_sink(player, event);
11953
11954         MMPLAYER_FLEAVE();
11955
11956         return result;
11957 }
11958
11959 /* NOTE : be careful with calling this api. please refer to below glib comment
11960  * glib comment : Note that there is a bug in GObject that makes this function much
11961  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11962  * will no longer be called, but, the signal handler is not currently disconnected.
11963  * If the instance is itself being freed at the same time than this doesn't matter,
11964  * since the signal will automatically be removed, but if instance persists,
11965  * then the signal handler will leak. You should not remove the signal yourself
11966  * because in a future versions of GObject, the handler will automatically be
11967  * disconnected.
11968  *
11969  * It's possible to work around this problem in a way that will continue to work
11970  * with future versions of GObject by checking that the signal handler is still
11971  * connected before disconnected it:
11972  *
11973  *  if (g_signal_handler_is_connected(instance, id))
11974  *    g_signal_handler_disconnect(instance, id);
11975  */
11976 static void
11977 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11978 {
11979         GList* sig_list = NULL;
11980         MMPlayerSignalItem* item = NULL;
11981
11982         MMPLAYER_FENTER();
11983
11984         MMPLAYER_RETURN_IF_FAIL(player);
11985
11986         LOGD("release signals type : %d", type);
11987
11988         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11989                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11990                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11991                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11992                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11993                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11994                 return;
11995         }
11996
11997         sig_list = player->signals[type];
11998
11999         for (; sig_list; sig_list = sig_list->next) {
12000                 item = sig_list->data;
12001
12002                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12003                         if (g_signal_handler_is_connected(item->obj, item->sig))
12004                                 g_signal_handler_disconnect(item->obj, item->sig);
12005                 }
12006
12007                 MMPLAYER_FREEIF(item);
12008         }
12009
12010         g_list_free(player->signals[type]);
12011         player->signals[type] = NULL;
12012
12013         MMPLAYER_FLEAVE();
12014
12015         return;
12016 }
12017
12018 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12019 {
12020         mm_player_t* player = 0;
12021         int prev_display_surface_type = 0;
12022         void *prev_display_overlay = NULL;
12023         const gchar *klass = NULL;
12024         gchar *cur_videosink_name = NULL;
12025         int ret = 0;
12026         int i = 0;
12027         int num_of_dec = 2; /* DEC1, DEC2 */
12028
12029         MMPLAYER_FENTER();
12030
12031         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12032         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12033
12034         player = MM_PLAYER_CAST(handle);
12035
12036         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12037                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12038                 MMPLAYER_FLEAVE();
12039                 return MM_ERROR_INVALID_ARGUMENT;
12040         }
12041
12042         /* load previous attributes */
12043         if (player->attrs) {
12044                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12045                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12046                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12047                 if (prev_display_surface_type == surface_type) {
12048                         LOGD("incoming display surface type is same as previous one, do nothing..");
12049                         MMPLAYER_FLEAVE();
12050                         return MM_ERROR_NONE;
12051                 }
12052         } else {
12053                 LOGE("failed to load attributes");
12054                 MMPLAYER_FLEAVE();
12055                 return MM_ERROR_PLAYER_INTERNAL;
12056         }
12057
12058         /* check videosink element is created */
12059         if (!player->pipeline || !player->pipeline->videobin ||
12060                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12061                 LOGD("videosink element is not yet ready");
12062
12063                 /* videobin is not created yet, so we just set attributes related to display surface */
12064                 LOGD("store display attribute for given surface type(%d)", surface_type);
12065                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12066                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12067                 if (mmf_attrs_commit(player->attrs)) {
12068                         LOGE("failed to commit attribute");
12069                         MMPLAYER_FLEAVE();
12070                         return MM_ERROR_PLAYER_INTERNAL;
12071                 }
12072                 MMPLAYER_FLEAVE();
12073                 return MM_ERROR_NONE;
12074         } else {
12075                 /* get player command status */
12076                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12077                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12078                         MMPLAYER_FLEAVE();
12079                         return MM_ERROR_PLAYER_INVALID_STATE;
12080                 }
12081
12082                 /* surface change */
12083                 for (i = 0 ; i < num_of_dec ; i++) {
12084                         if (player->pipeline->mainbin &&
12085                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12086                                 GstElementFactory *decfactory;
12087                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12088
12089                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12090                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12091                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12092                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12093                                                 if (ret) {
12094                                                         goto ERROR_CASE;
12095                                                 } else {
12096                                                         LOGW("success to changing display surface(%d)", surface_type);
12097                                                         MMPLAYER_FLEAVE();
12098                                                         return MM_ERROR_NONE;
12099                                                 }
12100                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12101                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12102                                                 if (ret) {
12103                                                         goto ERROR_CASE;
12104                                                 } else {
12105                                                         LOGW("success to changing display surface(%d)", surface_type);
12106                                                         MMPLAYER_FLEAVE();
12107                                                         return MM_ERROR_NONE;
12108                                                 }
12109                                         } else {
12110                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12111                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12112                                                 goto ERROR_CASE;
12113                                         }
12114                                 }
12115                         }
12116                 }
12117         }
12118
12119 ERROR_CASE:
12120         /* rollback to previous attributes */
12121         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12122         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12123         if (mmf_attrs_commit(player->attrs)) {
12124                 LOGE("failed to commit attributes to rollback");
12125                 MMPLAYER_FLEAVE();
12126                 return MM_ERROR_PLAYER_INTERNAL;
12127         }
12128         MMPLAYER_FLEAVE();
12129         return ret;
12130 }
12131
12132 /* NOTE : It does not support some use cases, eg using colorspace converter */
12133 int
12134 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12135 {
12136         GstPad *src_pad_dec = NULL;
12137         GstPad *sink_pad_videosink = NULL;
12138         GstPad *sink_pad_videobin = NULL;
12139         GstClock *clock = NULL;
12140         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12141         int ret = MM_ERROR_NONE;
12142         gboolean is_audiobin_created = TRUE;
12143
12144         MMPLAYER_FENTER();
12145
12146         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12147         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12148         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12149
12150         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12151         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12152
12153         /* get information whether if audiobin is created */
12154         if (!player->pipeline->audiobin ||
12155                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12156                 LOGW("audiobin is null, this video content may not have audio data");
12157                 is_audiobin_created = FALSE;
12158         }
12159
12160         /* get current state of player */
12161         previous_state = MMPLAYER_CURRENT_STATE(player);
12162         LOGD("previous state(%d)", previous_state);
12163
12164
12165         /* get src pad of decoder and block it */
12166         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12167         if (!src_pad_dec) {
12168                 LOGE("failed to get src pad from decode in mainbin");
12169                 return MM_ERROR_PLAYER_INTERNAL;
12170         }
12171
12172         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12173                 LOGW("trying to block pad(video)");
12174 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12175                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12176                         NULL, NULL, NULL);
12177                 {
12178                         LOGE("failed to set block pad(video)");
12179                         return MM_ERROR_PLAYER_INTERNAL;
12180                 }
12181                 LOGW("pad is blocked(video)");
12182         } else {
12183                 /* no data flows, so no need to do pad_block */
12184                 if (player->doing_seek)
12185                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12186
12187                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12188         }
12189
12190         /* remove pad */
12191         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12192                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12193                 LOGE("failed to remove previous ghost_pad for videobin");
12194                 return MM_ERROR_PLAYER_INTERNAL;
12195         }
12196
12197         /* change state of videobin to NULL */
12198         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12199         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12200         if (ret != GST_STATE_CHANGE_SUCCESS) {
12201                 LOGE("failed to change state of videobin to NULL");
12202                 return MM_ERROR_PLAYER_INTERNAL;
12203         }
12204
12205         /* unlink between decoder and videobin and remove previous videosink from videobin */
12206         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12207         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12208                 LOGE("failed to remove former videosink from videobin");
12209                 return MM_ERROR_PLAYER_INTERNAL;
12210         }
12211
12212         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12213
12214         /* create a new videosink and add it to videobin */
12215         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12216         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12217                 LOGE("failed to create videosink element\n");
12218                 MMPLAYER_FLEAVE();
12219                 return MM_ERROR_PLAYER_INTERNAL;
12220         }
12221         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12222         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12223         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12224
12225         /* save attributes */
12226         if (player->attrs) {
12227                 /* set a new display surface type */
12228                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12229                 /* set a new diplay overlay */
12230                 switch (surface_type) {
12231                 case MM_DISPLAY_SURFACE_OVERLAY:
12232                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12233                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12234                         break;
12235                 default:
12236                         LOGE("invalid type(%d) for changing display surface", surface_type);
12237                         MMPLAYER_FLEAVE();
12238                         return MM_ERROR_INVALID_ARGUMENT;
12239                 }
12240                 if (mmf_attrs_commit(player->attrs)) {
12241                         LOGE("failed to commit");
12242                         MMPLAYER_FLEAVE();
12243                         return MM_ERROR_PLAYER_INTERNAL;
12244                 }
12245         } else {
12246                 LOGE("player->attrs is null, failed to save attributes");
12247                 MMPLAYER_FLEAVE();
12248                 return MM_ERROR_PLAYER_INTERNAL;
12249         }
12250
12251         /* update video param */
12252         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12253                 LOGE("failed to update video param");
12254                 return MM_ERROR_PLAYER_INTERNAL;
12255         }
12256
12257         /* change state of videobin to READY */
12258         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12259         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12260         if (ret != GST_STATE_CHANGE_SUCCESS) {
12261                 LOGE("failed to change state of videobin to READY");
12262                 return MM_ERROR_PLAYER_INTERNAL;
12263         }
12264
12265         /* change ghostpad */
12266         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12267         if (!sink_pad_videosink) {
12268                 LOGE("failed to get sink pad from videosink element");
12269                 return MM_ERROR_PLAYER_INTERNAL;
12270         }
12271         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12272         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12273                 LOGE("failed to set active to ghost_pad");
12274                 return MM_ERROR_PLAYER_INTERNAL;
12275         }
12276         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12277                 LOGE("failed to change ghostpad for videobin");
12278                 return MM_ERROR_PLAYER_INTERNAL;
12279         }
12280         gst_object_unref(sink_pad_videosink);
12281
12282         /* link decoder with videobin */
12283         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12284         if (!sink_pad_videobin) {
12285                 LOGE("failed to get sink pad from videobin");
12286                 return MM_ERROR_PLAYER_INTERNAL;
12287         }
12288         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12289                 LOGE("failed to link");
12290                 return MM_ERROR_PLAYER_INTERNAL;
12291         }
12292         gst_object_unref(sink_pad_videobin);
12293
12294         /* clock setting for a new videosink plugin */
12295         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12296                         so we set it from audiosink plugin or pipeline(system clock) */
12297         if (!is_audiobin_created) {
12298                 LOGW("audiobin is not created, get clock from pipeline..");
12299                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12300         } else {
12301                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12302         }
12303         if (clock) {
12304                 GstClockTime now;
12305                 GstClockTime base_time;
12306                 LOGD("set the clock to videosink");
12307                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12308                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12309                 if (clock) {
12310                         LOGD("got clock of videosink");
12311                         now = gst_clock_get_time(clock);
12312                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12313                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12314                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12315                 } else {
12316                         LOGE("failed to get clock of videosink after setting clock");
12317                         return MM_ERROR_PLAYER_INTERNAL;
12318                 }
12319         } else
12320                 LOGW("failed to get clock, maybe it is the time before first playing");
12321
12322         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12323                 /* change state of videobin to PAUSED */
12324                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12325                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12326                 if (ret != GST_STATE_CHANGE_FAILURE) {
12327                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12328                 } else {
12329                         LOGE("failed to change state of videobin to PLAYING");
12330                         return MM_ERROR_PLAYER_INTERNAL;
12331                 }
12332
12333                 /* release blocked and unref src pad of video decoder */
12334                 #if 0
12335                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12336                         LOGE("failed to set pad blocked FALSE(video)");
12337                         return MM_ERROR_PLAYER_INTERNAL;
12338                 }
12339                 #endif
12340                 LOGW("pad is unblocked(video)");
12341         } else {
12342                 if (player->doing_seek)
12343                         LOGW("not completed seek(%d)", player->doing_seek);
12344                 /* change state of videobin to PAUSED */
12345                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12346                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12347                 if (ret != GST_STATE_CHANGE_FAILURE) {
12348                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12349                 } else {
12350                         LOGE("failed to change state of videobin to PLAYING");
12351                         return MM_ERROR_PLAYER_INTERNAL;
12352                 }
12353
12354                 /* already skipped pad block */
12355                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12356         }
12357
12358         /* do get/set position for new videosink plugin */
12359         {
12360                 unsigned long position = 0;
12361                 gint64 pos_msec = 0;
12362
12363                 LOGD("do get/set position for new videosink plugin");
12364                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12365                         LOGE("failed to get position");
12366                         return MM_ERROR_PLAYER_INTERNAL;
12367                 }
12368 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12369                 /* accurate seek */
12370                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12371                         LOGE("failed to set position");
12372                         return MM_ERROR_PLAYER_INTERNAL;
12373                 }
12374 #else
12375                 /* key unit seek */
12376                 pos_msec = position * G_GINT64_CONSTANT(1000000);
12377                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12378                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12379                                                         GST_SEEK_TYPE_SET, pos_msec,
12380                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12381                 if (!ret) {
12382                         LOGE("failed to set position");
12383                         return MM_ERROR_PLAYER_INTERNAL;
12384                 }
12385 #endif
12386         }
12387
12388         if (src_pad_dec)
12389                 gst_object_unref(src_pad_dec);
12390         LOGD("success to change sink");
12391
12392         MMPLAYER_FLEAVE();
12393
12394         return MM_ERROR_NONE;
12395 }
12396
12397
12398 /* Note : if silent is true, then subtitle would not be displayed. :*/
12399 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12400 {
12401         mm_player_t* player = (mm_player_t*) hplayer;
12402
12403         MMPLAYER_FENTER();
12404
12405         /* check player handle */
12406         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12407
12408         player->set_mode.subtitle_off = silent;
12409
12410         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12411
12412         MMPLAYER_FLEAVE();
12413
12414         return MM_ERROR_NONE;
12415 }
12416
12417 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12418 {
12419         MMPlayerGstElement* mainbin = NULL;
12420         MMPlayerGstElement* textbin = NULL;
12421         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12422         GstState current_state = GST_STATE_VOID_PENDING;
12423         GstState element_state = GST_STATE_VOID_PENDING;
12424         GstState element_pending_state = GST_STATE_VOID_PENDING;
12425         gint64 time = 0;
12426         GstEvent *event = NULL;
12427         int result = MM_ERROR_NONE;
12428
12429         GstClock *curr_clock = NULL;
12430         GstClockTime base_time, start_time, curr_time;
12431
12432
12433         MMPLAYER_FENTER();
12434
12435         /* check player handle */
12436         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12437                                                                 player->pipeline &&
12438                                                                 player->pipeline->mainbin &&
12439                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12440
12441         mainbin = player->pipeline->mainbin;
12442         textbin = player->pipeline->textbin;
12443
12444         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12445
12446         // sync clock with current pipeline
12447         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12448         curr_time = gst_clock_get_time(curr_clock);
12449
12450         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12451         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12452
12453         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12454                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12455
12456         if (current_state > GST_STATE_READY) {
12457                 // sync state with current pipeline
12458                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12459                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12460                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12461
12462                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12463                 if (GST_STATE_CHANGE_FAILURE == ret) {
12464                         LOGE("fail to state change.\n");
12465                         result = MM_ERROR_PLAYER_INTERNAL;
12466                         goto ERROR;
12467                 }
12468         }
12469
12470         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12471         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12472
12473         if (curr_clock) {
12474                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12475                 gst_object_unref(curr_clock);
12476         }
12477
12478         // seek to current position
12479         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12480                 result = MM_ERROR_PLAYER_INVALID_STATE;
12481                 LOGE("gst_element_query_position failed, invalid state\n");
12482                 goto ERROR;
12483         }
12484
12485         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12486         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);
12487         if (event) {
12488                 __gst_send_event_to_sink(player, event);
12489         } else {
12490                 result = MM_ERROR_PLAYER_INTERNAL;
12491                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12492                 goto ERROR;
12493         }
12494
12495         /* sync state with current pipeline */
12496         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12497         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12498         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12499
12500         return MM_ERROR_NONE;
12501
12502 ERROR:
12503         /* release text pipeline resource */
12504         player->textsink_linked = 0;
12505
12506         /* release signal */
12507         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12508
12509         /* release textbin with it's childs */
12510         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12511         MMPLAYER_FREEIF(player->pipeline->textbin);
12512         player->pipeline->textbin = NULL;
12513
12514         /* release subtitle elem */
12515         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12516         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12517
12518         return result;
12519 }
12520
12521 static int
12522 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12523 {
12524         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12525         GstState current_state = GST_STATE_VOID_PENDING;
12526
12527         MMHandleType attrs = 0;
12528         MMPlayerGstElement* mainbin = NULL;
12529         MMPlayerGstElement* textbin = NULL;
12530
12531         gchar* subtitle_uri = NULL;
12532         int result = MM_ERROR_NONE;
12533         const gchar *charset = NULL;
12534
12535         MMPLAYER_FENTER();
12536
12537         /* check player handle */
12538         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12539                                                                 player->pipeline &&
12540                                                                 player->pipeline->mainbin &&
12541                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12542         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12543
12544         mainbin = player->pipeline->mainbin;
12545         textbin = player->pipeline->textbin;
12546
12547         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12548         if (current_state < GST_STATE_READY) {
12549                 result = MM_ERROR_PLAYER_INVALID_STATE;
12550                 LOGE("Pipeline is not in proper state\n");
12551                 goto EXIT;
12552         }
12553
12554         attrs = MMPLAYER_GET_ATTRS(player);
12555         if (!attrs) {
12556                 LOGE("cannot get content attribute\n");
12557                 result = MM_ERROR_PLAYER_INTERNAL;
12558                 goto EXIT;
12559         }
12560
12561         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12562         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12563                 LOGE("subtitle uri is not proper filepath\n");
12564                 result = MM_ERROR_PLAYER_INVALID_URI;
12565                 goto EXIT;
12566         }
12567
12568         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12569                 LOGE("failed to get storage info of subtitle path");
12570                 result = MM_ERROR_PLAYER_INVALID_URI;
12571                 goto EXIT;
12572         }
12573
12574         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12575         LOGD("new subtitle file path is [%s]\n", filepath);
12576
12577         if (!strcmp(filepath, subtitle_uri)) {
12578                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12579                 goto EXIT;
12580         } else {
12581                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12582                 if (mmf_attrs_commit(player->attrs)) {
12583                         LOGE("failed to commit.\n");
12584                         goto EXIT;
12585                 }
12586         }
12587
12588         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12589         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12590         player->subtitle_language_list = NULL;
12591         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12592
12593         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12594         if (ret != GST_STATE_CHANGE_SUCCESS) {
12595                 LOGE("failed to change state of textbin to READY");
12596                 result = MM_ERROR_PLAYER_INTERNAL;
12597                 goto EXIT;
12598         }
12599
12600         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12601         if (ret != GST_STATE_CHANGE_SUCCESS) {
12602                 LOGE("failed to change state of subparse to READY");
12603                 result = MM_ERROR_PLAYER_INTERNAL;
12604                 goto EXIT;
12605         }
12606
12607         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12608         if (ret != GST_STATE_CHANGE_SUCCESS) {
12609                 LOGE("failed to change state of filesrc to READY");
12610                 result = MM_ERROR_PLAYER_INTERNAL;
12611                 goto EXIT;
12612         }
12613
12614         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12615
12616         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12617
12618         charset = util_get_charset(filepath);
12619         if (charset) {
12620                 LOGD("detected charset is %s\n", charset);
12621                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12622         }
12623
12624         result = _mmplayer_sync_subtitle_pipeline(player);
12625
12626 EXIT:
12627         MMPLAYER_FLEAVE();
12628         return result;
12629 }
12630
12631 /* API to switch between external subtitles */
12632 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12633 {
12634         int result = MM_ERROR_NONE;
12635         mm_player_t* player = (mm_player_t*)hplayer;
12636         char *path = NULL;
12637
12638         MMPLAYER_FENTER();
12639
12640         /* check player handle */
12641         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12642
12643         /* filepath can be null in idle state */
12644         if (filepath) {
12645                 /* check file path */
12646                 if ((path = strstr(filepath, "file://")))
12647                         result = util_exist_file_path(path + 7);
12648                 else
12649                         result = util_exist_file_path(filepath);
12650
12651                 if (result != MM_ERROR_NONE) {
12652                         LOGE("invalid subtitle path 0x%X", result);
12653                         return result; /* file not found or permission denied */
12654                 }
12655         }
12656
12657         if (!player->pipeline) {
12658                 /* IDLE state */
12659                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12660                 if (mmf_attrs_commit(player->attrs)) {
12661                         LOGE("failed to commit");       /* subtitle path will not be created */
12662                         return MM_ERROR_PLAYER_INTERNAL;
12663                 }
12664         } else {
12665                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12666                 /* check filepath */
12667                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12668
12669                 if (!__mmplayer_check_subtitle(player)) {
12670                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12671                         if (mmf_attrs_commit(player->attrs)) {
12672                                 LOGE("failed to commit");
12673                                 return MM_ERROR_PLAYER_INTERNAL;
12674                         }
12675
12676                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12677                                 LOGE("fail to create text pipeline");
12678                                 return MM_ERROR_PLAYER_INTERNAL;
12679                         }
12680
12681                         result = _mmplayer_sync_subtitle_pipeline(player);
12682                 } else {
12683                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12684                 }
12685
12686                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12687                 player->is_external_subtitle_added_now = TRUE;
12688
12689                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12690                 if (!player->subtitle_language_list) {
12691                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12692                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12693                                 LOGW("subtitle language list is not updated yet");
12694                 }
12695                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12696         }
12697
12698         MMPLAYER_FLEAVE();
12699         return result;
12700 }
12701
12702 static int
12703 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12704 {
12705         int result = MM_ERROR_NONE;
12706         gchar* change_pad_name = NULL;
12707         GstPad* sinkpad = NULL;
12708         MMPlayerGstElement* mainbin = NULL;
12709         enum MainElementID elemId = MMPLAYER_M_NUM;
12710         GstCaps* caps = NULL;
12711         gint total_track_num = 0;
12712
12713         MMPLAYER_FENTER();
12714
12715         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12716                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12717
12718         LOGD("Change Track(%d) to %d\n", type, index);
12719
12720         mainbin = player->pipeline->mainbin;
12721
12722         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12723                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12724         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12725                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12726         } else {
12727                 /* Changing Video Track is not supported. */
12728                 LOGE("Track Type Error\n");
12729                 goto EXIT;
12730         }
12731
12732         if (mainbin[elemId].gst == NULL) {
12733                 result = MM_ERROR_PLAYER_NO_OP;
12734                 LOGD("Req track doesn't exist\n");
12735                 goto EXIT;
12736         }
12737
12738         total_track_num = player->selector[type].total_track_num;
12739         if (total_track_num <= 0) {
12740                 result = MM_ERROR_PLAYER_NO_OP;
12741                 LOGD("Language list is not available \n");
12742                 goto EXIT;
12743         }
12744
12745         if ((index < 0) || (index >= total_track_num)) {
12746                 result = MM_ERROR_INVALID_ARGUMENT;
12747                 LOGD("Not a proper index : %d \n", index);
12748                 goto EXIT;
12749         }
12750
12751         /*To get the new pad from the selector*/
12752         change_pad_name = g_strdup_printf("sink_%u", index);
12753         if (change_pad_name == NULL) {
12754                 result = MM_ERROR_PLAYER_INTERNAL;
12755                 LOGD("Pad does not exists\n");
12756                 goto EXIT;
12757         }
12758
12759         LOGD("new active pad name: %s\n", change_pad_name);
12760
12761         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12762         if (sinkpad == NULL) {
12763                 LOGD("sinkpad is NULL");
12764                 result = MM_ERROR_PLAYER_INTERNAL;
12765                 goto EXIT;
12766         }
12767
12768         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12769         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12770
12771         caps = gst_pad_get_current_caps(sinkpad);
12772         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12773
12774         if (sinkpad)
12775                 gst_object_unref(sinkpad);
12776
12777         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12778                 __mmplayer_set_audio_attrs(player, caps);
12779
12780 EXIT:
12781
12782         MMPLAYER_FREEIF(change_pad_name);
12783         return result;
12784 }
12785
12786 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12787 {
12788         int result = MM_ERROR_NONE;
12789         mm_player_t* player = NULL;
12790         MMPlayerGstElement* mainbin = NULL;
12791
12792         gint current_active_index = 0;
12793
12794         GstState current_state = GST_STATE_VOID_PENDING;
12795         GstEvent* event = NULL;
12796         gint64 time = 0;
12797
12798         MMPLAYER_FENTER();
12799
12800         player = (mm_player_t*)hplayer;
12801         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12802
12803         if (!player->pipeline) {
12804                 LOGE("Track %d pre setting -> %d\n", type, index);
12805
12806                 player->selector[type].active_pad_index = index;
12807                 goto EXIT;
12808         }
12809
12810         mainbin = player->pipeline->mainbin;
12811
12812         current_active_index = player->selector[type].active_pad_index;
12813
12814         /*If index is same as running index no need to change the pad*/
12815         if (current_active_index == index)
12816                 goto EXIT;
12817
12818         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12819                 result = MM_ERROR_PLAYER_INVALID_STATE;
12820                 goto EXIT;
12821         }
12822
12823         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12824         if (current_state < GST_STATE_PAUSED) {
12825                 result = MM_ERROR_PLAYER_INVALID_STATE;
12826                 LOGW("Pipeline not in porper state\n");
12827                 goto EXIT;
12828         }
12829
12830         result = __mmplayer_change_selector_pad(player, type, index);
12831         if (result != MM_ERROR_NONE) {
12832                 LOGE("change selector pad error\n");
12833                 goto EXIT;
12834         }
12835
12836         player->selector[type].active_pad_index = index;
12837
12838         if (current_state == GST_STATE_PLAYING) {
12839                 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);
12840                 if (event) {
12841                         __gst_send_event_to_sink(player, event);
12842                 } else {
12843                         result = MM_ERROR_PLAYER_INTERNAL;
12844                         goto EXIT;
12845                 }
12846         }
12847
12848 EXIT:
12849         return result;
12850 }
12851
12852 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12853 {
12854         mm_player_t* player = (mm_player_t*) hplayer;
12855
12856         MMPLAYER_FENTER();
12857
12858         /* check player handle */
12859         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12860
12861         *silent = player->set_mode.subtitle_off;
12862
12863         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12864
12865         MMPLAYER_FLEAVE();
12866
12867         return MM_ERROR_NONE;
12868 }
12869
12870 gboolean
12871 __is_ms_buff_src(mm_player_t* player)
12872 {
12873         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12874
12875         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12876 }
12877
12878 gboolean
12879 __has_suffix(mm_player_t* player, const gchar* suffix)
12880 {
12881         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12882         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12883
12884         gboolean ret = FALSE;
12885         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12886         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12887
12888         if (g_str_has_suffix(player->profile.uri, suffix))
12889                 ret = TRUE;
12890
12891         MMPLAYER_FREEIF(t_url);
12892         MMPLAYER_FREEIF(t_suffix);
12893
12894         return ret;
12895 }
12896
12897 int
12898 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12899 {
12900         mm_player_t* player = (mm_player_t*) hplayer;
12901
12902         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12903
12904         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12905                 MMPLAYER_PRINT_STATE(player);
12906                 LOGE("wrong-state : can't set the download mode to parse");
12907                 return MM_ERROR_PLAYER_INVALID_STATE;
12908         }
12909
12910         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12911         player->video_hub_download_mode = mode;
12912
12913         return MM_ERROR_NONE;
12914 }
12915
12916 int
12917 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12918 {
12919         mm_player_t* player = (mm_player_t*) hplayer;
12920
12921         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12922
12923         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12924         player->sync_handler = enable;
12925
12926         return MM_ERROR_NONE;
12927 }
12928
12929 int
12930 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12931                                         long long clock,
12932                                         long long clock_delta,
12933                                         long long video_time,
12934                                         long long media_clock,
12935                                         long long audio_time)
12936 {
12937         mm_player_t* player = (mm_player_t*) hplayer;
12938         MMPlayerGstElement* mainbin = NULL;
12939         GstClockTime start_time_audio = 0, start_time_video = 0;
12940         GstClockTimeDiff base_time = 0, new_base_time = 0;
12941         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12942         gint64 api_delta = 0;
12943         gint64 position = 0, position_delta = 0;
12944         gint64 adj_base_time = 0;
12945         GstClock *curr_clock = NULL;
12946         GstClockTime curr_time = 0;
12947         gboolean query_ret = TRUE;
12948         int result = MM_ERROR_NONE;
12949
12950         MMPLAYER_FENTER();
12951
12952         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12953         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12954         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12955
12956         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12957
12958         if ((video_time < 0) || (player->doing_seek)) {
12959                 LOGD("skip setting master clock.  %lld", video_time);
12960                 goto EXIT;
12961         }
12962
12963         mainbin = player->pipeline->mainbin;
12964
12965         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12966         curr_time = gst_clock_get_time(curr_clock);
12967
12968         current_state = MMPLAYER_CURRENT_STATE(player);
12969
12970         if (current_state == MM_PLAYER_STATE_PLAYING)
12971                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12972
12973         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12974                 (!query_ret)) {
12975                 position = player->last_position;
12976                 LOGD("query fail. %lld", position);
12977         }
12978
12979         clock *= GST_USECOND;
12980         clock_delta *= GST_USECOND;
12981
12982         api_delta = clock - curr_time;
12983         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12984                 player->video_share_api_delta = api_delta;
12985         else
12986                 clock_delta += (api_delta - player->video_share_api_delta);
12987
12988         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12989                 player->video_share_clock_delta = (gint64)clock_delta;
12990
12991                 position_delta = (position/GST_USECOND) - video_time;
12992                 position_delta *= GST_USECOND;
12993
12994                 adj_base_time = position_delta;
12995                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12996
12997         } else {
12998                 gint64 new_play_time = 0;
12999                 gint64 network_delay = 0;
13000
13001                 video_time *= GST_USECOND;
13002
13003                 network_delay = clock_delta - player->video_share_clock_delta;
13004                 new_play_time = video_time + network_delay;
13005
13006                 adj_base_time = position - new_play_time;
13007
13008                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13009                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13010         }
13011
13012         /* Adjust Current Stream Time with base_time of sink
13013          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13014          * 2. Set new base time
13015          *    if adj_base_time is positive value, the stream time will be decreased.
13016          * 3. If seek event is occurred, the start time will be reset. */
13017         if ((player->pipeline->audiobin) &&
13018                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13019                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13020
13021                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13022                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13023                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13024                 }
13025
13026                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13027         }
13028
13029         if ((player->pipeline->videobin) &&
13030                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13031                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13032
13033                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13034                         LOGD("video sink : gst_element_set_start_time -> NONE");
13035                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13036                 }
13037
13038                 // if videobin exist, get base_time from videobin.
13039                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13040         }
13041
13042         new_base_time = base_time + adj_base_time;
13043
13044         if ((player->pipeline->audiobin) &&
13045                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13046                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13047
13048         if ((player->pipeline->videobin) &&
13049                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13050                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13051
13052 EXIT:
13053         MMPLAYER_FLEAVE();
13054
13055         return result;
13056 }
13057
13058 int
13059 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13060                                         long long *video_time,
13061                                         long long *media_clock,
13062                                         long long *audio_time)
13063 {
13064         mm_player_t* player = (mm_player_t*) hplayer;
13065         MMPlayerGstElement* mainbin = NULL;
13066         GstClock *curr_clock = NULL;
13067         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13068         gint64 position = 0;
13069         gboolean query_ret = TRUE;
13070
13071         MMPLAYER_FENTER();
13072
13073         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13074         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13075         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13076
13077         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13078         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13079         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13080
13081         mainbin = player->pipeline->mainbin;
13082
13083         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13084
13085         current_state = MMPLAYER_CURRENT_STATE(player);
13086
13087         if (current_state != MM_PLAYER_STATE_PAUSED)
13088                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13089
13090         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13091                 (!query_ret))
13092                 position = player->last_position;
13093
13094         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13095
13096         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13097
13098         if (curr_clock)
13099                 gst_object_unref(curr_clock);
13100
13101         MMPLAYER_FLEAVE();
13102
13103         return MM_ERROR_NONE;
13104 }
13105
13106 static gboolean
13107 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13108 {
13109         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13110         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13111
13112         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13113         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13114
13115         int idx = 0;
13116
13117         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13118                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13119                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13120                         mm_player_dump_t *dump_s;
13121                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13122
13123                         if (dump_s == NULL) {
13124                                 LOGE("malloc fail");
13125                                 return FALSE;
13126                         }
13127
13128                         dump_s->dump_element_file = NULL;
13129                         dump_s->dump_pad = NULL;
13130                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13131
13132                         if (dump_s->dump_pad) {
13133                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13134                                 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]);
13135                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13136                                 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);
13137                                 /* add list for removed buffer probe and close FILE */
13138                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13139                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13140                                 return TRUE;
13141                         } else {
13142                                 g_free(dump_s);
13143                                 dump_s = NULL;
13144                                 LOGE("failed to get %s sink pad added", factory_name);
13145                         }
13146
13147
13148                 }
13149         }
13150         return FALSE;
13151 }
13152
13153 static GstPadProbeReturn
13154 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13155 {
13156         FILE *dump_data = (FILE *) u_data;
13157 //      int written = 0;
13158         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13159         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13160
13161         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13162
13163         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13164
13165 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13166
13167         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13168
13169         return GST_PAD_PROBE_OK;
13170 }
13171
13172 static void
13173 __mmplayer_release_dump_list(GList *dump_list)
13174 {
13175         if (dump_list) {
13176                 GList *d_list = dump_list;
13177                 for (; d_list; d_list = g_list_next(d_list)) {
13178                         mm_player_dump_t *dump_s = d_list->data;
13179                         if (dump_s->dump_pad) {
13180                                 if (dump_s->probe_handle_id)
13181                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13182                         }
13183                         if (dump_s->dump_element_file) {
13184                                 fclose(dump_s->dump_element_file);
13185                                 dump_s->dump_element_file = NULL;
13186                         }
13187                         MMPLAYER_FREEIF(dump_s);
13188                 }
13189                 g_list_free(dump_list);
13190                 dump_list = NULL;
13191         }
13192 }
13193
13194 int
13195 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13196 {
13197         mm_player_t* player = (mm_player_t*) hplayer;
13198
13199         MMPLAYER_FENTER();
13200
13201         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13202         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13203
13204         *exist = player->has_closed_caption;
13205
13206         MMPLAYER_FLEAVE();
13207
13208         return MM_ERROR_NONE;
13209 }
13210
13211 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13212 {
13213         MMPLAYER_FENTER();
13214         if (buffer) {
13215                 // LOGD("unref internal gst buffer %p", buffer);
13216                 gst_buffer_unref((GstBuffer *)buffer);
13217                 buffer = NULL;
13218         }
13219         MMPLAYER_FLEAVE();
13220 }
13221
13222 void
13223 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13224 {
13225         mm_player_t *player  = (mm_player_t*)user_data;
13226         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13227         guint64 current_level_bytes = 0;
13228
13229         MMPLAYER_RETURN_IF_FAIL(player);
13230
13231         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13232
13233         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13234         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13235
13236         if (player->media_stream_buffer_status_cb[type])
13237                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13238         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13239
13240 }
13241
13242 void
13243 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13244 {
13245         mm_player_t *player  = (mm_player_t*)user_data;
13246         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13247         guint64 current_level_bytes = 0;
13248
13249         MMPLAYER_RETURN_IF_FAIL(player);
13250
13251         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13252
13253         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13254
13255         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13256         if (player->media_stream_buffer_status_cb[type])
13257                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13258         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13259 }
13260
13261 void
13262 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13263 {
13264         mm_player_t *player  = (mm_player_t*)user_data;
13265         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13266         guint64 current_level_bytes = 0;
13267
13268         MMPLAYER_RETURN_IF_FAIL(player);
13269
13270         LOGI("app-src: feed subtitle\n");
13271
13272         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13273
13274         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13275         if (player->media_stream_buffer_status_cb[type])
13276                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13277
13278         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13279 }
13280
13281 void
13282 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13283 {
13284         mm_player_t *player  = (mm_player_t*)user_data;
13285         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13286         guint64 current_level_bytes = 0;
13287
13288         MMPLAYER_RETURN_IF_FAIL(player);
13289
13290         LOGI("app-src: audio buffer is full.\n");
13291
13292         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13293
13294         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13295
13296         if (player->media_stream_buffer_status_cb[type])
13297                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13298
13299         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13300 }
13301
13302 void
13303 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13304 {
13305         mm_player_t *player  = (mm_player_t*)user_data;
13306         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13307         guint64 current_level_bytes = 0;
13308
13309         MMPLAYER_RETURN_IF_FAIL(player);
13310
13311         LOGI("app-src: video buffer is full.\n");
13312
13313         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13314
13315         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13316         if (player->media_stream_buffer_status_cb[type])
13317                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13318
13319         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13320 }
13321
13322 gboolean
13323 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13324 {
13325         mm_player_t *player  = (mm_player_t*)user_data;
13326         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13327
13328         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13329
13330         LOGD("app-src: seek audio data %llu\n", position);
13331         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13332
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_video_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_VIDEO;
13345
13346         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13347
13348         LOGD("app-src: seek video data %llu\n", position);
13349         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13350         if (player->media_stream_seek_data_cb[type])
13351                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13352         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13353
13354         return TRUE;
13355 }
13356
13357 gboolean
13358 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13359 {
13360         mm_player_t *player  = (mm_player_t*)user_data;
13361         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13362
13363         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13364
13365         LOGD("app-src: seek subtitle data\n");
13366         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13367
13368         if (player->media_stream_seek_data_cb[type])
13369                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13370         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13371
13372         return TRUE;
13373 }
13374
13375 int
13376 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13377 {
13378         mm_player_t* player = (mm_player_t*) hplayer;
13379
13380         MMPLAYER_FENTER();
13381
13382         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13383
13384         player->pcm_samplerate = samplerate;
13385         player->pcm_channel = channel;
13386
13387         MMPLAYER_FLEAVE();
13388         return MM_ERROR_NONE;
13389 }
13390
13391 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13392 {
13393         mm_player_t* player = (mm_player_t*) hplayer;
13394
13395         MMPLAYER_FENTER();
13396
13397         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13398         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13399
13400         if (MMPLAYER_IS_STREAMING(player))
13401                 *timeout = player->ini.live_state_change_timeout;
13402         else
13403                 *timeout = player->ini.localplayback_state_change_timeout;
13404
13405         LOGD("timeout = %d\n", *timeout);
13406
13407         MMPLAYER_FLEAVE();
13408         return MM_ERROR_NONE;
13409 }
13410
13411 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13412 {
13413         mm_player_t* player = (mm_player_t*) hplayer;
13414
13415         MMPLAYER_FENTER();
13416
13417         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13418         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13419
13420         *num = player->video_num_buffers;
13421         *extra_num = player->video_extra_num_buffers;
13422
13423         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13424
13425         MMPLAYER_FLEAVE();
13426         return MM_ERROR_NONE;
13427 }
13428
13429 static void
13430 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13431 {
13432         int i = 0;
13433         MMPLAYER_FENTER();
13434         MMPLAYER_RETURN_IF_FAIL(player);
13435
13436         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13437
13438                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13439                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13440                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13441                         player->storage_info[i].id = -1;
13442                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13443
13444                         if (path_type != MMPLAYER_PATH_MAX)
13445                                 break;
13446                 }
13447         }
13448
13449         MMPLAYER_FLEAVE();
13450 }
13451
13452 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13453 {
13454         int ret = MM_ERROR_NONE;
13455         mm_player_t* player = (mm_player_t*)hplayer;
13456         MMMessageParamType msg_param = {0, };
13457
13458         MMPLAYER_FENTER();
13459         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13460
13461         LOGW("state changed storage %d:%d", id, state);
13462
13463         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13464                 return MM_ERROR_NONE;
13465
13466         /* FIXME: text path should be handled seperately. */
13467         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13468                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13469                 LOGW("external storage is removed");
13470
13471                 if (player->msg_posted == FALSE) {
13472                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13473                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13474                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13475                         player->msg_posted = TRUE;
13476                 }
13477
13478                 /* unrealize the player */
13479                 ret = _mmplayer_unrealize(hplayer);
13480                 if (ret != MM_ERROR_NONE)
13481                         LOGE("failed to unrealize");
13482         }
13483
13484         MMPLAYER_FLEAVE();
13485         return ret;
13486 }
13487
13488 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13489 {
13490         int ret = MM_ERROR_NONE;
13491         mm_player_t* player = (mm_player_t*) hplayer;
13492         int idx = 0, total = 0;
13493         gchar *result = NULL, *tmp = NULL;
13494
13495         MMPLAYER_FENTER();
13496         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13497         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13498
13499         total = *num = g_list_length(player->adaptive_info.var_list);
13500         if (total <= 0) {
13501                 LOGW("There is no stream variant info.");
13502                 return ret;
13503         }
13504
13505         result = g_strdup("");
13506         for (idx = 0 ; idx < total ; idx++) {
13507                 VariantData *v_data = NULL;
13508                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13509
13510                 if (v_data) {
13511                         gchar data[64] = {0};
13512                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13513
13514                         tmp = g_strconcat(result, data, NULL);
13515                         g_free(result);
13516                         result = tmp;
13517                 } else {
13518                         LOGW("There is no variant data in %d", idx);
13519                         (*num)--;
13520                 }
13521         }
13522
13523         *var_info = (char *)result;
13524
13525         LOGD("variant info %d:%s", *num, *var_info);
13526         MMPLAYER_FLEAVE();
13527         return ret;
13528 }
13529
13530 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13531 {
13532         int ret = MM_ERROR_NONE;
13533         mm_player_t* player = (mm_player_t*) hplayer;
13534
13535         MMPLAYER_FENTER();
13536         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13537
13538         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13539
13540         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13541         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13542         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13543
13544         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13545                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13546                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13547                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13548
13549                 /* FIXME: seek to current position for applying new variant limitation */
13550         }
13551
13552         MMPLAYER_FLEAVE();
13553         return ret;
13554
13555 }
13556
13557 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13558 {
13559         int ret = MM_ERROR_NONE;
13560         mm_player_t* player = (mm_player_t*) hplayer;
13561
13562         MMPLAYER_FENTER();
13563         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13564         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13565
13566         *bandwidth = player->adaptive_info.limit.bandwidth;
13567         *width = player->adaptive_info.limit.width;
13568         *height = player->adaptive_info.limit.height;
13569
13570         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13571
13572         MMPLAYER_FLEAVE();
13573         return ret;
13574 }
13575
13576 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13577 {
13578         int ret = MM_ERROR_NONE;
13579         mm_player_t* player = (mm_player_t*) hplayer;
13580
13581         MMPLAYER_FENTER();
13582         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13583
13584         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13585                 LOGW("buffer_ms will not be applied.");
13586
13587
13588         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13589
13590         if (player->streamer == NULL) {
13591                 player->streamer = __mm_player_streaming_create();
13592                 __mm_player_streaming_initialize(player->streamer);
13593         }
13594
13595         if (buffer_ms >= 0)
13596                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13597
13598         if (rebuffer_ms >= 0)
13599                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13600
13601         MMPLAYER_FLEAVE();
13602         return ret;
13603
13604 }
13605
13606 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13607 {
13608         int ret = MM_ERROR_NONE;
13609         mm_player_t* player = (mm_player_t*) hplayer;
13610
13611         MMPLAYER_FENTER();
13612         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13613         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13614
13615         if (player->streamer == NULL) {
13616                 player->streamer = __mm_player_streaming_create();
13617                 __mm_player_streaming_initialize(player->streamer);
13618         }
13619
13620         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13621         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13622
13623         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13624
13625         MMPLAYER_FLEAVE();
13626         return ret;
13627 }
13628
13629 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13630 {
13631 #define IDX_FIRST_SW_CODEC 0
13632         mm_player_t* player = (mm_player_t*) hplayer;
13633         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13634         MMHandleType attrs = 0;
13635
13636         MMPLAYER_FENTER();
13637         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638
13639         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13640                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13641                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13642
13643         switch (stream_type) {
13644         case MM_PLAYER_STREAM_TYPE_AUDIO:
13645                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13646                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13647                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13648                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13649                         LOGE("There is no a codec for codec_type %d", codec_type);
13650                         return MM_ERROR_PLAYER_NO_OP;
13651                 }
13652         break;
13653         case MM_PLAYER_STREAM_TYPE_VIDEO:
13654                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13655                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13656                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13657                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13658                         LOGE("There is no v codec for codec_type %d", codec_type);
13659                         return MM_ERROR_PLAYER_NO_OP;
13660                 }
13661
13662         break;
13663         default:
13664                 LOGE("Invalid stream type %d", stream_type);
13665                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13666         break;
13667         }
13668
13669         LOGD("update %s codec_type to %d", attr_name, codec_type);
13670
13671         attrs = MMPLAYER_GET_ATTRS(player);
13672         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13673
13674         if (mmf_attrs_commit(player->attrs)) {
13675                 LOGE("failed to commit codec_type attributes");
13676                 return MM_ERROR_PLAYER_INTERNAL;
13677         }
13678
13679         MMPLAYER_FLEAVE();
13680         return MM_ERROR_NONE;
13681 }
13682
13683 int
13684 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13685 {
13686         mm_player_t* player = (mm_player_t*) hplayer;
13687         GstElement* rg_vol_element = NULL;
13688
13689         MMPLAYER_FENTER();
13690
13691         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13692
13693         player->sound.rg_enable = enabled;
13694
13695         /* just hold rgvolume enable value if pipeline is not ready */
13696         if (!player->pipeline || !player->pipeline->audiobin) {
13697                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13698                 return MM_ERROR_NONE;
13699         }
13700
13701         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13702
13703         if (!rg_vol_element) {
13704                 LOGD("rgvolume element is not created");
13705                 return MM_ERROR_PLAYER_INTERNAL;
13706         }
13707
13708         if (enabled)
13709                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13710         else
13711                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13712
13713         MMPLAYER_FLEAVE();
13714
13715         return MM_ERROR_NONE;
13716 }
13717
13718 int
13719 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13720 {
13721         mm_player_t* player = (mm_player_t*) hplayer;
13722         GstElement* rg_vol_element = NULL;
13723         gboolean enable = FALSE;
13724
13725         MMPLAYER_FENTER();
13726
13727         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13728         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13729
13730         /* just hold enable_rg value if pipeline is not ready */
13731         if (!player->pipeline || !player->pipeline->audiobin) {
13732                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13733                 *enabled = player->sound.rg_enable;
13734                 return MM_ERROR_NONE;
13735         }
13736
13737         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13738
13739         if (!rg_vol_element) {
13740                 LOGD("rgvolume element is not created");
13741                 return MM_ERROR_PLAYER_INTERNAL;
13742         }
13743
13744         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13745         *enabled = enable;
13746
13747         MMPLAYER_FLEAVE();
13748
13749         return MM_ERROR_NONE;
13750 }