628a956a711bf1f03ee15ca65447871a403efa05
[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 /* For PD mode */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE             1024 * 1024 * 3
103
104 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
105 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
106
107 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
108 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
109 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
110 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
111
112 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
113 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
114
115 /*---------------------------------------------------------------------------
116 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
117 ---------------------------------------------------------------------------*/
118
119 /*---------------------------------------------------------------------------
120 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
121 ---------------------------------------------------------------------------*/
122
123 /*---------------------------------------------------------------------------
124 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
125 ---------------------------------------------------------------------------*/
126
127 /*---------------------------------------------------------------------------
128 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
129 ---------------------------------------------------------------------------*/
130 static sound_stream_info_h stream_info;
131
132 /*---------------------------------------------------------------------------
133 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
134 ---------------------------------------------------------------------------*/
135 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
138 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
139 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
140 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
141 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
142
143 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
144 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
145 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
146 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
149 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
153 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
154 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
155 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
160
161 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
162 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
164 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
165 static void             __mmplayer_release_misc(mm_player_t* player);
166 static void             __mmplayer_release_misc_post(mm_player_t* player);
167 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
168 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
169 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
170 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
171 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
172 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
173 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
175 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
176 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
177 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
178
179 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
180 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
181 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
182 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
183 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
184 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
185 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
186 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
187 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
188 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
189 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
190 static gpointer __mmplayer_next_play_thread(gpointer data);
191 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
192
193 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
194 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
195 static void __mmplayer_release_dump_list(GList *dump_list);
196
197 static int              __gst_realize(mm_player_t* player);
198 static int              __gst_unrealize(mm_player_t* player);
199 static int              __gst_start(mm_player_t* player);
200 static int              __gst_stop(mm_player_t* player);
201 static int              __gst_pause(mm_player_t* player, gboolean async);
202 static int              __gst_resume(mm_player_t* player, gboolean async);
203 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
204                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
205                                         gint64 cur, GstSeekType stop_type, gint64 stop);
206 static int __gst_pending_seek(mm_player_t* player);
207
208 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
209 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
210 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
211 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
212 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
213
214 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
215
216 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
217 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
218
219 /* util */
220 static gboolean __is_ms_buff_src(mm_player_t* player);
221 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
222
223 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
224 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
225 static int __mmplayer_start_streaming_ext(mm_player_t *player);
226 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
227 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
228
229 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
230 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
231 static void __mmplayer_check_pipeline(mm_player_t* player);
232 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
233 static void __mmplayer_deactivate_old_path(mm_player_t *player);
234
235 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
236 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
237
238 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
239 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
240 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
241 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
242 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
243 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
244 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
245 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
247 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
248 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
249 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
250 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
251 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
252 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
253 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
254
255 /*===========================================================================================
256 |                                                                                                                                                                                       |
257 |  FUNCTION DEFINITIONS                                                                                                                                         |
258 |                                                                                                                                                                                       |
259 ========================================================================================== */
260
261 #if 0 //debug
262 static void
263 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
264 {
265         gint i, count;
266
267         count = gst_tag_list_get_tag_size(list, tag);
268
269         LOGD("count = %d", count);
270
271         for (i = 0; i < count; i++) {
272                 gchar *str;
273
274                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
275                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
276                                 g_assert_not_reached();
277                 } else
278                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
279
280                 if (i == 0)
281                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
282                 else
283                         g_print("                 : %s\n", str);
284
285                 g_free(str);
286         }
287 }
288 #endif
289
290 /* This function should be called after the pipeline goes PAUSED or higher
291 state. */
292 gboolean
293 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
294 {
295         static gboolean has_duration = FALSE;
296         static gboolean has_video_attrs = FALSE;
297         static gboolean has_audio_attrs = FALSE;
298         static gboolean has_bitrate = FALSE;
299         gboolean missing_only = FALSE;
300         gboolean all = FALSE;
301         gint64 dur_nsec = 0;
302         GstStructure* p = NULL;
303         MMHandleType attrs = 0;
304         gchar *path = NULL;
305         struct stat sb;
306
307         MMPLAYER_FENTER();
308
309         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
310
311         /* check player state here */
312         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
313                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
314                 /* give warning now only */
315                 LOGW("be careful. content attributes may not available in this state ");
316         }
317
318         /* get content attribute first */
319         attrs = MMPLAYER_GET_ATTRS(player);
320         if (!attrs) {
321                 LOGE("cannot get content attribute");
322                 return FALSE;
323         }
324
325         /* get update flag */
326
327         if (flag & ATTR_MISSING_ONLY) {
328                 missing_only = TRUE;
329                 LOGD("updating missed attr only");
330         }
331
332         if (flag & ATTR_ALL) {
333                 all = TRUE;
334                 has_duration = FALSE;
335                 has_video_attrs = FALSE;
336                 has_audio_attrs = FALSE;
337                 has_bitrate = FALSE;
338
339                 LOGD("updating all attrs");
340         }
341
342         if (missing_only && all) {
343                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
344                 missing_only = FALSE;
345         }
346
347         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
348                 LOGD("try to update duration");
349                 has_duration = FALSE;
350
351                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
352                         player->duration = dur_nsec;
353                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
354                 }
355
356                 if (player->duration < 0) {
357                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
358                         player->duration = 0;
359                 }
360
361                 /* update streaming service type */
362                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
363
364                 /* check duration is OK */
365                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
366                         /* FIXIT : find another way to get duration here. */
367                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
368                 } else {
369                         /*update duration */
370                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
371                         has_duration = TRUE;
372                 }
373         }
374
375         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
376                 /* update audio params
377                 NOTE : We need original audio params and it can be only obtained from src pad of audio
378                 decoder. Below code only valid when we are not using 'resampler' just before
379                 'audioconverter'. */
380
381                 LOGD("try to update audio attrs");
382                 has_audio_attrs = FALSE;
383
384                 if (player->pipeline->audiobin &&
385                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
386                         GstCaps *caps_a = NULL;
387                         GstPad* pad = NULL;
388                         gint samplerate = 0, channels = 0;
389
390                         pad = gst_element_get_static_pad(
391                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
392
393                         if (pad) {
394                                 caps_a = gst_pad_get_current_caps(pad);
395
396                                 if (caps_a) {
397                                         p = gst_caps_get_structure(caps_a, 0);
398
399                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
400
401                                         gst_structure_get_int(p, "rate", &samplerate);
402                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
403
404                                         gst_structure_get_int(p, "channels", &channels);
405                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
406
407                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
408
409                                         gst_caps_unref(caps_a);
410                                         caps_a = NULL;
411
412                                         has_audio_attrs = TRUE;
413                                 } else
414                                         LOGW("not ready to get audio caps");
415
416                                 gst_object_unref(pad);
417                         } else
418                                 LOGW("failed to get pad from audiosink");
419                 }
420         }
421
422         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
423                 LOGD("try to update video attrs");
424                 has_video_attrs = FALSE;
425
426                 if (player->pipeline->videobin &&
427                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
428                         GstCaps *caps_v = NULL;
429                         GstPad* pad = NULL;
430                         gint tmpNu, tmpDe;
431                         gint width, height;
432
433                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
434                         if (pad) {
435                                 caps_v = gst_pad_get_current_caps(pad);
436
437                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
438                                 if (!caps_v && player->v_stream_caps) {
439                                         caps_v = player->v_stream_caps;
440                                         gst_caps_ref(caps_v);
441                                 }
442
443                                 if (caps_v) {
444                                         p = gst_caps_get_structure(caps_v, 0);
445                                         gst_structure_get_int(p, "width", &width);
446                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
447
448                                         gst_structure_get_int(p, "height", &height);
449                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
450
451                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
452
453                                         SECURE_LOGD("width : %d     height : %d", width, height);
454
455                                         gst_caps_unref(caps_v);
456                                         caps_v = NULL;
457
458                                         if (tmpDe > 0) {
459                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
460                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
461                                         }
462
463                                         has_video_attrs = TRUE;
464                                 } else
465                                         LOGD("no negitiated caps from videosink");
466                                 gst_object_unref(pad);
467                                 pad = NULL;
468                         } else
469                                 LOGD("no videosink sink pad");
470                 }
471         }
472
473
474         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
475                 has_bitrate = FALSE;
476
477                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
478                 if (player->duration) {
479                         guint64 data_size = 0;
480
481                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
482                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
483
484                                 if (stat(path, &sb) == 0)
485                                         data_size = (guint64)sb.st_size;
486                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
487                                 data_size = player->http_content_size;
488                         }
489                         LOGD("try to update bitrate : data_size = %lld", data_size);
490
491                         if (data_size) {
492                                 guint64 bitrate = 0;
493                                 guint64 msec_dur = 0;
494
495                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
496                                 if (msec_dur > 0) {
497                                         bitrate = data_size * 8 * 1000 / msec_dur;
498                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
499                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
500
501                                         has_bitrate = TRUE;
502                                 } else {
503                                         LOGD("player duration is less than 0");
504                                 }
505                         }
506
507                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
508                                 if (player->total_bitrate) {
509                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
510                                         has_bitrate = TRUE;
511                                 }
512                         }
513                 }
514         }
515
516         /* validate all */
517         if (mmf_attrs_commit(attrs)) {
518                 LOGE("failed to update attributes\n");
519                 return FALSE;
520         }
521
522         MMPLAYER_FLEAVE();
523
524         return TRUE;
525 }
526
527 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
528 {
529         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
530
531         MMPLAYER_FENTER();
532
533         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
534                         player->pipeline &&
535                         player->pipeline->mainbin &&
536                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
537                         STREAMING_SERVICE_NONE);
538
539         /* streaming service type if streaming */
540         if (!MMPLAYER_IS_STREAMING(player))
541                 return STREAMING_SERVICE_NONE;
542
543         if (MMPLAYER_IS_HTTP_STREAMING(player))
544                 streaming_type = (player->duration == 0) ?
545                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
546
547         switch (streaming_type) {
548         case STREAMING_SERVICE_LIVE:
549                 LOGD("it's live streaming");
550                 break;
551         case STREAMING_SERVICE_VOD:
552                 LOGD("it's vod streaming");
553                 break;
554         default:
555                 LOGE("should not get here");
556                 break;
557         }
558
559         MMPLAYER_FLEAVE();
560
561         return streaming_type;
562 }
563
564
565 /* this function sets the player state and also report
566  * it to applicaton by calling callback function
567  */
568 int
569 __mmplayer_set_state(mm_player_t* player, int state)
570 {
571         MMMessageParamType msg = {0, };
572         gboolean post_bos = FALSE;
573
574         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
575
576         if (MMPLAYER_CURRENT_STATE(player) == state) {
577                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
578                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
579                 return MM_ERROR_NONE;
580         }
581
582         /* update player states */
583         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
584         MMPLAYER_CURRENT_STATE(player) = state;
585
586         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
587                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
588
589         /* print state */
590         MMPLAYER_PRINT_STATE(player);
591
592         switch (MMPLAYER_CURRENT_STATE(player)) {
593         case MM_PLAYER_STATE_NULL:
594         case MM_PLAYER_STATE_READY:
595                 break;
596
597         case MM_PLAYER_STATE_PAUSED:
598                 {
599                         if (!player->sent_bos) {
600                                 /* rtsp case, get content attrs by GstMessage */
601                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
602                                         /* it's first time to update all content attrs. */
603                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
604                                 }
605                         }
606
607                         /* add audio callback probe if condition is satisfied */
608                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
609                                 __mmplayer_configure_audio_callback(player);
610
611                         /* FIXIT : handle return value */
612                 }
613                 break;
614
615         case MM_PLAYER_STATE_PLAYING:
616                 {
617                         /* try to get content metadata */
618                         if (!player->sent_bos) {
619                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
620                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
621                                  * legacy mmfw-player api */
622                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
623                         }
624
625                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
626                                 if (!player->sent_bos)
627                                         __mmplayer_handle_missed_plugin(player);
628                         }
629
630                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
631                                 /* initialize because auto resume is done well. */
632                                 player->resumed_by_rewind = FALSE;
633                                 player->playback_rate = 1.0;
634                         }
635
636                         if (!player->sent_bos) {
637                                 /* check audio codec field is set or not
638                                  * we can get it from typefinder or codec's caps.
639                                  */
640                                 gchar *audio_codec = NULL;
641                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
642
643                                 /* The codec format can't be sent for audio only case like amr, mid etc.
644                                  * Because, parser don't make related TAG.
645                                  * So, if it's not set yet, fill it with found data.
646                                  */
647                                 if (!audio_codec) {
648                                         if (g_strrstr(player->type, "audio/midi"))
649                                                 audio_codec = g_strdup("MIDI");
650                                         else if (g_strrstr(player->type, "audio/x-amr"))
651                                                 audio_codec = g_strdup("AMR");
652                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
653                                                 audio_codec = g_strdup("AAC");
654                                         else
655                                                 audio_codec = g_strdup("unknown");
656                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
657
658                                         MMPLAYER_FREEIF(audio_codec);
659                                         if (mmf_attrs_commit(player->attrs))
660                                                 LOGE("failed to update attributes\n");
661
662                                         LOGD("set audio codec type with caps\n");
663                                 }
664
665                                 post_bos = TRUE;
666                         }
667                 }
668                 break;
669
670         case MM_PLAYER_STATE_NONE:
671         default:
672                 LOGW("invalid target state, there is nothing to do.\n");
673                 break;
674         }
675
676
677         /* post message to application */
678         if (MMPLAYER_TARGET_STATE(player) == state) {
679                 /* fill the message with state of player */
680                 msg.union_type = MM_MSG_UNION_STATE;
681                 msg.state.previous = MMPLAYER_PREV_STATE(player);
682                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
683
684                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
685
686                 /* state changed by resource callback */
687                 if (player->interrupted_by_resource) {
688                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
689                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
690                 } else { /* state changed by usecase */
691                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
692                 }
693         } else {
694                 LOGD("intermediate state, do nothing.\n");
695                 MMPLAYER_PRINT_STATE(player);
696                 return MM_ERROR_NONE;
697         }
698
699         if (post_bos) {
700                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
701                 player->sent_bos = TRUE;
702         }
703
704         return MM_ERROR_NONE;
705 }
706
707 static gpointer __mmplayer_next_play_thread(gpointer data)
708 {
709         mm_player_t* player = (mm_player_t*) data;
710         MMPlayerGstElement *mainbin = NULL;
711
712         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
713
714         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
715         while (!player->next_play_thread_exit) {
716                 LOGD("next play thread started. waiting for signal.\n");
717                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
718
719                 LOGD("reconfigure pipeline for gapless play.\n");
720
721                 if (player->next_play_thread_exit) {
722                         if (player->gapless.reconfigure) {
723                                 player->gapless.reconfigure = false;
724                                 MMPLAYER_PLAYBACK_UNLOCK(player);
725                         }
726                         LOGD("exiting gapless play thread\n");
727                         break;
728                 }
729
730                 mainbin = player->pipeline->mainbin;
731
732                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
733                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
734                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
735                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
736                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
737
738                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
739         }
740         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
741
742         return NULL;
743 }
744
745 static void
746 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
747 {
748         MMHandleType attrs = 0;
749         guint64 data_size = 0;
750         gchar* path = NULL;
751         unsigned long pos_msec = 0;
752         struct stat sb;
753
754         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
755
756         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
757
758         attrs = MMPLAYER_GET_ATTRS(player);
759         if (!attrs) {
760                 LOGE("fail to get attributes.\n");
761                 return;
762         }
763
764         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
765                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
766
767                 if (stat(path, &sb) == 0)
768                         data_size = (guint64)sb.st_size;
769         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
770                 data_size = player->http_content_size;
771
772         __mm_player_streaming_buffering(player->streamer,
773                                                                                 buffering_msg,
774                                                                                 data_size,
775                                                                                 player->last_position,
776                                                                                 player->duration);
777
778         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
779
780         return;
781 }
782
783 static int
784 __mmplayer_handle_buffering_message(mm_player_t* player)
785 {
786         int ret = MM_ERROR_NONE;
787         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
788         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
789         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
790         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
791
792         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
793                 LOGW("do nothing for buffering msg\n");
794                 ret = MM_ERROR_PLAYER_INVALID_STATE;
795                 goto exit;
796         }
797
798         prev_state = MMPLAYER_PREV_STATE(player);
799         current_state = MMPLAYER_CURRENT_STATE(player);
800         target_state = MMPLAYER_TARGET_STATE(player);
801         pending_state = MMPLAYER_PENDING_STATE(player);
802
803         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
804                 MMPLAYER_STATE_GET_NAME(prev_state),
805                 MMPLAYER_STATE_GET_NAME(current_state),
806                 MMPLAYER_STATE_GET_NAME(pending_state),
807                 MMPLAYER_STATE_GET_NAME(target_state),
808                 player->streamer->is_buffering);
809
810         if (!player->streamer->is_buffering) {
811                 /* NOTE : if buffering has done, player has to go to target state. */
812                 switch (target_state) {
813                 case MM_PLAYER_STATE_PAUSED:
814                         {
815                                 switch (pending_state) {
816                                 case MM_PLAYER_STATE_PLAYING:
817                                         __gst_pause(player, TRUE);
818                                         break;
819
820                                 case MM_PLAYER_STATE_PAUSED:
821                                         LOGD("player is already going to paused state, there is nothing to do.\n");
822                                         break;
823
824                                 case MM_PLAYER_STATE_NONE:
825                                 case MM_PLAYER_STATE_NULL:
826                                 case MM_PLAYER_STATE_READY:
827                                 default:
828                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
829                                         break;
830                                 }
831                         }
832                         break;
833
834                 case MM_PLAYER_STATE_PLAYING:
835                         {
836                                 switch (pending_state) {
837                                 case MM_PLAYER_STATE_NONE:
838                                         {
839                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
840                                                         __gst_resume(player, TRUE);
841                                         }
842                                         break;
843
844                                 case MM_PLAYER_STATE_PAUSED:
845                                         /* NOTE: It should be worked as asynchronously.
846                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
847                                          */
848                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
849                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
850                                                  * The current state should be changed to paused purposely to prevent state conflict.
851                                                  */
852                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
853                                         }
854                                         __gst_resume(player, TRUE);
855                                         break;
856
857                                 case MM_PLAYER_STATE_PLAYING:
858                                         LOGD("player is already going to playing state, there is nothing to do.\n");
859                                         break;
860
861                                 case MM_PLAYER_STATE_NULL:
862                                 case MM_PLAYER_STATE_READY:
863                                 default:
864                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
865                                         break;
866                                 }
867                         }
868                         break;
869
870                 case MM_PLAYER_STATE_NULL:
871                 case MM_PLAYER_STATE_READY:
872                 case MM_PLAYER_STATE_NONE:
873                 default:
874                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
875                         break;
876                 }
877         } else {
878                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
879                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
880                  */
881                 switch (pending_state) {
882                 case MM_PLAYER_STATE_NONE:
883                         {
884                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
885                                         /* rtsp streaming pause makes rtsp server stop sending data. */
886                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
887                                                 LOGD("set pause state during buffering\n");
888                                                 __gst_pause(player, TRUE);
889                                         }
890                                 }
891                         }
892                         break;
893
894                 case MM_PLAYER_STATE_PLAYING:
895                         /* rtsp streaming pause makes rtsp server stop sending data. */
896                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
897                                 __gst_pause(player, TRUE);
898                         break;
899
900                 case MM_PLAYER_STATE_PAUSED:
901                         break;
902
903                 case MM_PLAYER_STATE_NULL:
904                 case MM_PLAYER_STATE_READY:
905                 default:
906                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
907                         break;
908                 }
909         }
910
911 exit:
912         return ret;
913 }
914
915 static void
916 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
917 {
918         MMPlayerGstElement *textbin;
919         MMPLAYER_FENTER();
920
921         MMPLAYER_RETURN_IF_FAIL(player &&
922                                         player->pipeline &&
923                                         player->pipeline->textbin);
924
925         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
926
927         textbin = player->pipeline->textbin;
928
929         if (is_drop) {
930                 LOGD("Drop subtitle text after getting EOS\n");
931
932                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
933                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
934
935                 player->is_subtitle_force_drop = TRUE;
936         } else {
937                 if (player->is_subtitle_force_drop == TRUE) {
938                         LOGD("Enable subtitle data path without drop\n");
939
940                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
941                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
942
943                         LOGD("non-connected with external display");
944
945                         player->is_subtitle_force_drop = FALSE;
946                 }
947         }
948 }
949
950 static VariantData *
951 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
952 {
953         VariantData *var_info = NULL;
954         g_return_val_if_fail(self != NULL, NULL);
955
956         var_info = g_new0(VariantData, 1);
957         if (!var_info) return NULL;
958         var_info->bandwidth = self->bandwidth;
959         var_info->width = self->width;
960         var_info->height = self->height;
961         return var_info;
962 }
963
964 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
965 {
966         mm_player_t* player = (mm_player_t*)hplayer;
967         GstMessage *msg = NULL;
968         GQueue *queue = NULL;
969
970         MMPLAYER_FENTER();
971         MMPLAYER_RETURN_IF_FAIL(player);
972
973         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
974
975         /* destroy the gst bus msg thread */
976         if (player->bus_msg_thread) {
977                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
978                 player->bus_msg_thread_exit = TRUE;
979                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
980                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
981
982                 LOGD("gst bus msg thread exit.");
983                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
984                 player->bus_msg_thread = NULL;
985
986                 g_mutex_clear(&player->bus_msg_thread_mutex);
987                 g_cond_clear(&player->bus_msg_thread_cond);
988         }
989
990         g_mutex_lock(&player->bus_msg_q_lock);
991         queue = player->bus_msg_q;
992         while (!g_queue_is_empty(queue)) {
993                 msg = (GstMessage *)g_queue_pop_head(queue);
994                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
995                 gst_message_unref(msg);
996         }
997         g_mutex_unlock(&player->bus_msg_q_lock);
998
999         MMPLAYER_FLEAVE();
1000 }
1001
1002 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1003 {
1004         mm_player_t *player = (mm_player_t *) data;
1005
1006         g_return_val_if_fail(player, FALSE);
1007         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1008
1009         gst_message_ref(msg);
1010
1011         g_mutex_lock(&player->bus_msg_q_lock);
1012         g_queue_push_tail(player->bus_msg_q, msg);
1013         g_mutex_unlock(&player->bus_msg_q_lock);
1014
1015         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1017         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1018         return TRUE;
1019 }
1020
1021 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1022 {
1023         mm_player_t *player = (mm_player_t*)(data);
1024         GstMessage *msg = NULL;
1025         GstBus *bus = NULL;
1026
1027         MMPLAYER_FENTER();
1028         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1029                                                 player->pipeline &&
1030                                                 player->pipeline->mainbin &&
1031                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1032                                                 NULL);
1033
1034         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1035         if (!bus) {
1036                 LOGE("cannot get BUS from the pipeline");
1037                 return NULL;
1038         }
1039
1040         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1041
1042         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1043         while (!player->bus_msg_thread_exit) {
1044                 g_mutex_lock(&player->bus_msg_q_lock);
1045                 msg = g_queue_pop_head(player->bus_msg_q);
1046                 g_mutex_unlock(&player->bus_msg_q_lock);
1047                 if (msg == NULL) {
1048                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1049                         continue;
1050                 }
1051                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1052                 /* handle the gst msg */
1053                 __mmplayer_gst_callback(msg, player);
1054                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1055                 gst_message_unref(msg);
1056         }
1057
1058         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1059         gst_object_unref(GST_OBJECT(bus));
1060
1061         MMPLAYER_FLEAVE();
1062         return NULL;
1063 }
1064
1065 static void
1066 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1067 {
1068         mm_player_t* player = (mm_player_t*)(data);
1069         static gboolean async_done = FALSE;
1070
1071         MMPLAYER_RETURN_IF_FAIL(player);
1072         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1073
1074         switch (GST_MESSAGE_TYPE(msg)) {
1075         case GST_MESSAGE_UNKNOWN:
1076                 LOGD("unknown message received\n");
1077                 break;
1078
1079         case GST_MESSAGE_EOS:
1080                 {
1081                         MMHandleType attrs = 0;
1082                         gint count = 0;
1083
1084                         LOGD("GST_MESSAGE_EOS received\n");
1085
1086                         /* NOTE : EOS event is comming multiple time. watch out it */
1087                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1088                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1089                                 LOGD("EOS received on non-playing state. ignoring it\n");
1090                                 break;
1091                         }
1092
1093                         if (player->pipeline) {
1094                                 if (player->pipeline->textbin)
1095                                         __mmplayer_drop_subtitle(player, TRUE);
1096
1097                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1098                                         GstPad *pad = NULL;
1099
1100                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1101
1102                                         LOGD("release audio callback\n");
1103
1104                                         /* release audio callback */
1105                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1106                                         player->audio_cb_probe_id = 0;
1107                                         /* audio callback should be free because it can be called even though probe remove.*/
1108                                         player->audio_stream_cb = NULL;
1109                                         player->audio_stream_cb_user_param = NULL;
1110
1111                                 }
1112                         }
1113                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1114                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1115
1116                         /* rewind if repeat count is greater then zero */
1117                         /* get play count */
1118                         attrs = MMPLAYER_GET_ATTRS(player);
1119
1120                         if (attrs) {
1121                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1122
1123                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1124
1125                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1126                                         if (player->playback_rate < 0.0) {
1127                                                 player->resumed_by_rewind = TRUE;
1128                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1129                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1130                                         }
1131
1132                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1133
1134                                         /* initialize */
1135                                         player->sent_bos = FALSE;
1136
1137                                         /* not posting eos when repeating */
1138                                         break;
1139                                 }
1140                         }
1141
1142                         if (player->pipeline)
1143                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1144
1145                         /* post eos message to application */
1146                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1147
1148                         /* reset last position */
1149                         player->last_position = 0;
1150                 }
1151                 break;
1152
1153         case GST_MESSAGE_ERROR:
1154                 {
1155                         GError *error = NULL;
1156                         gchar* debug = NULL;
1157
1158                         /* generating debug info before returning error */
1159                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1160
1161                         /* get error code */
1162                         gst_message_parse_error(msg, &error, &debug);
1163
1164                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1165                                 /* Note : the streaming error from the streaming source is handled
1166                                  *   using __mmplayer_handle_streaming_error.
1167                                  */
1168                                 __mmplayer_handle_streaming_error(player, msg);
1169
1170                                 /* dump state of all element */
1171                                 __mmplayer_dump_pipeline_state(player);
1172                         } else {
1173                                 /* traslate gst error code to msl error code. then post it
1174                                  * to application if needed
1175                                  */
1176                                 __mmplayer_handle_gst_error(player, msg, error);
1177
1178                                 if (debug)
1179                                         LOGE("error debug : %s", debug);
1180                         }
1181
1182                         if (MMPLAYER_IS_HTTP_PD(player))
1183                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1184
1185                         MMPLAYER_FREEIF(debug);
1186                         g_error_free(error);
1187                 }
1188                 break;
1189
1190         case GST_MESSAGE_WARNING:
1191                 {
1192                         char* debug = NULL;
1193                         GError* error = NULL;
1194
1195                         gst_message_parse_warning(msg, &error, &debug);
1196
1197                         LOGD("warning : %s\n", error->message);
1198                         LOGD("debug : %s\n", debug);
1199
1200                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1201
1202                         MMPLAYER_FREEIF(debug);
1203                         g_error_free(error);
1204                 }
1205                 break;
1206
1207         case GST_MESSAGE_TAG:
1208                 {
1209                         LOGD("GST_MESSAGE_TAG\n");
1210                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1211                                 LOGW("failed to extract tags from gstmessage\n");
1212                 }
1213                 break;
1214
1215         case GST_MESSAGE_BUFFERING:
1216                 {
1217                         MMMessageParamType msg_param = {0, };
1218                         int bRet = MM_ERROR_NONE;
1219
1220                         if (!(player->pipeline && player->pipeline->mainbin)) {
1221                                 LOGE("player pipeline handle is null");
1222                                 break;
1223                         }
1224
1225                         if (!MMPLAYER_IS_STREAMING(player))
1226                                 break;
1227
1228                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1229                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1230                                         /* skip the playback control by buffering msg while user request is handled. */
1231                                         gint per = 0;
1232
1233                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1234
1235                                         gst_message_parse_buffering(msg, &per);
1236                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1237
1238                                         msg_param.connection.buffering = per;
1239                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1240                                         break;
1241                                 }
1242                         } else {
1243                                 MMPLAYER_CMD_LOCK(player);
1244                         }
1245
1246                         /* ignore the prev buffering message */
1247                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1248                                 && (player->streamer->is_buffering_done == TRUE)) {
1249                                 gint buffer_percent = 0;
1250
1251                                 gst_message_parse_buffering(msg, &buffer_percent);
1252
1253                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1254                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1255                                         player->streamer->is_buffering_done = FALSE;
1256                                 }
1257                                 MMPLAYER_CMD_UNLOCK(player);
1258                                 break;
1259                         }
1260
1261                         __mmplayer_update_buffer_setting(player, msg);
1262
1263                         bRet = __mmplayer_handle_buffering_message(player);
1264
1265                         if (bRet == MM_ERROR_NONE) {
1266                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1267                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1268
1269                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1270                                         player->pending_resume &&
1271                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1272
1273                                         player->is_external_subtitle_added_now = FALSE;
1274                                         player->pending_resume = FALSE;
1275                                         _mmplayer_resume((MMHandleType)player);
1276                                 }
1277
1278                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1279                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1280
1281                                         if (player->doing_seek) {
1282                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1283                                                         player->doing_seek = FALSE;
1284                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1285                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1286                                                         async_done = TRUE;
1287                                                 }
1288                                         }
1289                                 }
1290                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1291                                 if (!player->streamer) {
1292                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1293                                         MMPLAYER_CMD_UNLOCK(player);
1294                                         break;
1295                                 }
1296
1297                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1298
1299                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1300                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1301
1302                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1303                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1304                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1305                                         } else {
1306                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1307                                         }
1308                                 } else {
1309                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1310                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1311                                 }
1312                         }
1313                         MMPLAYER_CMD_UNLOCK(player);
1314                 }
1315                 break;
1316
1317         case GST_MESSAGE_STATE_CHANGED:
1318                 {
1319                         MMPlayerGstElement *mainbin;
1320                         const GValue *voldstate, *vnewstate, *vpending;
1321                         GstState oldstate = GST_STATE_NULL;
1322                         GstState newstate = GST_STATE_NULL;
1323                         GstState pending = GST_STATE_NULL;
1324
1325                         if (!(player->pipeline && player->pipeline->mainbin)) {
1326                                 LOGE("player pipeline handle is null");
1327                                 break;
1328                         }
1329
1330                         mainbin = player->pipeline->mainbin;
1331
1332                         /* we only handle messages from pipeline */
1333                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1334                                 break;
1335
1336                         /* get state info from msg */
1337                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1338                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1339                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1340
1341                         if (!voldstate || !vnewstate) {
1342                                 LOGE("received msg has wrong format.");
1343                                 break;
1344                         }
1345
1346                         oldstate = (GstState)voldstate->data[0].v_int;
1347                         newstate = (GstState)vnewstate->data[0].v_int;
1348                         if (vpending)
1349                                 pending = (GstState)vpending->data[0].v_int;
1350
1351                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1352                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1353                                 gst_element_state_get_name((GstState)oldstate),
1354                                 gst_element_state_get_name((GstState)newstate),
1355                                 gst_element_state_get_name((GstState)pending));
1356
1357                         if (newstate == GST_STATE_PLAYING) {
1358                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1359
1360                                         int retVal = MM_ERROR_NONE;
1361                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1362
1363                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1364
1365                                         if (MM_ERROR_NONE != retVal)
1366                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1367
1368                                         player->pending_seek.is_pending = FALSE;
1369                                 }
1370                         }
1371
1372                         if (oldstate == newstate) {
1373                                 LOGD("pipeline reports state transition to old state");
1374                                 break;
1375                         }
1376
1377                         switch (newstate) {
1378                         case GST_STATE_VOID_PENDING:
1379                                 break;
1380
1381                         case GST_STATE_NULL:
1382                                 break;
1383
1384                         case GST_STATE_READY:
1385                                 break;
1386
1387                         case GST_STATE_PAUSED:
1388                                 {
1389                                         gboolean prepare_async = FALSE;
1390                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1391
1392                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1393                                                 __mmplayer_configure_audio_callback(player);
1394
1395                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1396                                                 // managed prepare async case
1397                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1398                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1399                                         }
1400
1401                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1402                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1403
1404                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1405                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1406                                                                 player->total_maximum_bitrate, player->total_bitrate);
1407
1408                                                 if (player->pending_seek.is_pending) {
1409                                                         LOGW("trying to do pending seek");
1410                                                         MMPLAYER_CMD_LOCK(player);
1411                                                         __gst_pending_seek(player);
1412                                                         MMPLAYER_CMD_UNLOCK(player);
1413                                                 }
1414                                         }
1415                                 }
1416                                 break;
1417
1418                         case GST_STATE_PLAYING:
1419                                 {
1420                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1421
1422                                         if (MMPLAYER_IS_STREAMING(player)) {
1423                                                 // managed prepare async case when buffering is completed
1424                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1425                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1426                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1427                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1428
1429                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1430
1431                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1432                                                         if (player->streamer->buffering_percent < 100) {
1433
1434                                                                 MMMessageParamType msg_param = {0, };
1435                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1436
1437                                                                 msg_param.connection.buffering = 100;
1438                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1439                                                         }
1440                                                 }
1441                                         }
1442
1443                                         if (player->gapless.stream_changed) {
1444                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1445                                                 player->gapless.stream_changed = FALSE;
1446                                         }
1447
1448                                         if (player->doing_seek && async_done) {
1449                                                 player->doing_seek = FALSE;
1450                                                 async_done = FALSE;
1451                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1452                                         }
1453                                 }
1454                                 break;
1455
1456                         default:
1457                                 break;
1458                         }
1459                 }
1460                 break;
1461
1462         case GST_MESSAGE_CLOCK_LOST:
1463                         {
1464                                 GstClock *clock = NULL;
1465                                 gboolean need_new_clock = FALSE;
1466
1467                                 gst_message_parse_clock_lost(msg, &clock);
1468                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1469
1470                                 if (!player->videodec_linked)
1471                                         need_new_clock = TRUE;
1472                                 else if (!player->ini.use_system_clock)
1473                                         need_new_clock = TRUE;
1474
1475                                 if (need_new_clock) {
1476                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1477                                         __gst_pause(player, FALSE);
1478                                         __gst_resume(player, FALSE);
1479                                 }
1480                         }
1481                         break;
1482
1483         case GST_MESSAGE_NEW_CLOCK:
1484                         {
1485                                 GstClock *clock = NULL;
1486                                 gst_message_parse_new_clock(msg, &clock);
1487                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1488                         }
1489                         break;
1490
1491         case GST_MESSAGE_ELEMENT:
1492                         {
1493                                 const gchar *structure_name;
1494                                 gint count = 0, idx = 0;
1495                                 MMHandleType attrs = 0;
1496
1497                                 attrs = MMPLAYER_GET_ATTRS(player);
1498                                 if (!attrs) {
1499                                         LOGE("cannot get content attribute");
1500                                         break;
1501                                 }
1502
1503                                 if (gst_message_get_structure(msg) == NULL)
1504                                         break;
1505
1506                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1507                                 if (!structure_name)
1508                                         break;
1509
1510                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1511
1512                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1513                                         const GValue *var_info = NULL;
1514
1515                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1516                                         if (var_info != NULL) {
1517                                                 if (player->adaptive_info.var_list)
1518                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1519
1520                                                 /* share addr or copy the list */
1521                                                 player->adaptive_info.var_list =
1522                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1523
1524                                                 count = g_list_length(player->adaptive_info.var_list);
1525                                                 if (count > 0) {
1526                                                         VariantData *temp = NULL;
1527
1528                                                         /* print out for debug */
1529                                                         LOGD("num of variant_info %d", count);
1530                                                         for (idx = 0; idx < count; idx++) {
1531                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1532                                                                 if (temp)
1533                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1534                                                         }
1535                                                 }
1536                                         }
1537                                 }
1538
1539                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1540                                         gint num_buffers = 0;
1541                                         gint extra_num_buffers = 0;
1542
1543                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1544                                                 player->video_num_buffers = num_buffers;
1545                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1546                                         }
1547
1548                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1549                                                 player->video_extra_num_buffers = extra_num_buffers;
1550                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1551                                         }
1552                                         break;
1553                                 }
1554
1555                                 if (!strcmp(structure_name, "Language_list")) {
1556                                         const GValue *lang_list = NULL;
1557                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1558                                         if (lang_list != NULL) {
1559                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1560                                                 if (count > 1)
1561                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1562                                         }
1563                                 }
1564
1565                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1566                                         const GValue *lang_list = NULL;
1567                                         MMPlayerLangStruct *temp = NULL;
1568
1569                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1570                                         if (lang_list != NULL) {
1571                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1572                                                 if (count) {
1573                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1574                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1575                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1576                                                         if (mmf_attrs_commit(attrs))
1577                                                                 LOGE("failed to commit.\n");
1578                                                         LOGD("Total subtitle tracks = %d \n", count);
1579
1580                                                         while (count) {
1581                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1582                                                                 if (temp)
1583                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1584                                                                                                 temp->language_key, temp->language_code);
1585                                                                 count--;
1586                                                         }
1587                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1588                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1589                                                 }
1590                                         }
1591                                 }
1592
1593                                 /* custom message */
1594                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1595                                         MMMessageParamType msg_param = {0,};
1596                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1597                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1598                                 }
1599
1600                                 /* custom message for RTSP attribute :
1601                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1602                                     sdp which has contents info is received when rtsp connection is opened.
1603                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1604                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1605
1606                                         gchar *audio_codec = NULL;
1607                                         gchar *video_codec = NULL;
1608                                         gchar *video_frame_size = NULL;
1609
1610                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1611                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1612                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1613                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1614
1615                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1616                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1617                                         if (audio_codec)
1618                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1619
1620                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1621                                         LOGD("rtsp_video_codec : %s", video_codec);
1622                                         if (video_codec)
1623                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1624
1625                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1626                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1627                                         if (video_frame_size) {
1628
1629                                                 char *seperator = strchr(video_frame_size, '-');
1630                                                 if (seperator) {
1631
1632                                                         char video_width[10] = {0,};
1633                                                         int frame_size_len = strlen(video_frame_size);
1634                                                         int separtor_len = strlen(seperator);
1635
1636                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1637                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1638
1639                                                         seperator++;
1640                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1641                                                 }
1642                                         }
1643
1644                                         if (mmf_attrs_commit(attrs))
1645                                                 LOGE("failed to commit.\n");
1646                                 }
1647                         }
1648                         break;
1649
1650         case GST_MESSAGE_DURATION_CHANGED:
1651                 {
1652                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1653                         if (!__mmplayer_gst_handle_duration(player, msg))
1654                                 LOGW("failed to update duration");
1655                 }
1656
1657                 break;
1658
1659         case GST_MESSAGE_ASYNC_START:
1660                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1661                 break;
1662
1663         case GST_MESSAGE_ASYNC_DONE:
1664                 {
1665                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1666
1667                         /* we only handle messages from pipeline */
1668                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1669                                 break;
1670
1671                         if (player->doing_seek) {
1672                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1673                                         player->doing_seek = FALSE;
1674                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1675                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1676                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1677                                                 (player->streamer) &&
1678                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1679                                                 (player->streamer->is_buffering == FALSE)) {
1680                                                 GstQuery *query = NULL;
1681                                                 gboolean busy = FALSE;
1682                                                 gint percent = 0;
1683
1684                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1685                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1686                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1687                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1688                                                         gst_query_unref(query);
1689
1690                                                         LOGD("buffered percent(%s): %d\n",
1691                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1692                                                 }
1693
1694                                                 if (percent >= 100) {
1695                                                         player->streamer->is_buffering = FALSE;
1696                                                         __mmplayer_handle_buffering_message(player);
1697                                                 }
1698                                         }
1699
1700                                         async_done = TRUE;
1701                                 }
1702                         }
1703                 }
1704                 break;
1705
1706         #if 0 /* delete unnecessary logs */
1707         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1708         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1709         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1710         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1711         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1712         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1713         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1714         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1715         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1716         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1717         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1718         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1719         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1720         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1721         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1722         #endif
1723
1724         default:
1725                 break;
1726         }
1727
1728         /* should not call 'gst_message_unref(msg)' */
1729         return;
1730 }
1731
1732 static gboolean
1733 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1734 {
1735         gint64 bytes = 0;
1736
1737         MMPLAYER_FENTER();
1738
1739         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1740         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1741
1742         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1743                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1744                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1745
1746                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1747                         LOGD("data total size of http content: %lld", bytes);
1748                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1749                 }
1750         } else
1751                 /* handling audio clip which has vbr. means duration is keep changing */
1752                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1753
1754         MMPLAYER_FLEAVE();
1755
1756         return TRUE;
1757 }
1758
1759 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1760                 mm_player_spherical_metadata_t *metadata) {
1761         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1762         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1763         gst_tag_list_get_string(tags, "stitching_software",
1764                         &metadata->stitching_software);
1765         gst_tag_list_get_string(tags, "projection_type",
1766                         &metadata->projection_type_string);
1767         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1768         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1769         gst_tag_list_get_int(tags, "init_view_heading",
1770                         &metadata->init_view_heading);
1771         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1772         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1773         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1774         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1775                         &metadata->full_pano_width_pixels);
1776         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1777                         &metadata->full_pano_height_pixels);
1778         gst_tag_list_get_int(tags, "cropped_area_image_width",
1779                         &metadata->cropped_area_image_width);
1780         gst_tag_list_get_int(tags, "cropped_area_image_height",
1781                         &metadata->cropped_area_image_height);
1782         gst_tag_list_get_int(tags, "cropped_area_left",
1783                         &metadata->cropped_area_left);
1784         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1785         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1786         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1787         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1788 }
1789
1790 static gboolean
1791 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1792 {
1793
1794 /* macro for better code readability */
1795 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1796 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1797         if (string != NULL) { \
1798                 SECURE_LOGD("update tag string : %s\n", string); \
1799                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1800                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1801                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1802                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1803                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1804                         g_free(new_string); \
1805                         new_string = NULL; \
1806                 } else { \
1807                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1808                 } \
1809                 g_free(string); \
1810                 string = NULL; \
1811         } \
1812 }
1813
1814 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1815 do {    \
1816         GstSample *sample = NULL;\
1817         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1818                 GstMapInfo info = GST_MAP_INFO_INIT;\
1819                 buffer = gst_sample_get_buffer(sample);\
1820                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1821                         LOGD("failed to get image data from tag");\
1822                         gst_sample_unref(sample);\
1823                         return FALSE;\
1824                 } \
1825                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1826                 MMPLAYER_FREEIF(player->album_art);\
1827                 player->album_art = (gchar *)g_malloc(info.size);\
1828                 if (player->album_art) {\
1829                         memcpy(player->album_art, info.data, info.size);\
1830                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1831                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1832                                 msg_param.data = (void *)player->album_art;\
1833                                 msg_param.size = info.size;\
1834                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1835                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1836                         } \
1837                 } \
1838                 gst_buffer_unmap(buffer, &info);\
1839                 gst_sample_unref(sample);\
1840         }       \
1841 } while (0)
1842
1843 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1844 do {    \
1845         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1846                 if (v_uint) { \
1847                         int i = 0; \
1848                         gchar *tag_list_str = NULL; \
1849                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1850                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1851                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1852                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1853                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1854                         else \
1855                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1856                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1857                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1858                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1859                                 player->bitrate[track_type] = v_uint; \
1860                                 player->total_bitrate = 0; \
1861                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1862                                         player->total_bitrate += player->bitrate[i]; \
1863                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1864                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1865                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1866                                 player->maximum_bitrate[track_type] = v_uint; \
1867                                 player->total_maximum_bitrate = 0; \
1868                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1869                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1870                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1871                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1872                         } else { \
1873                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1874                         } \
1875                         v_uint = 0;\
1876                         g_free(tag_list_str); \
1877                 } \
1878         } \
1879 } while (0)
1880
1881 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1882 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1883         if (date != NULL) {\
1884                 string = g_strdup_printf("%d", g_date_get_year(date));\
1885                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1886                 SECURE_LOGD("metainfo year : %s\n", string);\
1887                 MMPLAYER_FREEIF(string);\
1888                 g_date_free(date);\
1889         } \
1890 }
1891
1892 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1893 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1894         if (datetime != NULL) {\
1895                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1896                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1897                 SECURE_LOGD("metainfo year : %s\n", string);\
1898                 MMPLAYER_FREEIF(string);\
1899                 gst_date_time_unref(datetime);\
1900         } \
1901 }
1902
1903 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1904 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1905         if (v_uint64) {\
1906                 /* FIXIT : don't know how to store date */\
1907                 g_assert(1);\
1908                 v_uint64 = 0;\
1909         } \
1910 }
1911
1912 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1913 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1914         if (v_double) {\
1915                 /* FIXIT : don't know how to store date */\
1916                 g_assert(1);\
1917                 v_double = 0;\
1918         } \
1919 }
1920
1921         /* function start */
1922         GstTagList* tag_list = NULL;
1923
1924         MMHandleType attrs = 0;
1925
1926         char *string = NULL;
1927         guint v_uint = 0;
1928         GDate *date = NULL;
1929         GstDateTime *datetime = NULL;
1930         /* album cover */
1931         GstBuffer *buffer = NULL;
1932         gint index = 0;
1933         MMMessageParamType msg_param = {0, };
1934
1935         /* currently not used. but those are needed for above macro */
1936         //guint64 v_uint64 = 0;
1937         //gdouble v_double = 0;
1938
1939         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1940
1941         attrs = MMPLAYER_GET_ATTRS(player);
1942
1943         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1944
1945         /* get tag list from gst message */
1946         gst_message_parse_tag(msg, &tag_list);
1947
1948         /* store tags to player attributes */
1949         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1950         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1951         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1952         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1953         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1954         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1955         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1956         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1957         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1958         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1959         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1960         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1961         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1962         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1963         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1964         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1965         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1966         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1967         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1968         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1969         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1970         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1971         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1972         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1973         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1974         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1975         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1976         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1977         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1978         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1979         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1980         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1981         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1982         MMPLAYER_UPDATE_TAG_LOCK(player);
1983         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1984         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1985         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1986         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1987         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1988         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1989         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1990         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1991         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1992         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1993         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1994         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1995         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1996         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1997         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1998
1999         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2000                 if (player->video360_metadata.is_spherical == -1) {
2001                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2002                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2003                                         player->video360_metadata.is_spherical);
2004                         if (player->video360_metadata.is_spherical == 1) {
2005                                 LOGD("This is spherical content for 360 playback.");
2006                                 player->is_content_spherical = TRUE;
2007                         } else {
2008                                 LOGD("This is not spherical content");
2009                                 player->is_content_spherical = FALSE;
2010                         }
2011
2012                         if (player->video360_metadata.projection_type_string) {
2013                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2014                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2015                                 } else {
2016                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2017                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2018                                 }
2019                         }
2020
2021                         if (player->video360_metadata.stereo_mode_string) {
2022                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2023                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2024                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2025                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2026                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2027                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2028                                 } else {
2029                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2030                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2031                                 }
2032                         }
2033                 }
2034         }
2035
2036         if (mmf_attrs_commit(attrs))
2037                 LOGE("failed to commit.\n");
2038
2039         gst_tag_list_free(tag_list);
2040
2041         return TRUE;
2042 }
2043
2044 static void
2045 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2046 {
2047         mm_player_t* player = (mm_player_t*) data;
2048
2049         MMPLAYER_FENTER();
2050
2051         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2052           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2053           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2054           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2055
2056           * [1] audio and video will be dumped with filesink.
2057           * [2] autoplugging is done by just using pad caps.
2058           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2059           * and the video will be dumped via filesink.
2060           */
2061         if (player->num_dynamic_pad == 0) {
2062                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2063
2064                 if (!__mmplayer_gst_remove_fakesink(player,
2065                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2066                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2067                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2068                          * source element are not same. To overcome this situation, this function will called
2069                          * several places and several times. Therefore, this is not an error case.
2070                          */
2071                         return;
2072         }
2073
2074         /* create dot before error-return. for debugging */
2075         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2076
2077         player->no_more_pad = TRUE;
2078
2079         MMPLAYER_FLEAVE();
2080 }
2081
2082 static gboolean
2083 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2084 {
2085         GstElement* parent = NULL;
2086
2087         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2088
2089         /* if we have no fakesink. this meas we are using decodebin which doesn'
2090         t need to add extra fakesink */
2091         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2092
2093         /* lock */
2094         MMPLAYER_FSINK_LOCK(player);
2095
2096         if (!fakesink->gst)
2097                 goto ERROR;
2098
2099         /* get parent of fakesink */
2100         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2101         if (!parent) {
2102                 LOGD("fakesink already removed\n");
2103                 goto ERROR;
2104         }
2105
2106         gst_element_set_locked_state(fakesink->gst, TRUE);
2107
2108         /* setting the state to NULL never returns async
2109          * so no need to wait for completion of state transiton
2110          */
2111         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2112                 LOGE("fakesink state change failure!\n");
2113                 /* FIXIT : should I return here? or try to proceed to next? */
2114                 /* return FALSE; */
2115
2116         /* remove fakesink from it's parent */
2117         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2118                 LOGE("failed to remove fakesink\n");
2119
2120                 gst_object_unref(parent);
2121
2122                 goto ERROR;
2123         }
2124
2125         gst_object_unref(parent);
2126
2127         LOGD("state-holder removed\n");
2128
2129         gst_element_set_locked_state(fakesink->gst, FALSE);
2130
2131         MMPLAYER_FSINK_UNLOCK(player);
2132         return TRUE;
2133
2134 ERROR:
2135         if (fakesink->gst)
2136                 gst_element_set_locked_state(fakesink->gst, FALSE);
2137
2138         MMPLAYER_FSINK_UNLOCK(player);
2139         return FALSE;
2140 }
2141
2142
2143 static void
2144 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2145 {
2146         GstPad *sinkpad = NULL;
2147         GstCaps* caps = NULL;
2148         GstElement* new_element = NULL;
2149         GstStructure* str = NULL;
2150         const gchar* name = NULL;
2151
2152         mm_player_t* player = (mm_player_t*) data;
2153
2154         MMPLAYER_FENTER();
2155
2156         MMPLAYER_RETURN_IF_FAIL(element && pad);
2157         MMPLAYER_RETURN_IF_FAIL(player &&
2158                                         player->pipeline &&
2159                                         player->pipeline->mainbin);
2160
2161
2162         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2163          * num_dynamic_pad will decreased after creating a sinkbin.
2164          */
2165         player->num_dynamic_pad++;
2166         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2167
2168         caps = gst_pad_query_caps(pad, NULL);
2169
2170         MMPLAYER_CHECK_NULL(caps);
2171
2172         /* clear  previous result*/
2173         player->have_dynamic_pad = FALSE;
2174
2175         str = gst_caps_get_structure(caps, 0);
2176
2177         if (!str) {
2178                 LOGE("cannot get structure from caps.\n");
2179                 goto ERROR;
2180         }
2181
2182         name = gst_structure_get_name(str);
2183         if (!name) {
2184                 LOGE("cannot get mimetype from structure.\n");
2185                 goto ERROR;
2186         }
2187
2188         if (strstr(name, "video")) {
2189                 gint stype = 0;
2190                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2191
2192                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2193                         if (player->v_stream_caps) {
2194                                 gst_caps_unref(player->v_stream_caps);
2195                                 player->v_stream_caps = NULL;
2196                         }
2197
2198                         new_element = gst_element_factory_make("fakesink", NULL);
2199                         player->num_dynamic_pad--;
2200                         goto NEW_ELEMENT;
2201                 }
2202         }
2203
2204         /* clear  previous result*/
2205         player->have_dynamic_pad = FALSE;
2206
2207         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2208                 LOGE("failed to autoplug for caps");
2209                 goto ERROR;
2210         }
2211
2212         /* check if there's dynamic pad*/
2213         if (player->have_dynamic_pad) {
2214                 LOGE("using pad caps assums there's no dynamic pad !\n");
2215                 goto ERROR;
2216         }
2217
2218         gst_caps_unref(caps);
2219         caps = NULL;
2220
2221 NEW_ELEMENT:
2222
2223         /* excute new_element if created*/
2224         if (new_element) {
2225                 LOGD("adding new element to pipeline\n");
2226
2227                 /* set state to READY before add to bin */
2228                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2229
2230                 /* add new element to the pipeline */
2231                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2232                         LOGE("failed to add autoplug element to bin\n");
2233                         goto ERROR;
2234                 }
2235
2236                 /* get pad from element */
2237                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2238                 if (!sinkpad) {
2239                         LOGE("failed to get sinkpad from autoplug element\n");
2240                         goto ERROR;
2241                 }
2242
2243                 /* link it */
2244                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2245                         LOGE("failed to link autoplug element\n");
2246                         goto ERROR;
2247                 }
2248
2249                 gst_object_unref(sinkpad);
2250                 sinkpad = NULL;
2251
2252                 /* run. setting PLAYING here since streamming source is live source */
2253                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2254         }
2255
2256         if (caps)
2257                 gst_caps_unref(caps);
2258
2259         MMPLAYER_FLEAVE();
2260
2261         return;
2262
2263 STATE_CHANGE_FAILED:
2264 ERROR:
2265         /* FIXIT : take care if new_element has already added to pipeline */
2266         if (new_element)
2267                 gst_object_unref(GST_OBJECT(new_element));
2268
2269         if (sinkpad)
2270                 gst_object_unref(GST_OBJECT(sinkpad));
2271
2272         if (caps)
2273                 gst_caps_unref(caps);
2274
2275         /* FIXIT : how to inform this error to MSL ????? */
2276         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2277          * then post an error to application
2278          */
2279 }
2280
2281 static GstPadProbeReturn
2282 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2283 {
2284         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2285         return GST_PAD_PROBE_OK;
2286 }
2287
2288 static GstPadProbeReturn
2289 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2290 {
2291         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2292         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2293         mm_player_t* player = (mm_player_t*)data;
2294         GstCaps* caps = NULL;
2295         GstStructure* str = NULL;
2296         const gchar* name = NULL;
2297         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2298
2299
2300         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2301                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2302                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2303                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2304                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2305                         return ret;
2306         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2307                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2308                         return ret;
2309         }
2310
2311         caps = gst_pad_query_caps(pad, NULL);
2312         if (!caps) {
2313                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2314                 return ret;
2315         }
2316
2317         str = gst_caps_get_structure(caps, 0);
2318         if (!str) {
2319                 LOGE("failed to get structure from caps");
2320                 goto ERROR;
2321         }
2322
2323         name = gst_structure_get_name(str);
2324         if (!name) {
2325                 LOGE("failed to get name from str");
2326                 goto ERROR;
2327         }
2328
2329         if (strstr(name, "audio")) {
2330                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2331         } else if (strstr(name, "video")) {
2332                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2333         } else {
2334                 /* text track is not supportable */
2335                 LOGE("invalid name %s", name);
2336                 goto ERROR;
2337         }
2338
2339         switch (GST_EVENT_TYPE(event)) {
2340         case GST_EVENT_EOS:
2341                 {
2342                         /* in case of gapless, drop eos event not to send it to sink */
2343                         if (player->gapless.reconfigure && !player->msg_posted) {
2344                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2345                                 ret = GST_PAD_PROBE_DROP;
2346                         }
2347                         break;
2348                 }
2349         case GST_EVENT_STREAM_START:
2350                 {
2351                         gint64 stop_running_time = 0;
2352                         gint64 position_running_time = 0;
2353                         gint64 position = 0;
2354                         gint idx = 0;
2355
2356                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2357                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2358                                         !(player->selector[idx].event_probe_id)) {
2359                                         /* LOGW("[%d] skip", idx); */
2360                                         continue;
2361                                 }
2362
2363                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2364                                         stop_running_time =
2365                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2366                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2367                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2368                                         stop_running_time =
2369                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2370                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2371                                 } else {
2372                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2373                                         stop_running_time =
2374                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2375                                                                 GST_FORMAT_TIME, player->duration);
2376                                 }
2377
2378                                 position_running_time =
2379                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2380                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2381
2382                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2383                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2384                                         idx,
2385                                         GST_TIME_ARGS(stop_running_time),
2386                                         GST_TIME_ARGS(position_running_time),
2387                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2388                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2389
2390                                 position_running_time = MAX(position_running_time, stop_running_time);
2391                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2392                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2393                                 position_running_time = MAX(0, position_running_time);
2394                                 position = MAX(position, position_running_time);
2395                         }
2396
2397                         if (position != 0) {
2398                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2399                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2400                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2401
2402                                 player->gapless.start_time[stream_type] += position;
2403                         }
2404                         break;
2405                 }
2406         case GST_EVENT_FLUSH_STOP:
2407                 {
2408                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2409                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2410                         player->gapless.start_time[stream_type] = 0;
2411                         break;
2412                 }
2413         case GST_EVENT_SEGMENT:
2414                 {
2415                         GstSegment segment;
2416                         GstEvent *tmpev;
2417
2418                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2419                         gst_event_copy_segment(event, &segment);
2420
2421                         if (segment.format == GST_FORMAT_TIME) {
2422                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2423                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2424                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2425                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2426                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2427                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2428
2429                                 /* keep the all the segment ev to cover the seeking */
2430                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2431                                 player->gapless.update_segment[stream_type] = TRUE;
2432
2433                                 if (!player->gapless.running)
2434                                         break;
2435
2436                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2437
2438                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2439
2440                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2441                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2442                                 gst_event_unref(event);
2443                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2444                         }
2445                         break;
2446                 }
2447         case GST_EVENT_QOS:
2448                 {
2449                         gdouble proportion = 0.0;
2450                         GstClockTimeDiff diff = 0;
2451                         GstClockTime timestamp = 0;
2452                         gint64 running_time_diff = -1;
2453                         GstQOSType type = 0;
2454                         GstEvent *tmpev = NULL;
2455
2456                         running_time_diff = player->gapless.segment[stream_type].base;
2457
2458                         if (running_time_diff <= 0) /* don't need to adjust */
2459                                 break;
2460
2461                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2462                         gst_event_unref(event);
2463
2464                         if (timestamp < running_time_diff) {
2465                                 LOGW("QOS event from previous group");
2466                                 ret = GST_PAD_PROBE_DROP;
2467                                 break;
2468                         }
2469
2470                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2471                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2472                                                 stream_type, GST_TIME_ARGS(timestamp),
2473                                                 GST_TIME_ARGS(running_time_diff),
2474                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2475
2476                         timestamp -= running_time_diff;
2477
2478                         /* That case is invalid for QoS events */
2479                         if (diff < 0 && -diff > timestamp) {
2480                                 LOGW("QOS event from previous group");
2481                                 ret = GST_PAD_PROBE_DROP;
2482                                 break;
2483                         }
2484
2485                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2486                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2487
2488                         break;
2489                 }
2490         default:
2491                 break;
2492         }
2493
2494 ERROR:
2495         if (caps)
2496                 gst_caps_unref(caps);
2497         return ret;
2498 }
2499
2500 static void
2501 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2502 {
2503         mm_player_t* player = NULL;
2504         GstElement* pipeline = NULL;
2505         GstElement* selector = NULL;
2506         GstElement* fakesink = NULL;
2507         GstCaps* caps = NULL;
2508         GstStructure* str = NULL;
2509         const gchar* name = NULL;
2510         GstPad* sinkpad = NULL;
2511         GstPad* srcpad = NULL;
2512         gboolean first_track = FALSE;
2513
2514         enum MainElementID elemId = MMPLAYER_M_NUM;
2515         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2516
2517         /* check handles */
2518         player = (mm_player_t*)data;
2519
2520         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2521         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2522
2523         //LOGD("pad-added signal handling\n");
2524
2525         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2526
2527         /* get mimetype from caps */
2528         caps = gst_pad_query_caps(pad, NULL);
2529         if (!caps) {
2530                 LOGE("cannot get caps from pad.\n");
2531                 goto ERROR;
2532         }
2533
2534         str = gst_caps_get_structure(caps, 0);
2535         if (!str) {
2536                 LOGE("cannot get structure from caps.\n");
2537                 goto ERROR;
2538         }
2539
2540         name = gst_structure_get_name(str);
2541         if (!name) {
2542                 LOGE("cannot get mimetype from structure.\n");
2543                 goto ERROR;
2544         }
2545
2546         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2547         //LOGD("detected mimetype : %s\n", name);
2548
2549         if (strstr(name, "video")) {
2550                 gint stype = 0;
2551
2552                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2553                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2554
2555                 /* don't make video because of not required, and not support multiple track */
2556                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2557                         LOGD("no video sink by null surface");
2558
2559                         gchar *caps_str = gst_caps_to_string(caps);
2560                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2561                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2562                                 player->set_mode.video_zc = TRUE;
2563
2564                         MMPLAYER_FREEIF(caps_str);
2565
2566                         if (player->v_stream_caps) {
2567                                 gst_caps_unref(player->v_stream_caps);
2568                                 player->v_stream_caps = NULL;
2569                         }
2570
2571                         LOGD("create fakesink instead of videobin");
2572
2573                         /* fake sink */
2574                         fakesink = gst_element_factory_make("fakesink", NULL);
2575                         if (fakesink == NULL) {
2576                                 LOGE("ERROR : fakesink create error\n");
2577                                 goto ERROR;
2578                         }
2579
2580                         if (player->ini.set_dump_element_flag)
2581                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2582
2583                         player->video_fakesink = fakesink;
2584
2585                         /* store it as it's sink element */
2586                         __mmplayer_add_sink(player, player->video_fakesink);
2587
2588                         gst_bin_add(GST_BIN(pipeline), fakesink);
2589
2590                         // link
2591                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2592
2593                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2594                                 LOGW("failed to link fakesink\n");
2595                                 gst_object_unref(GST_OBJECT(fakesink));
2596                                 goto ERROR;
2597                         }
2598
2599                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2600                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2601                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2602                         }
2603
2604                         if (player->set_mode.media_packet_video_stream) {
2605                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2606
2607                                 MMPLAYER_SIGNAL_CONNECT(player,
2608                                                                                 G_OBJECT(fakesink),
2609                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2610                                                                                 "handoff",
2611                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2612                                                                                 (gpointer)player);
2613
2614                                 MMPLAYER_SIGNAL_CONNECT(player,
2615                                                                                 G_OBJECT(fakesink),
2616                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2617                                                                                 "preroll-handoff",
2618                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2619                                                                                 (gpointer)player);
2620                         }
2621
2622                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2623                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2624                         goto DONE;
2625                 }
2626
2627                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2628                         __mmplayer_gst_decode_callback(elem, pad, player);
2629                         goto DONE;
2630                 }
2631
2632                 LOGD("video selector \n");
2633                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2634                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2635         } else {
2636                 if (strstr(name, "audio")) {
2637                         gint samplerate = 0;
2638                         gint channels = 0;
2639
2640                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2641                                 __mmplayer_gst_decode_callback(elem, pad, player);
2642                                 goto DONE;
2643                         }
2644
2645                         LOGD("audio selector \n");
2646                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2647                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2648
2649                         gst_structure_get_int(str, "rate", &samplerate);
2650                         gst_structure_get_int(str, "channels", &channels);
2651
2652                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2653                                 /* fake sink */
2654                                 fakesink = gst_element_factory_make("fakesink", NULL);
2655                                 if (fakesink == NULL) {
2656                                         LOGE("ERROR : fakesink create error\n");
2657                                         goto ERROR;
2658                                 }
2659
2660                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2661
2662                                 /* link */
2663                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2664
2665                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2666                                         LOGW("failed to link fakesink\n");
2667                                         gst_object_unref(GST_OBJECT(fakesink));
2668                                         goto ERROR;
2669                                 }
2670
2671                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2672                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2673                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2674
2675                                 goto DONE;
2676                         }
2677                 } else if (strstr(name, "text")) {
2678                         LOGD("text selector \n");
2679                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2680                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2681                 } else {
2682                         LOGE("wrong elem id \n");
2683                         goto ERROR;
2684                 }
2685         }
2686
2687         selector = player->pipeline->mainbin[elemId].gst;
2688         if (selector == NULL) {
2689                 selector = gst_element_factory_make("input-selector", NULL);
2690                 LOGD("Creating input-selector\n");
2691                 if (selector == NULL) {
2692                         LOGE("ERROR : input-selector create error\n");
2693                         goto ERROR;
2694                 }
2695                 g_object_set(selector, "sync-streams", TRUE, NULL);
2696
2697                 player->pipeline->mainbin[elemId].id = elemId;
2698                 player->pipeline->mainbin[elemId].gst = selector;
2699
2700                 first_track = TRUE;
2701                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2702
2703                 srcpad = gst_element_get_static_pad(selector, "src");
2704
2705                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2706                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2707                         __mmplayer_gst_selector_blocked, NULL, NULL);
2708                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2709                         __mmplayer_gst_selector_event_probe, player, NULL);
2710
2711                 gst_element_set_state(selector, GST_STATE_PAUSED);
2712                 gst_bin_add(GST_BIN(pipeline), selector);
2713         } else
2714                 LOGD("input-selector is already created.\n");
2715
2716         // link
2717         LOGD("Calling request pad with selector %p \n", selector);
2718         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2719
2720         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2721
2722         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2723                 LOGW("failed to link selector\n");
2724                 gst_object_unref(GST_OBJECT(selector));
2725                 goto ERROR;
2726         }
2727
2728         if (first_track) {
2729                 LOGD("this is first track --> active track \n");
2730                 g_object_set(selector, "active-pad", sinkpad, NULL);
2731         }
2732
2733         _mmplayer_track_update_info(player, stream_type, sinkpad);
2734
2735
2736 DONE:
2737 ERROR:
2738
2739         if (caps)
2740                 gst_caps_unref(caps);
2741
2742         if (sinkpad) {
2743                 gst_object_unref(GST_OBJECT(sinkpad));
2744                 sinkpad = NULL;
2745         }
2746
2747         if (srcpad) {
2748                 gst_object_unref(GST_OBJECT(srcpad));
2749                 srcpad = NULL;
2750         }
2751
2752         return;
2753 }
2754
2755 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2756 {
2757         GstPad* srcpad = NULL;
2758         MMHandleType attrs = 0;
2759         gint active_index = 0;
2760
2761         // [link] input-selector :: textbin
2762         srcpad = gst_element_get_static_pad(text_selector, "src");
2763         if (!srcpad) {
2764                 LOGE("failed to get srcpad from selector\n");
2765                 return;
2766         }
2767
2768         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2769
2770         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2771         if ((active_index != DEFAULT_TRACK) &&
2772                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2773                 LOGW("failed to change text track\n");
2774                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2775         }
2776
2777         player->no_more_pad = TRUE;
2778         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2779
2780         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2781         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2782                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2783                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2784         }
2785
2786         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2787
2788         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2789                 player->has_closed_caption = TRUE;
2790
2791         attrs = MMPLAYER_GET_ATTRS(player);
2792         if (attrs) {
2793                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2794                 if (mmf_attrs_commit(attrs))
2795                         LOGE("failed to commit.\n");
2796         } else
2797                 LOGE("cannot get content attribute");
2798
2799         if (srcpad) {
2800                 gst_object_unref(GST_OBJECT(srcpad));
2801                 srcpad = NULL;
2802         }
2803 }
2804
2805 static void
2806 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2807 {
2808         mm_player_t* player = (mm_player_t*)data;
2809         GstElement* selector = NULL;
2810         GstElement* queue = NULL;
2811
2812         GstPad* srcpad = NULL;
2813         GstPad* sinkpad = NULL;
2814         GstCaps* caps = NULL;
2815         gchar* caps_str = NULL;
2816
2817         MMPLAYER_FENTER();
2818         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2819
2820         caps = gst_pad_get_current_caps(pad);
2821         caps_str = gst_caps_to_string(caps);
2822         LOGD("deinterleave new caps : %s\n", caps_str);
2823         MMPLAYER_FREEIF(caps_str);
2824         gst_caps_unref(caps);
2825
2826         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2827                 LOGE("ERROR : queue create error\n");
2828                 goto ERROR;
2829         }
2830
2831         g_object_set(G_OBJECT(queue),
2832                                 "max-size-buffers", 10,
2833                                 "max-size-bytes", 0,
2834                                 "max-size-time", (guint64)0,
2835                                 NULL);
2836
2837         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2838
2839         if (!selector) {
2840                 LOGE("there is no audio channel selector.\n");
2841                 goto ERROR;
2842         }
2843
2844         srcpad = gst_element_get_static_pad(queue, "src");
2845         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2846
2847         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2848
2849         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2850                 LOGW("failed to link deinterleave - selector\n");
2851                 goto ERROR;
2852         }
2853
2854         gst_element_set_state(queue, GST_STATE_PAUSED);
2855         player->audio_mode.total_track_num++;
2856
2857 ERROR:
2858
2859         if (srcpad) {
2860                 gst_object_unref(GST_OBJECT(srcpad));
2861                 srcpad = NULL;
2862         }
2863
2864         if (sinkpad) {
2865                 gst_object_unref(GST_OBJECT(sinkpad));
2866                 sinkpad = NULL;
2867         }
2868
2869         MMPLAYER_FLEAVE();
2870         return;
2871 }
2872
2873 static void
2874 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2875 {
2876         mm_player_t* player = NULL;
2877         GstElement* selector = NULL;
2878         GstPad* sinkpad = NULL;
2879         gint active_index = 0;
2880         gchar* change_pad_name = NULL;
2881         GstCaps* caps = NULL;   // no need to unref
2882         gint default_audio_ch = 0;
2883
2884         MMPLAYER_FENTER();
2885         player = (mm_player_t*) data;
2886
2887         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2888
2889         if (!selector) {
2890                 LOGE("there is no audio channel selector.\n");
2891                 goto ERROR;
2892         }
2893
2894         active_index = player->audio_mode.active_pad_index;
2895
2896         if (active_index != default_audio_ch) {
2897                 gint audio_ch = default_audio_ch;
2898
2899                 /*To get the new pad from the selector*/
2900                 change_pad_name = g_strdup_printf("sink%d", active_index);
2901                 if (change_pad_name != NULL) {
2902                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2903                         if (sinkpad != NULL) {
2904                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2905                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2906
2907                                 audio_ch = active_index;
2908
2909                                 caps = gst_pad_get_current_caps(sinkpad);
2910                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2911
2912                                 __mmplayer_set_audio_attrs(player, caps);
2913                                 gst_caps_unref(caps);
2914                         }
2915                         MMPLAYER_FREEIF(change_pad_name);
2916                 }
2917
2918                 player->audio_mode.active_pad_index = audio_ch;
2919                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2920         }
2921
2922 ERROR:
2923
2924         if (sinkpad)
2925                 gst_object_unref(sinkpad);
2926
2927         MMPLAYER_FLEAVE();
2928         return;
2929 }
2930
2931 static void
2932 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2933 {
2934         mm_player_t* player = NULL;
2935         MMPlayerGstElement *mainbin = NULL;
2936
2937         GstElement* tee = NULL;
2938         GstElement* stereo_queue = NULL;
2939         GstElement* mono_queue = NULL;
2940         GstElement* conv = NULL;
2941         GstElement* filter = NULL;
2942         GstElement* deinterleave = NULL;
2943         GstElement* selector = NULL;
2944
2945         GstPad* srcpad = NULL;
2946         GstPad* selector_srcpad = NULL;
2947         GstPad* sinkpad = NULL;
2948         GstCaps* caps = NULL;
2949         gulong block_id = 0;
2950
2951         MMPLAYER_FENTER();
2952
2953         /* check handles */
2954         player = (mm_player_t*) data;
2955
2956         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2957         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2958
2959         mainbin = player->pipeline->mainbin;
2960
2961         /* tee */
2962         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2963                 LOGE("ERROR : tee create error\n");
2964                 goto ERROR;
2965         }
2966
2967         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2968         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2969
2970         gst_element_set_state(tee, GST_STATE_PAUSED);
2971
2972         /* queue */
2973         srcpad = gst_element_get_request_pad(tee, "src_%u");
2974         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2975                 LOGE("ERROR : stereo queue create error\n");
2976                 goto ERROR;
2977         }
2978
2979         g_object_set(G_OBJECT(stereo_queue),
2980                                 "max-size-buffers", 10,
2981                                 "max-size-bytes", 0,
2982                                 "max-size-time", (guint64)0,
2983                                 NULL);
2984
2985         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2986         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2987
2988         if (srcpad) {
2989                 gst_object_unref(GST_OBJECT(srcpad));
2990                 srcpad = NULL;
2991         }
2992
2993         srcpad = gst_element_get_request_pad(tee, "src_%u");
2994
2995         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2996                 LOGE("ERROR : mono queue create error\n");
2997                 goto ERROR;
2998         }
2999
3000         g_object_set(G_OBJECT(mono_queue),
3001                                 "max-size-buffers", 10,
3002                                 "max-size-bytes", 0,
3003                                 "max-size-time", (guint64)0,
3004                                 NULL);
3005
3006         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3007         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3008
3009         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3010         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3011
3012         /* audioconvert */
3013         srcpad = gst_element_get_static_pad(mono_queue, "src");
3014         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3015                 LOGE("ERROR : audioconvert create error\n");
3016                 goto ERROR;
3017         }
3018
3019         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3020         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3021
3022         /* caps filter */
3023         if (srcpad) {
3024                 gst_object_unref(GST_OBJECT(srcpad));
3025                 srcpad = NULL;
3026         }
3027         srcpad = gst_element_get_static_pad(conv, "src");
3028
3029         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3030                 LOGE("ERROR : capsfilter create error\n");
3031                 goto ERROR;
3032         }
3033
3034         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3035         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3036
3037         caps = gst_caps_from_string("audio/x-raw-int, "
3038                                 "width = (int) 16, "
3039                                 "depth = (int) 16, "
3040                                 "channels = (int) 2");
3041
3042         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3043         gst_caps_unref(caps);
3044
3045         gst_element_set_state(conv, GST_STATE_PAUSED);
3046         gst_element_set_state(filter, GST_STATE_PAUSED);
3047
3048         /* deinterleave */
3049         if (srcpad) {
3050                 gst_object_unref(GST_OBJECT(srcpad));
3051                 srcpad = NULL;
3052         }
3053         srcpad = gst_element_get_static_pad(filter, "src");
3054
3055         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3056                 LOGE("ERROR : deinterleave create error\n");
3057                 goto ERROR;
3058         }
3059
3060         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3061
3062         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3063                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3064
3065         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3066                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3067
3068         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3069         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3070
3071         /* selector */
3072         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3073         if (selector == NULL) {
3074                 LOGE("ERROR : audio-selector create error\n");
3075                 goto ERROR;
3076         }
3077
3078         g_object_set(selector, "sync-streams", TRUE, NULL);
3079         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3080
3081         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3082         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3083
3084         selector_srcpad = gst_element_get_static_pad(selector, "src");
3085
3086         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3087         block_id =
3088                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3089                         __mmplayer_gst_selector_blocked, NULL, NULL);
3090
3091         if (srcpad) {
3092                 gst_object_unref(GST_OBJECT(srcpad));
3093                 srcpad = NULL;
3094         }
3095
3096         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3097         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3098
3099         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3100                 LOGW("failed to link queue_stereo - selector\n");
3101                 goto ERROR;
3102         }
3103
3104         player->audio_mode.total_track_num++;
3105
3106         g_object_set(selector, "active-pad", sinkpad, NULL);
3107         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3108         gst_element_set_state(selector, GST_STATE_PAUSED);
3109
3110         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3111
3112 ERROR:
3113
3114         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3115         if (block_id != 0) {
3116                 gst_pad_remove_probe(selector_srcpad, block_id);
3117                 block_id = 0;
3118         }
3119
3120         if (sinkpad) {
3121                 gst_object_unref(GST_OBJECT(sinkpad));
3122                 sinkpad = NULL;
3123         }
3124
3125         if (srcpad) {
3126                 gst_object_unref(GST_OBJECT(srcpad));
3127                 srcpad = NULL;
3128         }
3129
3130         if (selector_srcpad) {
3131                 gst_object_unref(GST_OBJECT(selector_srcpad));
3132                 selector_srcpad = NULL;
3133         }
3134
3135         MMPLAYER_FLEAVE();
3136         return;
3137 }
3138
3139 static void
3140 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3141 {
3142         mm_player_t* player = NULL;
3143         GstPad* srcpad = NULL;
3144         GstElement* video_selector = NULL;
3145         GstElement* audio_selector = NULL;
3146         GstElement* text_selector = NULL;
3147         MMHandleType attrs = 0;
3148         gint active_index = 0;
3149         gint64 dur_bytes = 0L;
3150
3151         player = (mm_player_t*) data;
3152
3153         LOGD("no-more-pad signal handling\n");
3154
3155         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3156                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3157                 LOGW("no need to go more");
3158
3159                 if (player->gapless.reconfigure) {
3160                         player->gapless.reconfigure = FALSE;
3161                         MMPLAYER_PLAYBACK_UNLOCK(player);
3162                 }
3163
3164                 return;
3165         }
3166
3167         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3168                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3169                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3170                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3171                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3172
3173                 if (NULL == player->streamer) {
3174                         LOGW("invalid state for buffering");
3175                         goto ERROR;
3176                 }
3177
3178                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3179                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3180
3181                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3182                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3183
3184                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3185
3186                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3187                         LOGE("fail to get duration.\n");
3188
3189                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3190                 // use file information was already set on Q2 when it was created.
3191                 __mm_player_streaming_set_queue2(player->streamer,
3192                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3193                                                 TRUE,                                                           // use_buffering
3194                                                 buffer_bytes,
3195                                                 init_buffering_time,
3196                                                 1.0,                                                            // low percent
3197                                                 player->ini.http_buffering_limit,       // high percent
3198                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3199                                                 NULL,
3200                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3201         }
3202
3203         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3204         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3205         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3206         if (video_selector) {
3207                 // [link] input-selector :: videobin
3208                 srcpad = gst_element_get_static_pad(video_selector, "src");
3209                 if (!srcpad) {
3210                         LOGE("failed to get srcpad from video selector\n");
3211                         goto ERROR;
3212                 }
3213
3214                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3215                 if (!text_selector && !audio_selector)
3216                         player->no_more_pad = TRUE;
3217
3218                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3219
3220                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3221                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3222                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3223                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3224                 }
3225         }
3226
3227         if (audio_selector) {
3228                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3229                 if ((active_index != DEFAULT_TRACK) &&
3230                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3231                         LOGW("failed to change audio track\n");
3232                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3233                 }
3234
3235                 // [link] input-selector :: audiobin
3236                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3237                 if (!srcpad) {
3238                         LOGE("failed to get srcpad from selector\n");
3239                         goto ERROR;
3240                 }
3241
3242                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3243                 if (!text_selector)
3244                         player->no_more_pad = TRUE;
3245
3246                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3247                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3248                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3249                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3250                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3251                         }
3252
3253                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3254                 } else {
3255                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3256
3257                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3258                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3259                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3260                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3261                         }
3262                 }
3263
3264                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3265
3266                 attrs = MMPLAYER_GET_ATTRS(player);
3267                 if (attrs) {
3268                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3269                         if (mmf_attrs_commit(attrs))
3270                                 LOGE("failed to commit.\n");
3271                 } else
3272                         LOGE("cannot get content attribute");
3273         } else {
3274                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3275                         LOGD("There is no audio track : remove audiobin");
3276
3277                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3278                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3279
3280                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3281                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3282                 }
3283
3284                 if (player->num_dynamic_pad == 0)
3285                         __mmplayer_pipeline_complete(NULL, player);
3286         }
3287
3288         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3289                 if (text_selector)
3290                         __mmplayer_handle_text_decode_path(player, text_selector);
3291         }
3292
3293         MMPLAYER_FLEAVE();
3294
3295 ERROR:
3296         if (srcpad) {
3297                 gst_object_unref(GST_OBJECT(srcpad));
3298                 srcpad = NULL;
3299         }
3300
3301         if (player->gapless.reconfigure) {
3302                 player->gapless.reconfigure = FALSE;
3303                 MMPLAYER_PLAYBACK_UNLOCK(player);
3304         }
3305 }
3306
3307 static void
3308 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3309 {
3310         mm_player_t* player = NULL;
3311         MMHandleType attrs = 0;
3312         GstElement* pipeline = NULL;
3313         GstCaps* caps = NULL;
3314         gchar* caps_str = NULL;
3315         GstStructure* str = NULL;
3316         const gchar* name = NULL;
3317         GstPad* sinkpad = NULL;
3318         GstElement* sinkbin = NULL;
3319         gboolean reusing = FALSE;
3320         GstElement *text_selector = NULL;
3321
3322         /* check handles */
3323         player = (mm_player_t*) data;
3324
3325         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3326         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3327
3328         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3329
3330         attrs = MMPLAYER_GET_ATTRS(player);
3331         if (!attrs) {
3332                 LOGE("cannot get content attribute\n");
3333                 goto ERROR;
3334         }
3335
3336         /* get mimetype from caps */
3337         caps = gst_pad_query_caps(pad, NULL);
3338         if (!caps) {
3339                 LOGE("cannot get caps from pad.\n");
3340                 goto ERROR;
3341         }
3342         caps_str = gst_caps_to_string(caps);
3343
3344         str = gst_caps_get_structure(caps, 0);
3345         if (!str) {
3346                 LOGE("cannot get structure from caps.\n");
3347                 goto ERROR;
3348         }
3349
3350         name = gst_structure_get_name(str);
3351         if (!name) {
3352                 LOGE("cannot get mimetype from structure.\n");
3353                 goto ERROR;
3354         }
3355
3356         //LOGD("detected mimetype : %s\n", name);
3357
3358         if (strstr(name, "audio")) {
3359                 if (player->pipeline->audiobin == NULL) {
3360                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3361                                 LOGE("failed to create audiobin. continuing without audio\n");
3362                                 goto ERROR;
3363                         }
3364
3365                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3366                         LOGD("creating audiosink bin success\n");
3367                 } else {
3368                         reusing = TRUE;
3369                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3370                         LOGD("reusing audiobin\n");
3371                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3372                 }
3373
3374                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3375                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3376
3377                 player->audiosink_linked  = 1;
3378
3379                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3380                 if (!sinkpad) {
3381                         LOGE("failed to get pad from sinkbin\n");
3382                         goto ERROR;
3383                 }
3384         } else if (strstr(name, "video")) {
3385                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3386                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3387                         player->set_mode.video_zc = TRUE;
3388
3389                 if (player->pipeline->videobin == NULL) {
3390                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3391                         /* get video surface type */
3392                         int surface_type = 0;
3393                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3394                         LOGD("display_surface_type(%d)\n", surface_type);
3395
3396                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3397                                 LOGD("not make videobin because it dose not want\n");
3398                                 goto ERROR;
3399                         }
3400
3401                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3402                                 /* mark video overlay for acquire */
3403                                 if (player->video_overlay_resource == NULL) {
3404                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3405                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3406                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3407                                                         &player->video_overlay_resource)
3408                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3409                                                 LOGE("could not mark video_overlay resource for acquire\n");
3410                                                 goto ERROR;
3411                                         }
3412                                 }
3413                         }
3414
3415                         player->interrupted_by_resource = FALSE;
3416                         /* acquire resources for video overlay */
3417                         if (mm_resource_manager_commit(player->resource_manager) !=
3418                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3419                                 LOGE("could not acquire resources for video playing\n");
3420                                 goto ERROR;
3421                         }
3422
3423                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3424                                 LOGE("failed to create videobin. continuing without video\n");
3425                                 goto ERROR;
3426                         }
3427
3428                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3429                         LOGD("creating videosink bin success\n");
3430                 } else {
3431                         reusing = TRUE;
3432                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3433                         LOGD("re-using videobin\n");
3434                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3435                 }
3436
3437                 player->videosink_linked  = 1;
3438
3439                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3440                 if (!sinkpad) {
3441                         LOGE("failed to get pad from sinkbin\n");
3442                         goto ERROR;
3443                 }
3444         } else if (strstr(name, "text")) {
3445                 if (player->pipeline->textbin == NULL) {
3446                         MMPlayerGstElement* mainbin = NULL;
3447
3448                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3449                                 LOGE("failed to create text sink bin. continuing without text\n");
3450                                 goto ERROR;
3451                         }
3452
3453                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3454                         LOGD("creating textsink bin success\n");
3455
3456                         /* FIXIT : track number shouldn't be hardcoded */
3457                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3458
3459                         player->textsink_linked  = 1;
3460                         LOGI("player->textsink_linked set to 1\n");
3461
3462                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3463                         if (!sinkpad) {
3464                                 LOGE("failed to get pad from sinkbin\n");
3465                                 goto ERROR;
3466                         }
3467
3468                         mainbin = player->pipeline->mainbin;
3469
3470                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3471                                 /* input selector */
3472                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3473                                 if (!text_selector) {
3474                                         LOGE("failed to create subtitle input selector element\n");
3475                                         goto ERROR;
3476                                 }
3477                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3478
3479                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3480                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3481
3482                                 /* warm up */
3483                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3484                                         LOGE("failed to set state(READY) to sinkbin\n");
3485                                         goto ERROR;
3486                                 }
3487
3488                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3489                                         LOGW("failed to add subtitle input selector\n");
3490                                         goto ERROR;
3491                                 }
3492
3493                                 LOGD("created element input-selector");
3494
3495                         } else {
3496                                 LOGD("already having subtitle input selector");
3497                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3498                         }
3499                 } else {
3500                         if (!player->textsink_linked) {
3501                                 LOGD("re-using textbin\n");
3502
3503                                 reusing = TRUE;
3504                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3505
3506                                 player->textsink_linked  = 1;
3507                                 LOGI("player->textsink_linked set to 1\n");
3508                         } else
3509                                 LOGD("ignoring internal subtutle since external subtitle is available");
3510                 }
3511         } else {
3512                 LOGW("unknown type of elementary stream!ignoring it...\n");
3513                 goto ERROR;
3514         }
3515
3516         if (sinkbin) {
3517                 if (!reusing) {
3518                         /* warm up */
3519                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3520                                 LOGE("failed to set state(READY) to sinkbin\n");
3521                                 goto ERROR;
3522                         }
3523
3524                         /* Added for multi audio support to avoid adding audio bin again*/
3525                         /* add */
3526                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3527                                 LOGE("failed to add sinkbin to pipeline\n");
3528                                 goto ERROR;
3529                         }
3530                 }
3531
3532                 /* link */
3533                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3534                         LOGE("failed to get pad from sinkbin\n");
3535                         goto ERROR;
3536                 }
3537
3538                 if (!reusing) {
3539                         /* run */
3540                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3541                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3542                                 goto ERROR;
3543                         }
3544
3545                         if (text_selector) {
3546                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3547                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3548                                         goto ERROR;
3549                                 }
3550                         }
3551                 }
3552
3553                 gst_object_unref(sinkpad);
3554                 sinkpad = NULL;
3555         }
3556
3557         LOGD("[handle: %p] linking sink bin success", player);
3558
3559         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3560          * streaming task. if the task blocked, then buffer will not flow to the next element
3561          *(autoplugging element). so this is special hack for streaming. please try to remove it
3562          */
3563         /* dec stream count. we can remove fakesink if it's zero */
3564         if (player->num_dynamic_pad)
3565                 player->num_dynamic_pad--;
3566
3567         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3568
3569         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3570                 __mmplayer_pipeline_complete(NULL, player);
3571
3572 ERROR:
3573
3574         MMPLAYER_FREEIF(caps_str);
3575
3576         if (caps)
3577                 gst_caps_unref(caps);
3578
3579         if (sinkpad)
3580                 gst_object_unref(GST_OBJECT(sinkpad));
3581
3582         /* flusing out new attributes */
3583         if (mmf_attrs_commit(attrs))
3584                 LOGE("failed to comit attributes\n");
3585
3586         return;
3587 }
3588
3589 static gboolean
3590 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3591 {
3592         int pro_value = 0; // in the case of expection, default will be returned.
3593         int dest_angle = rotation_angle;
3594         int rotation_type = -1;
3595
3596         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3597         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3598         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3599
3600         if (rotation_angle >= 360)
3601                 dest_angle = rotation_angle - 360;
3602
3603         /* chech if supported or not */
3604         if (dest_angle % 90) {
3605                 LOGD("not supported rotation angle = %d", rotation_angle);
3606                 return FALSE;
3607         }
3608
3609         /*
3610           * tizenwlsink (A)
3611           * custom_convert - none (B)
3612           * videoflip - none (C)
3613           */
3614         if (player->set_mode.video_zc) {
3615                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3616                         rotation_type = ROTATION_USING_CUSTOM;
3617                 else // A
3618                         rotation_type = ROTATION_USING_SINK;
3619         } else {
3620                 int surface_type = 0;
3621                 rotation_type = ROTATION_USING_FLIP;
3622
3623                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3624                 LOGD("check display surface type attribute: %d", surface_type);
3625
3626                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3627                         rotation_type = ROTATION_USING_SINK;
3628                 else
3629                         rotation_type = ROTATION_USING_FLIP; //C
3630
3631                 LOGD("using %d type for rotation", rotation_type);
3632         }
3633
3634         /* get property value for setting */
3635         switch (rotation_type) {
3636         case ROTATION_USING_SINK: // tizenwlsink
3637                 {
3638                         switch (dest_angle) {
3639                         case 0:
3640                                 break;
3641                         case 90:
3642                                 pro_value = 3; // clockwise 90
3643                                 break;
3644                         case 180:
3645                                 pro_value = 2;
3646                                 break;
3647                         case 270:
3648                                 pro_value = 1; // counter-clockwise 90
3649                                 break;
3650                         }
3651                 }
3652                 break;
3653         case ROTATION_USING_CUSTOM:
3654                 {
3655                         gchar *ename = NULL;
3656                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3657
3658                         if (g_strrstr(ename, "fimcconvert")) {
3659                                 switch (dest_angle) {
3660                                 case 0:
3661                                         break;
3662                                 case 90:
3663                                         pro_value = 90; // clockwise 90
3664                                         break;
3665                                 case 180:
3666                                         pro_value = 180;
3667                                         break;
3668                                 case 270:
3669                                         pro_value = 270; // counter-clockwise 90
3670                                         break;
3671                                 }
3672                         }
3673                 }
3674                 break;
3675         case ROTATION_USING_FLIP: // videoflip
3676                 {
3677                                 switch (dest_angle) {
3678                                 case 0:
3679                                         break;
3680                                 case 90:
3681                                         pro_value = 1; // clockwise 90
3682                                         break;
3683                                 case 180:
3684                                         pro_value = 2;
3685                                         break;
3686                                 case 270:
3687                                         pro_value = 3; // counter-clockwise 90
3688                                         break;
3689                                 }
3690                 }
3691                 break;
3692         }
3693
3694         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3695
3696         *value = pro_value;
3697
3698         return TRUE;
3699 }
3700
3701 int
3702 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3703 {
3704         /* check video sinkbin is created */
3705         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3706                 player->pipeline &&
3707                 player->pipeline->videobin &&
3708                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3709                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3710                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3711
3712         return MM_ERROR_NONE;
3713 }
3714
3715 void
3716 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3717 {
3718         int rotation_value = 0;
3719         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3720         int user_angle = 0;
3721         MMPLAYER_FENTER();
3722
3723         /* check video sinkbin is created */
3724         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3725                 return;
3726
3727         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3728
3729         /* get rotation value to set */
3730         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3731         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3732         LOGD("set video param : rotate %d", rotation_value);
3733 }
3734
3735 void
3736 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3737 {
3738         MMHandleType attrs = 0;
3739         int visible = 0;
3740         MMPLAYER_FENTER();
3741
3742         /* check video sinkbin is created */
3743         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3744                 return;
3745
3746         attrs = MMPLAYER_GET_ATTRS(player);
3747         MMPLAYER_RETURN_IF_FAIL(attrs);
3748
3749         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3750         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3751         LOGD("set video param : visible %d", visible);
3752 }
3753
3754 void
3755 __mmplayer_video_param_set_display_method(mm_player_t* player)
3756 {
3757         MMHandleType attrs = 0;
3758         int display_method = 0;
3759         MMPLAYER_FENTER();
3760
3761         /* check video sinkbin is created */
3762         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3763                 return;
3764
3765         attrs = MMPLAYER_GET_ATTRS(player);
3766         MMPLAYER_RETURN_IF_FAIL(attrs);
3767
3768         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3769         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3770         LOGD("set video param : method %d", display_method);
3771 }
3772
3773 void
3774 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3775 {
3776         MMHandleType attrs = 0;
3777         void *handle = NULL;
3778         /*set wl_display*/
3779         int wl_window_x = 0;
3780         int wl_window_y = 0;
3781         int wl_window_width = 0;
3782         int wl_window_height = 0;
3783         MMPLAYER_FENTER();
3784
3785         /* check video sinkbin is created */
3786         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3787                 return;
3788
3789         attrs = MMPLAYER_GET_ATTRS(player);
3790         MMPLAYER_RETURN_IF_FAIL(attrs);
3791
3792         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3793
3794         if (handle) {
3795                 /*It should be set after setting window*/
3796                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3797                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3798                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3799                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3800
3801                 /* After setting window handle, set render      rectangle */
3802                 gst_video_overlay_set_render_rectangle(
3803                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3804                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3805                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3806                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3807
3808         }
3809 }
3810 void
3811 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3812 {
3813         MMHandleType attrs = 0;
3814         void *handle = NULL;
3815
3816         /* check video sinkbin is created */
3817         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3818                 return;
3819
3820         attrs = MMPLAYER_GET_ATTRS(player);
3821         MMPLAYER_RETURN_IF_FAIL(attrs);
3822
3823         /* common case if using overlay surface */
3824         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3825
3826         if (handle) {
3827                 /* default is using wl_surface_id */
3828                 unsigned int wl_surface_id      = 0;
3829                 wl_surface_id = *(int*)handle;
3830                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3831                 gst_video_overlay_set_wl_window_wl_surface_id(
3832                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3833                                 *(int*)handle);
3834         } else
3835                 /* FIXIT : is it error case? */
3836                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3837 }
3838
3839
3840 int
3841 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3842 {
3843         bool update_all_param = FALSE;
3844         MMPLAYER_FENTER();
3845
3846         /* check video sinkbin is created */
3847         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3848                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3849
3850         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3851                 LOGE("can not find tizenwlsink");
3852                 return MM_ERROR_PLAYER_INTERNAL;
3853         }
3854
3855         LOGD("param_name : %s", param_name);
3856         if (!g_strcmp0(param_name, "update_all_param"))
3857                 update_all_param = TRUE;
3858
3859         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3860                 __mmplayer_video_param_set_display_overlay(player);
3861         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3862                 __mmplayer_video_param_set_display_method(player);
3863         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3864                 __mmplayer_video_param_set_render_rectangle(player);
3865         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3866                 __mmplayer_video_param_set_display_visible(player);
3867         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3868                 __mmplayer_video_param_set_display_rotation(player);
3869
3870         return MM_ERROR_NONE;
3871 }
3872
3873 int
3874 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3875 {
3876         MMHandleType attrs = 0;
3877         int surface_type = 0;
3878         int ret = MM_ERROR_NONE;
3879
3880         MMPLAYER_FENTER();
3881
3882         /* check video sinkbin is created */
3883         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3884                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3885
3886         attrs = MMPLAYER_GET_ATTRS(player);
3887         if (!attrs) {
3888                 LOGE("cannot get content attribute");
3889                 return MM_ERROR_PLAYER_INTERNAL;
3890         }
3891         LOGD("param_name : %s", param_name);
3892
3893         /* update display surface */
3894         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3895         LOGD("check display surface type attribute: %d", surface_type);
3896
3897         /* configuring display */
3898         switch (surface_type) {
3899         case MM_DISPLAY_SURFACE_OVERLAY:
3900                 {
3901                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3902                         if (ret != MM_ERROR_NONE)
3903                                 return ret;
3904                 }
3905                 break;
3906         }
3907
3908         MMPLAYER_FLEAVE();
3909
3910         return MM_ERROR_NONE;
3911 }
3912
3913 int
3914 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3915 {
3916         gboolean disable_overlay = FALSE;
3917         mm_player_t* player = (mm_player_t*) hplayer;
3918         int ret = MM_ERROR_NONE;
3919
3920         MMPLAYER_FENTER();
3921         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3922         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3923                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3924                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3925
3926         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3927                 LOGW("Display control is not supported");
3928                 return MM_ERROR_PLAYER_INTERNAL;
3929         }
3930
3931         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3932
3933         if (audio_only == (bool)disable_overlay) {
3934                 LOGE("It's the same with current setting: (%d)", audio_only);
3935                 return MM_ERROR_NONE;
3936         }
3937
3938         if (audio_only) {
3939                 LOGE("disable overlay");
3940                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3941
3942                 /* release overlay resource */
3943                 if (player->video_overlay_resource != NULL) {
3944                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3945                                         player->video_overlay_resource);
3946                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3947                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3948                                 goto ERROR;
3949                         }
3950                         player->video_overlay_resource = NULL;
3951                 }
3952
3953                 ret = mm_resource_manager_commit(player->resource_manager);
3954                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3955                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3956                         goto ERROR;
3957                 }
3958         } else {
3959                 /* mark video overlay for acquire */
3960                 if (player->video_overlay_resource == NULL) {
3961                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3962                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3963                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3964                                         &player->video_overlay_resource);
3965                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3966                                 LOGE("could not prepare for video_overlay resource\n");
3967                                 goto ERROR;
3968                         }
3969                 }
3970
3971                 player->interrupted_by_resource = FALSE;
3972                 /* acquire resources for video overlay */
3973                 ret = mm_resource_manager_commit(player->resource_manager);
3974                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3975                         LOGE("could not acquire resources for video playing\n");
3976                         goto ERROR;
3977                 }
3978
3979                 LOGD("enable overlay");
3980                 __mmplayer_video_param_set_display_overlay(player);
3981                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3982         }
3983
3984 ERROR:
3985         MMPLAYER_FLEAVE();
3986         return MM_ERROR_NONE;
3987 }
3988
3989 int
3990 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3991 {
3992         mm_player_t* player = (mm_player_t*) hplayer;
3993         gboolean disable_overlay = FALSE;
3994
3995         MMPLAYER_FENTER();
3996
3997         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3998         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3999         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4000                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4001                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4002
4003         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4004                 LOGW("Display control is not supported");
4005                 return MM_ERROR_PLAYER_INTERNAL;
4006         }
4007
4008         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4009
4010         *paudio_only = (bool)(disable_overlay);
4011
4012         LOGD("audio_only : %d", *paudio_only);
4013
4014         MMPLAYER_FLEAVE();
4015
4016         return MM_ERROR_NONE;
4017 }
4018
4019 static int
4020 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4021 {
4022         GList* bucket = element_bucket;
4023         MMPlayerGstElement* element = NULL;
4024         MMPlayerGstElement* prv_element = NULL;
4025         gint successful_link_count = 0;
4026
4027         MMPLAYER_FENTER();
4028
4029         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4030
4031         prv_element = (MMPlayerGstElement*)bucket->data;
4032         bucket = bucket->next;
4033
4034         for (; bucket; bucket = bucket->next) {
4035                 element = (MMPlayerGstElement*)bucket->data;
4036
4037                 if (element && element->gst) {
4038                         /* If next element is audio appsrc then make a separate audio pipeline */
4039                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4040                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4041                                 prv_element = element;
4042                                 continue;
4043                         }
4044
4045                         if (prv_element && prv_element->gst) {
4046                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4047                                         LOGD("linking [%s] to [%s] success\n",
4048                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4049                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4050                                         successful_link_count++;
4051                                 } else {
4052                                         LOGD("linking [%s] to [%s] failed\n",
4053                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4054                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4055                                         return -1;
4056                                 }
4057                         }
4058                 }
4059
4060                 prv_element = element;
4061         }
4062
4063         MMPLAYER_FLEAVE();
4064
4065         return successful_link_count;
4066 }
4067
4068 static int
4069 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4070 {
4071         GList* bucket = element_bucket;
4072         MMPlayerGstElement* element = NULL;
4073         int successful_add_count = 0;
4074
4075         MMPLAYER_FENTER();
4076
4077         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4078         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4079
4080         for (; bucket; bucket = bucket->next) {
4081                 element = (MMPlayerGstElement*)bucket->data;
4082
4083                 if (element && element->gst) {
4084                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4085                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4086                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4087                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4088                                 return 0;
4089                         }
4090                         successful_add_count++;
4091                 }
4092         }
4093
4094         MMPLAYER_FLEAVE();
4095
4096         return successful_add_count;
4097 }
4098
4099 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4100 {
4101         mm_player_t* player = (mm_player_t*) data;
4102         GstCaps *caps = NULL;
4103         GstStructure *str = NULL;
4104         const char *name;
4105
4106         MMPLAYER_FENTER();
4107
4108         MMPLAYER_RETURN_IF_FAIL(pad)
4109         MMPLAYER_RETURN_IF_FAIL(unused)
4110         MMPLAYER_RETURN_IF_FAIL(data)
4111
4112         caps = gst_pad_get_current_caps(pad);
4113         if (!caps)
4114                 return;
4115
4116         str = gst_caps_get_structure(caps, 0);
4117         if (!str)
4118                 goto ERROR;
4119
4120         name = gst_structure_get_name(str);
4121         if (!name)
4122                 goto ERROR;
4123
4124         LOGD("name = %s\n", name);
4125
4126         if (strstr(name, "audio")) {
4127                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4128
4129                 if (player->audio_stream_changed_cb) {
4130                         LOGE("call the audio stream changed cb\n");
4131                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4132                 }
4133         } else if (strstr(name, "video")) {
4134                 if ((name = gst_structure_get_string(str, "format")))
4135                         player->set_mode.video_zc = name[0] == 'S';
4136
4137                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4138
4139                 if (player->video_stream_changed_cb) {
4140                         LOGE("call the video stream changed cb\n");
4141                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4142                 }
4143         } else
4144                 goto ERROR;
4145
4146 ERROR:
4147
4148         gst_caps_unref(caps);
4149
4150         MMPLAYER_FLEAVE();
4151
4152         return;
4153 }
4154
4155
4156
4157 /**
4158  * This function is to create audio pipeline for playing.
4159  *
4160  * @param       player          [in]    handle of player
4161  *
4162  * @return      This function returns zero on success.
4163  * @remark
4164  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4165  */
4166 /* macro for code readability. just for sinkbin-creation functions */
4167 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4168 do {\
4169         x_bin[x_id].id = x_id;\
4170         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4171         if (!x_bin[x_id].gst) {\
4172                 LOGE("failed to create %s \n", x_factory);\
4173                 goto ERROR;\
4174         } else {\
4175                 if (x_player->ini.set_dump_element_flag)\
4176                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4177         } \
4178         if (x_add_bucket)\
4179                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4180 } while (0);
4181
4182 static void
4183 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4184 {
4185         GList *l = NULL;
4186
4187         MMPLAYER_FENTER();
4188         MMPLAYER_RETURN_IF_FAIL(player);
4189
4190         if (player->audio_stream_buff_list) {
4191                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4192                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4193                         if (tmp) {
4194                                 if (send_all) {
4195                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4196                                         __mmplayer_audio_stream_send_data(player, tmp);
4197                                 }
4198                                 if (tmp->pcm_data)
4199                                         g_free(tmp->pcm_data);
4200                                 g_free(tmp);
4201                         }
4202                 }
4203                 g_list_free(player->audio_stream_buff_list);
4204                 player->audio_stream_buff_list = NULL;
4205         }
4206
4207         MMPLAYER_FLEAVE();
4208 }
4209
4210 static void
4211 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4212 {
4213         MMPlayerAudioStreamDataType audio_stream = { 0, };
4214
4215         MMPLAYER_FENTER();
4216         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4217
4218         audio_stream.bitrate = a_buffer->bitrate;
4219         audio_stream.channel = a_buffer->channel;
4220         audio_stream.depth = a_buffer->depth;
4221         audio_stream.is_little_endian = a_buffer->is_little_endian;
4222         audio_stream.channel_mask = a_buffer->channel_mask;
4223         audio_stream.data_size = a_buffer->data_size;
4224         audio_stream.data = a_buffer->pcm_data;
4225
4226         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4227         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4228
4229         MMPLAYER_FLEAVE();
4230 }
4231
4232 static void
4233 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4234 {
4235         mm_player_t* player = (mm_player_t*) data;
4236
4237         gint channel = 0;
4238         gint rate = 0;
4239         gint depth = 0;
4240         gint endianness = 0;
4241         guint64 channel_mask = 0;
4242         void *a_data = NULL;
4243         gint a_size = 0;
4244         mm_player_audio_stream_buff_t *a_buffer = NULL;
4245         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4246         GList *l = NULL;
4247
4248         MMPLAYER_FENTER();
4249         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4250
4251         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4252         a_data = mapinfo.data;
4253         a_size = mapinfo.size;
4254
4255         GstCaps *caps = gst_pad_get_current_caps(pad);
4256         GstStructure *structure = gst_caps_get_structure(caps, 0);
4257
4258         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4259         gst_structure_get_int(structure, "rate", &rate);
4260         gst_structure_get_int(structure, "channels", &channel);
4261         gst_structure_get_int(structure, "depth", &depth);
4262         gst_structure_get_int(structure, "endianness", &endianness);
4263         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4264         gst_caps_unref(GST_CAPS(caps));
4265
4266         /* In case of the sync is false, use buffer list.              *
4267          * The num of buffer list depends on the num of audio channels */
4268         if (player->audio_stream_buff_list) {
4269                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4270                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4271                         if (tmp) {
4272                                 if (channel_mask == tmp->channel_mask) {
4273                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4274                                         if (tmp->data_size + a_size < tmp->buff_size) {
4275                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4276                                                 tmp->data_size += a_size;
4277                                         } else {
4278                                                 /* send data to client */
4279                                                 __mmplayer_audio_stream_send_data(player, tmp);
4280
4281                                                 if (a_size > tmp->buff_size) {
4282                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4283                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4284                                                         if (tmp->pcm_data == NULL) {
4285                                                                 LOGE("failed to realloc data.");
4286                                                                 goto DONE;
4287                                                         }
4288                                                         tmp->buff_size = a_size;
4289                                                 }
4290                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4291                                                 memcpy(tmp->pcm_data, a_data, a_size);
4292                                                 tmp->data_size = a_size;
4293                                         }
4294                                         goto DONE;
4295                                 }
4296                         } else {
4297                                 LOGE("data is empty in list.");
4298                                 goto DONE;
4299                         }
4300                 }
4301         }
4302
4303         /* create new audio stream data */
4304         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4305         if (a_buffer == NULL) {
4306                 LOGE("failed to alloc data.");
4307                 goto DONE;
4308         }
4309         a_buffer->bitrate = rate;
4310         a_buffer->channel = channel;
4311         a_buffer->depth = depth;
4312         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4313         a_buffer->channel_mask = channel_mask;
4314         a_buffer->data_size = a_size;
4315
4316         if (!player->audio_stream_sink_sync) {
4317                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4318                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4319                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4320                 if (a_buffer->pcm_data == NULL) {
4321                         LOGE("failed to alloc data.");
4322                         g_free(a_buffer);
4323                         goto DONE;
4324                 }
4325                 memcpy(a_buffer->pcm_data, a_data, a_size);
4326                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4327                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4328         } else {
4329                 /* If sync is TRUE, send data directly. */
4330                 a_buffer->pcm_data = a_data;
4331                 __mmplayer_audio_stream_send_data(player, a_buffer);
4332                 g_free(a_buffer);
4333         }
4334
4335 DONE:
4336         gst_buffer_unmap(buffer, &mapinfo);
4337         MMPLAYER_FLEAVE();
4338 }
4339
4340 static void
4341 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4342 {
4343         mm_player_t* player = (mm_player_t*)data;
4344         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4345         GstPad* sinkpad = NULL;
4346         GstElement *queue = NULL, *sink = NULL;
4347
4348         MMPLAYER_FENTER();
4349         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4350
4351         queue = gst_element_factory_make("queue", NULL);
4352         if (queue == NULL) {
4353                 LOGD("fail make queue\n");
4354                 goto ERROR;
4355         }
4356
4357         sink = gst_element_factory_make("fakesink", NULL);
4358         if (sink == NULL) {
4359                 LOGD("fail make fakesink\n");
4360                 goto ERROR;
4361         }
4362
4363         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4364
4365         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4366                 LOGW("failed to link queue & sink\n");
4367                 goto ERROR;
4368         }
4369
4370         sinkpad = gst_element_get_static_pad(queue, "sink");
4371
4372         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4373                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4374                 goto ERROR;
4375         }
4376
4377         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4378
4379         gst_object_unref(sinkpad);
4380         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4381         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4382
4383         gst_element_set_state(sink, GST_STATE_PAUSED);
4384         gst_element_set_state(queue, GST_STATE_PAUSED);
4385
4386         MMPLAYER_SIGNAL_CONNECT(player,
4387                 G_OBJECT(sink),
4388                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4389                 "handoff",
4390                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4391                 (gpointer)player);
4392
4393         MMPLAYER_FLEAVE();
4394         return;
4395
4396 ERROR:
4397         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4398         if (queue) {
4399                 gst_object_unref(GST_OBJECT(queue));
4400                 queue = NULL;
4401         }
4402         if (sink) {
4403                 gst_object_unref(GST_OBJECT(sink));
4404                 sink = NULL;
4405         }
4406         if (sinkpad) {
4407                 gst_object_unref(GST_OBJECT(sinkpad));
4408                 sinkpad = NULL;
4409         }
4410
4411         return;
4412 }
4413
4414 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4415 {
4416         #define MAX_PROPS_LEN 128
4417         gint latency_mode = 0;
4418         gchar *stream_type = NULL;
4419         gchar *latency = NULL;
4420         gint stream_id = 0;
4421         gchar stream_props[MAX_PROPS_LEN] = {0,};
4422         GstStructure *props = NULL;
4423
4424         /* set volume table
4425          * It should be set after player creation through attribute.
4426          * But, it can not be changed during playing.
4427          */
4428         MMPLAYER_FENTER();
4429         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4430         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4431
4432         if (!stream_type) {
4433                 LOGE("stream_type is null.\n");
4434         } else {
4435                 if (player->sound.focus_id)
4436                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4437                                         stream_type, stream_id, player->sound.focus_id);
4438                 else
4439                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4440                                         stream_type, stream_id);
4441                 props = gst_structure_from_string(stream_props, NULL);
4442                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4443                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4444                         stream_type, stream_id, player->sound.focus_id, stream_props);
4445                 gst_structure_free(props);
4446         }
4447
4448         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4449
4450         switch (latency_mode) {
4451         case AUDIO_LATENCY_MODE_LOW:
4452                 latency = g_strndup("low", 3);
4453                 break;
4454         case AUDIO_LATENCY_MODE_MID:
4455                 latency = g_strndup("mid", 3);
4456                 break;
4457         case AUDIO_LATENCY_MODE_HIGH:
4458                 latency = g_strndup("high", 4);
4459                 break;
4460         };
4461
4462         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4463                         "latency", latency,
4464                         NULL);
4465
4466         LOGD("audiosink property - latency=%s \n", latency);
4467
4468         g_free(latency);
4469
4470         MMPLAYER_FLEAVE();
4471 }
4472
4473 static int
4474 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4475 {
4476         MMPlayerGstElement* first_element = NULL;
4477         MMPlayerGstElement* audiobin = NULL;
4478         MMHandleType attrs = 0;
4479         GstPad *pad = NULL;
4480         GstPad *ghostpad = NULL;
4481         GList* element_bucket = NULL;
4482         gboolean link_audio_sink_now = TRUE;
4483         int i = 0;
4484         GstCaps *acaps;
4485
4486         MMPLAYER_FENTER();
4487
4488         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4489
4490         /* alloc handles */
4491         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4492         if (!audiobin) {
4493                 LOGE("failed to allocate memory for audiobin\n");
4494                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4495         }
4496
4497         attrs = MMPLAYER_GET_ATTRS(player);
4498
4499         /* create bin */
4500         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4501         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4502         if (!audiobin[MMPLAYER_A_BIN].gst) {
4503                 LOGE("failed to create audiobin\n");
4504                 goto ERROR;
4505         }
4506
4507         /* take it */
4508         player->pipeline->audiobin = audiobin;
4509
4510         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4511
4512         /* Adding audiotp plugin for reverse trickplay feature */
4513 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4514
4515         /* converter */
4516         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4517
4518         /* replaygain volume */
4519         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4520         if (player->sound.rg_enable)
4521                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4522         else
4523                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4524
4525         /* resampler */
4526         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4527
4528         if (player->set_mode.pcm_extraction) {
4529                 // pcm extraction only and no sound output
4530                 if (player->audio_stream_render_cb_ex) {
4531                         char *caps_str = NULL;
4532                         GstCaps* caps = NULL;
4533                         gchar *format = NULL;
4534
4535                         /* capsfilter */
4536                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4537
4538                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4539
4540                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4541
4542                         caps = gst_caps_new_simple("audio/x-raw",
4543                                         "format", G_TYPE_STRING, format,
4544                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4545                                         "channels", G_TYPE_INT, player->pcm_channel,
4546                                         NULL);
4547                         caps_str = gst_caps_to_string(caps);
4548                         LOGD("new caps : %s\n", caps_str);
4549
4550                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4551
4552                         /* clean */
4553                         gst_caps_unref(caps);
4554                         MMPLAYER_FREEIF(caps_str);
4555
4556                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4557
4558                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4559                         /* raw pad handling signal */
4560                         MMPLAYER_SIGNAL_CONNECT(player,
4561                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4562                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4563                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4564                 } else {
4565                         int dst_samplerate = 0;
4566                         int dst_channels = 0;
4567                         int dst_depth = 0;
4568                         char *caps_str = NULL;
4569                         GstCaps* caps = NULL;
4570
4571                         /* get conf. values */
4572                         mm_attrs_multiple_get(player->attrs,
4573                                                 NULL,
4574                                                 "pcm_extraction_samplerate", &dst_samplerate,
4575                                                 "pcm_extraction_channels", &dst_channels,
4576                                                 "pcm_extraction_depth", &dst_depth,
4577                                                 NULL);
4578
4579                         /* capsfilter */
4580                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4581                         caps = gst_caps_new_simple("audio/x-raw",
4582                                         "rate", G_TYPE_INT, dst_samplerate,
4583                                         "channels", G_TYPE_INT, dst_channels,
4584                                         "depth", G_TYPE_INT, dst_depth,
4585                                         NULL);
4586                         caps_str = gst_caps_to_string(caps);
4587                         LOGD("new caps : %s\n", caps_str);
4588
4589                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4590
4591                         /* clean */
4592                         gst_caps_unref(caps);
4593                         MMPLAYER_FREEIF(caps_str);
4594
4595                         /* fake sink */
4596                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4597
4598                         /* set sync */
4599                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4600                 }
4601         } else {
4602                 // normal playback
4603                 //GstCaps* caps = NULL;
4604                 gint channels = 0;
4605
4606                 /* for logical volume control */
4607                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4608                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4609
4610                 if (player->sound.mute) {
4611                         LOGD("mute enabled\n");
4612                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4613                 }
4614
4615 #if 0
4616                 /*capsfilter */
4617                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4618                 caps = gst_caps_from_string("audio/x-raw-int, "
4619                                         "endianness = (int) LITTLE_ENDIAN, "
4620                                         "signed = (boolean) true, "
4621                                         "width = (int) 16, "
4622                                         "depth = (int) 16");
4623                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4624                 gst_caps_unref(caps);
4625 #endif
4626
4627                 /* check if multi-channels */
4628                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4629                         GstPad *srcpad = NULL;
4630                         GstCaps *caps = NULL;
4631
4632                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4633                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4634                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4635                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4636                                         if (str)
4637                                                 gst_structure_get_int(str, "channels", &channels);
4638                                         gst_caps_unref(caps);
4639                                 }
4640                                 gst_object_unref(srcpad);
4641                         }
4642                 }
4643
4644                 /* audio effect element. if audio effect is enabled */
4645                 if ((strcmp(player->ini.audioeffect_element, ""))
4646                         && (channels <= 2)
4647                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4648                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4649
4650                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4651
4652                         if ((!player->bypass_audio_effect)
4653                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4654                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4655                                         if (!_mmplayer_audio_effect_custom_apply(player))
4656                                                 LOGI("apply audio effect(custom) setting success\n");
4657                                 }
4658                         }
4659
4660                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4661                                 && (player->set_mode.rich_audio))
4662                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4663                 }
4664
4665                 /* create audio sink */
4666                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4667                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4668                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4669
4670                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4671                 if (player->is_360_feature_enabled &&
4672                         player->is_content_spherical &&
4673                         channels == 4 &&
4674                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4675                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4676                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4677
4678                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4679
4680                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4681
4682                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4683                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4684                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4685                         gst_caps_unref(acaps);
4686
4687                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4688                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4689                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4690                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4691
4692                         player->is_openal_plugin_used = TRUE;
4693
4694                         if (player->video360_yaw_radians <= M_PI &&
4695                                         player->video360_yaw_radians >= -M_PI &&
4696                                         player->video360_pitch_radians <= M_PI_2 &&
4697                                         player->video360_pitch_radians >= -M_PI_2) {
4698                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4699                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4700                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4701                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4702                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4703                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4704                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4705                         }
4706                 } else {
4707                         if (player->is_360_feature_enabled && player->is_content_spherical)
4708                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4709                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4710                 }
4711
4712                 /* qos on */
4713                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4714                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4715
4716
4717                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4718                         (player->videodec_linked && player->ini.use_system_clock)) {
4719                         LOGD("system clock will be used.\n");
4720                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4721                 }
4722
4723                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4724                         __mmplayer_gst_set_audiosink_property(player, attrs);
4725         }
4726
4727         if (audiobin[MMPLAYER_A_SINK].gst) {
4728                 GstPad *sink_pad = NULL;
4729                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4730                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4731                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4732                 gst_object_unref(GST_OBJECT(sink_pad));
4733         }
4734
4735         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4736
4737         /* adding created elements to bin */
4738         LOGD("adding created elements to bin\n");
4739         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4740                 LOGE("failed to add elements\n");
4741                 goto ERROR;
4742         }
4743
4744         /* linking elements in the bucket by added order. */
4745         LOGD("Linking elements in the bucket by added order.\n");
4746         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4747                 LOGE("failed to link elements\n");
4748                 goto ERROR;
4749         }
4750
4751         /* get first element's sinkpad for creating ghostpad */
4752         first_element = (MMPlayerGstElement *)element_bucket->data;
4753         if (!first_element) {
4754                 LOGE("failed to get first elem\n");
4755                 goto ERROR;
4756         }
4757
4758         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4759         if (!pad) {
4760                 LOGE("failed to get pad from first element of audiobin\n");
4761                 goto ERROR;
4762         }
4763
4764         ghostpad = gst_ghost_pad_new("sink", pad);
4765         if (!ghostpad) {
4766                 LOGE("failed to create ghostpad\n");
4767                 goto ERROR;
4768         }
4769
4770         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4771                 LOGE("failed to add ghostpad to audiobin\n");
4772                 goto ERROR;
4773         }
4774
4775         gst_object_unref(pad);
4776
4777         g_list_free(element_bucket);
4778         MMPLAYER_FLEAVE();
4779
4780         return MM_ERROR_NONE;
4781
4782 ERROR:
4783
4784         LOGD("ERROR : releasing audiobin\n");
4785
4786         if (pad)
4787                 gst_object_unref(GST_OBJECT(pad));
4788
4789         if (ghostpad)
4790                 gst_object_unref(GST_OBJECT(ghostpad));
4791
4792         if (element_bucket)
4793                 g_list_free(element_bucket);
4794
4795         /* release element which are not added to bin */
4796         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4797                 /* NOTE : skip bin */
4798                 if (audiobin[i].gst) {
4799                         GstObject* parent = NULL;
4800                         parent = gst_element_get_parent(audiobin[i].gst);
4801
4802                         if (!parent) {
4803                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4804                                 audiobin[i].gst = NULL;
4805                         } else
4806                                 gst_object_unref(GST_OBJECT(parent));
4807                 }
4808         }
4809
4810         /* release audiobin with it's childs */
4811         if (audiobin[MMPLAYER_A_BIN].gst)
4812                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4813
4814         MMPLAYER_FREEIF(audiobin);
4815
4816         player->pipeline->audiobin = NULL;
4817
4818         return MM_ERROR_PLAYER_INTERNAL;
4819 }
4820
4821 static GstPadProbeReturn
4822 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4823 {
4824         mm_player_t* player = (mm_player_t*) u_data;
4825         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4826         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4827
4828         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4829
4830         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4831                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4832
4833         return GST_PAD_PROBE_OK;
4834 }
4835
4836 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4837 {
4838         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4839 }
4840
4841 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4842 {
4843         int ret = MM_ERROR_NONE;
4844         GList *l = NULL;
4845         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4846         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4847
4848         MMPLAYER_VIDEO_BO_LOCK(player);
4849
4850         if (player->video_bo_list) {
4851                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4852                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4853                         if (tmp && tmp->bo == bo) {
4854                                 tmp->using = FALSE;
4855                                 LOGD("release bo %p", bo);
4856                                 tbm_bo_unref(tmp->bo);
4857                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4858                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4859                                 return ret;
4860                         }
4861                 }
4862         } else {
4863                 /* hw codec is running or the list was reset for DRC. */
4864                 LOGW("there is no bo list.");
4865         }
4866         MMPLAYER_VIDEO_BO_UNLOCK(player);
4867
4868         LOGW("failed to find bo %p", bo);
4869         return ret;
4870 }
4871
4872 static void
4873 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4874 {
4875         GList *l = NULL;
4876
4877         MMPLAYER_FENTER();
4878         MMPLAYER_RETURN_IF_FAIL(player);
4879
4880         MMPLAYER_VIDEO_BO_LOCK(player);
4881         if (player->video_bo_list) {
4882                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4883                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4884                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4885                         if (tmp) {
4886                                 if (tmp->bo)
4887                                         tbm_bo_unref(tmp->bo);
4888                                 g_free(tmp);
4889                         }
4890                 }
4891                 g_list_free(player->video_bo_list);
4892                 player->video_bo_list = NULL;
4893         }
4894         player->video_bo_size = 0;
4895         MMPLAYER_VIDEO_BO_UNLOCK(player);
4896
4897         MMPLAYER_FLEAVE();
4898         return;
4899 }
4900
4901 static void*
4902 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4903 {
4904         GList *l = NULL;
4905         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4906         gboolean ret = TRUE;
4907
4908         /* check DRC, if it is, destroy the prev bo list to create again */
4909         if (player->video_bo_size != size) {
4910                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4911                 __mmplayer_video_stream_destroy_bo_list(player);
4912                 player->video_bo_size = size;
4913         }
4914
4915         MMPLAYER_VIDEO_BO_LOCK(player);
4916
4917         if ((!player->video_bo_list) ||
4918                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4919
4920                 /* create bo list */
4921                 int idx = 0;
4922                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4923
4924                 if (player->video_bo_list) {
4925                         /* if bo list did not created all, try it again. */
4926                         idx = g_list_length(player->video_bo_list);
4927                         LOGD("bo list exist(len: %d)", idx);
4928                 }
4929
4930                 for (; idx < player->ini.num_of_video_bo; idx++) {
4931                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4932                         if (!bo_info) {
4933                                 LOGE("Fail to alloc bo_info.");
4934                                 break;
4935                         }
4936                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4937                         if (!bo_info->bo) {
4938                                 LOGE("Fail to tbm_bo_alloc.");
4939                                 g_free(bo_info);
4940                                 break;
4941                         }
4942                         bo_info->using = FALSE;
4943                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4944                 }
4945
4946                 /* update video num buffers */
4947                 player->video_num_buffers = idx;
4948                 if (idx == player->ini.num_of_video_bo)
4949                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4950
4951                 if (idx == 0) {
4952                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4953                         return NULL;
4954                 }
4955
4956                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4957         }
4958
4959         while (TRUE) {
4960                 /* get bo from list*/
4961                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4962                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4963                         if (tmp && (tmp->using == FALSE)) {
4964                                 LOGD("found bo %p to use", tmp->bo);
4965                                 tmp->using = TRUE;
4966                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4967                                 return tbm_bo_ref(tmp->bo);
4968                         }
4969                 }
4970                 if (!ret) {
4971                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4972                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4973                         return NULL;
4974                 }
4975
4976                 if (player->ini.video_bo_timeout <= 0) {
4977                         MMPLAYER_VIDEO_BO_WAIT(player);
4978                 } else {
4979                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4980                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4981                 }
4982                 continue;
4983         }
4984 }
4985
4986 static void
4987 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4988 {
4989         mm_player_t* player = (mm_player_t*)data;
4990         MMPLAYER_FENTER();
4991         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4992
4993         /* send prerolled pkt */
4994         player->video_stream_prerolled = FALSE;
4995
4996         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4997
4998         /* not to send prerolled pkt again */
4999         player->video_stream_prerolled = TRUE;
5000 }
5001
5002 static void
5003 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5004 {
5005         mm_player_t* player = (mm_player_t*)data;
5006         GstCaps *caps = NULL;
5007         MMPlayerVideoStreamDataType *stream = NULL;
5008         MMVideoBuffer *video_buffer = NULL;
5009         GstMemory *dataBlock = NULL;
5010         GstMemory *metaBlock = NULL;
5011         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5012         GstStructure *structure = NULL;
5013         const gchar *string_format = NULL;
5014         unsigned int fourcc = 0;
5015
5016         MMPLAYER_FENTER();
5017         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5018
5019         if (player->video_stream_prerolled) {
5020                 player->video_stream_prerolled = FALSE;
5021                 LOGD("skip the prerolled pkt not to send it again");
5022                 return;
5023         }
5024
5025         caps = gst_pad_get_current_caps(pad);
5026         if (caps == NULL) {
5027                 LOGE("Caps is NULL.");
5028                 return;
5029         }
5030
5031         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5032
5033         /* clear stream data structure */
5034         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5035         if (!stream) {
5036                 LOGE("failed to alloc mem for video data");
5037                 return;
5038         }
5039
5040         structure = gst_caps_get_structure(caps, 0);
5041         gst_structure_get_int(structure, "width", &(stream->width));
5042         gst_structure_get_int(structure, "height", &(stream->height));
5043         string_format = gst_structure_get_string(structure, "format");
5044         if (string_format)
5045                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5046         stream->format = util_get_pixtype(fourcc);
5047         gst_caps_unref(caps);
5048         caps = NULL;
5049
5050     /*
5051         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5052                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5053     */
5054
5055         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5056                 LOGE("Wrong condition!!");
5057                 goto ERROR;
5058         }
5059
5060         /* set size and timestamp */
5061         dataBlock = gst_buffer_peek_memory(buffer, 0);
5062         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5063         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5064
5065         /* check zero-copy */
5066         if (player->set_mode.video_zc &&
5067                 player->set_mode.media_packet_video_stream &&
5068                 gst_buffer_n_memory(buffer) > 1) {
5069                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5070                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5071                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5072         }
5073
5074         if (video_buffer) { /* hw codec */
5075                 /* set tbm bo */
5076                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5077                         int i = 0;
5078
5079                         /* copy pointer of tbm bo, stride, elevation */
5080                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5081                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5082                                 i++;
5083                         }
5084                 } else {
5085                         LOGE("Not support video buffer format");
5086                         goto ERROR;
5087                 }
5088                 memcpy(stream->stride, video_buffer->stride_width,
5089                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5090                 memcpy(stream->elevation, video_buffer->stride_height,
5091                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5092
5093                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5094                 stream->internal_buffer = gst_buffer_ref(buffer);
5095         } else { /* sw codec */
5096                 int i = 0;
5097                 int j = 0;
5098                 int k = 0;
5099                 int ret = TBM_SURFACE_ERROR_NONE;
5100                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5101                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5102                 int size = 0;
5103                 unsigned char *src = NULL;
5104                 unsigned char *dest = NULL;
5105                 tbm_bo_handle thandle;
5106                 tbm_surface_h surface;
5107                 tbm_surface_info_s info;
5108                 gboolean gst_ret;
5109
5110                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5111                 if (!gst_ret) {
5112                         LOGE("fail to gst_memory_map");
5113                         goto ERROR;
5114                 }
5115
5116
5117                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5118                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5119
5120                         ret = tbm_surface_get_info(surface, &info);
5121
5122                         if (ret != TBM_SURFACE_ERROR_NONE) {
5123                                 tbm_surface_destroy(surface);
5124                                 goto ERROR;
5125                         }
5126                         tbm_surface_destroy(surface);
5127
5128                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5129                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5130                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5131                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5132                         stream->stride[0] = info.planes[0].stride;
5133                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5134                         stream->stride[1] = info.planes[1].stride;
5135                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5136                         stream->stride[2] = info.planes[2].stride;
5137                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5138                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5139                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5140                         stream->stride[0] = stream->width * 4;
5141                         stream->elevation[0] = stream->height;
5142                         size = stream->stride[0] * stream->height;
5143                 } else {
5144                         LOGE("Not support format %d", stream->format);
5145                         goto ERROR;
5146                 }
5147
5148                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5149                 if (!stream->bo[0]) {
5150                         LOGE("Fail to tbm_bo_alloc!!");
5151                         goto ERROR;
5152                 }
5153
5154                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5155                 if (thandle.ptr && mapinfo.data) {
5156                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5157                                 for (i = 0; i < 3; i++) {
5158                                         src = mapinfo.data + src_offset[i];
5159                                         dest = thandle.ptr + info.planes[i].offset;
5160
5161                                         if (i > 0) k = 1;
5162                                         for (j = 0; j < stream->height>>k; j++) {
5163                                                 memcpy(dest, src, stream->width>>k);
5164                                                 src += src_stride[i];
5165                                                 dest += stream->stride[i];
5166                                         }
5167                                 }
5168                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5169                                 memcpy(thandle.ptr, mapinfo.data, size);
5170                         } else {
5171                                 LOGE("Not support format %d", stream->format);
5172                                 goto ERROR;
5173                         }
5174                 } else {
5175                         LOGE("data pointer is wrong. dest : %p, src : %p",
5176                                         thandle.ptr, mapinfo.data);
5177                         goto ERROR;
5178                 }
5179                 tbm_bo_unmap(stream->bo[0]);
5180         }
5181
5182         if (player->video_stream_cb) { /* This has been already checked at the entry */
5183                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5184                         LOGE("failed to send video stream data.");
5185                         goto ERROR;
5186                 }
5187         }
5188
5189         if (metaBlock)
5190                 gst_memory_unmap(metaBlock, &mapinfo);
5191         else
5192                 gst_memory_unmap(dataBlock, &mapinfo);
5193
5194         return;
5195
5196 ERROR:
5197         LOGE("release video stream resource.");
5198         if (metaBlock) {
5199                 int i = 0;
5200                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5201                         if (stream->bo[i])
5202                                 tbm_bo_unref(stream->bo[i]);
5203                 }
5204                 gst_memory_unmap(metaBlock, &mapinfo);
5205
5206                 /* unref gst buffer */
5207                 if (stream->internal_buffer)
5208                         gst_buffer_unref(stream->internal_buffer);
5209         } else if (dataBlock) {
5210                 if (stream->bo[0])
5211                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5212                 gst_memory_unmap(dataBlock, &mapinfo);
5213         }
5214
5215         g_free(stream);
5216         return;
5217 }
5218
5219 static int
5220 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5221 {
5222         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5223         GList* element_bucket = NULL;
5224
5225         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5226
5227         MMPLAYER_FENTER();
5228
5229         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5230                 LOGD("do not need to add video filters.");
5231                 return MM_ERROR_NONE;
5232         }
5233
5234         /* in case of sw codec except 360 playback,
5235          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5236         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5237         LOGD("using video converter: %s", video_csc);
5238
5239         /* set video rotator */
5240         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5241
5242         *bucket = element_bucket;
5243         MMPLAYER_FLEAVE();
5244         return MM_ERROR_NONE;
5245
5246 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5247         g_list_free(element_bucket);
5248
5249         *bucket = NULL;
5250         MMPLAYER_FLEAVE();
5251         return MM_ERROR_PLAYER_INTERNAL;
5252 }
5253
5254 /**
5255  * This function is to create video pipeline.
5256  *
5257  * @param       player          [in]    handle of player
5258  *              caps            [in]    src caps of decoder
5259  *              surface_type    [in]    surface type for video rendering
5260  *
5261  * @return      This function returns zero on success.
5262  * @remark
5263  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5264  */
5265 /**
5266   * VIDEO PIPELINE
5267   * - video overlay surface(arm/x86) : tizenwlsink
5268   */
5269 static int
5270 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5271 {
5272         GstPad *pad = NULL;
5273         MMHandleType attrs;
5274         GList*element_bucket = NULL;
5275         MMPlayerGstElement* first_element = NULL;
5276         MMPlayerGstElement* videobin = NULL;
5277         gchar *videosink_element = NULL;
5278
5279         MMPLAYER_FENTER();
5280
5281         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282
5283         /* alloc handles */
5284         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5285         if (!videobin)
5286                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5287
5288         player->pipeline->videobin = videobin;
5289
5290         attrs = MMPLAYER_GET_ATTRS(player);
5291         if (!attrs) {
5292                 LOGE("cannot get content attribute");
5293                 return MM_ERROR_PLAYER_INTERNAL;
5294         }
5295
5296         /* create bin */
5297         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5298         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5299         if (!videobin[MMPLAYER_V_BIN].gst) {
5300                 LOGE("failed to create videobin");
5301                 goto ERROR;
5302         }
5303
5304         int enable_video_decoded_cb = 0;
5305         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5306
5307         if (player->is_360_feature_enabled && player->is_content_spherical) {
5308                 LOGD("video360 elem will be added.");
5309
5310                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5311                                 "video-360", TRUE, player);
5312
5313                 /* Set spatial media metadata and/or user settings to the element.
5314                  * */
5315                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316                                 "projection-type", player->video360_metadata.projection_type, NULL);
5317
5318                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5319                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5320
5321                 if (player->video360_metadata.full_pano_width_pixels &&
5322                                 player->video360_metadata.full_pano_height_pixels &&
5323                                 player->video360_metadata.cropped_area_image_width &&
5324                                 player->video360_metadata.cropped_area_image_height) {
5325                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5326                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5327                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5328                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5329                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5330                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5331                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5332                                         NULL);
5333                 }
5334
5335                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5336                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5337                                         "horizontal-fov", player->video360_horizontal_fov,
5338                                         "vertical-fov", player->video360_vertical_fov, NULL);
5339                 }
5340
5341                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5342                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5343                                         "zoom", 1.0f / player->video360_zoom, NULL);
5344                 }
5345
5346                 if (player->video360_yaw_radians <= M_PI &&
5347                                 player->video360_yaw_radians >= -M_PI &&
5348                                 player->video360_pitch_radians <= M_PI_2 &&
5349                                 player->video360_pitch_radians >= -M_PI_2) {
5350                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5351                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5352                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5353                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5354                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355                                         "pose-yaw", player->video360_metadata.init_view_heading,
5356                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5357                 }
5358
5359                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5360                                 "passthrough", !player->is_video360_enabled, NULL);
5361         }
5362
5363         /* set video sink */
5364         switch (surface_type) {
5365         case MM_DISPLAY_SURFACE_OVERLAY:
5366                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5367                         goto ERROR;
5368                 if (strlen(player->ini.videosink_element_overlay) > 0)
5369                         videosink_element = player->ini.videosink_element_overlay;
5370                 else
5371                         goto ERROR;
5372                 break;
5373         case MM_DISPLAY_SURFACE_NULL:
5374                 if (strlen(player->ini.videosink_element_fake) > 0)
5375                         videosink_element = player->ini.videosink_element_fake;
5376                 else
5377                         goto ERROR;
5378                 break;
5379         case MM_DISPLAY_SURFACE_REMOTE:
5380                 if (strlen(player->ini.videosink_element_fake) > 0)
5381                         videosink_element = player->ini.videosink_element_fake;
5382                 else
5383                         goto ERROR;
5384                 break;
5385         default:
5386                 LOGE("unidentified surface type");
5387                 goto ERROR;
5388         }
5389         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5390
5391         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5392
5393         /* additional setting for sink plug-in */
5394         switch (surface_type) {
5395         case MM_DISPLAY_SURFACE_OVERLAY:
5396         {
5397                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5398                 if (!use_tbm) {
5399                         LOGD("selected videosink name: %s", videosink_element);
5400
5401                         /* support shard memory with S/W codec on HawkP */
5402                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5403                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5404                                         "use-tbm", use_tbm, NULL);
5405                         }
5406                 } else {
5407                         if (attrs) {
5408                                 int gapless = 0;
5409
5410                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5411
5412                                 if (gapless > 0) {
5413                                         LOGD("disable last-sample");
5414                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5415                                 }
5416                         }
5417                 }
5418                 if (player->set_mode.media_packet_video_stream) {
5419                         int enable = 0;
5420                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5421                         if (enable)
5422                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5423
5424                         MMPLAYER_SIGNAL_CONNECT(player,
5425                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5426                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5427                                                                         "handoff",
5428                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5429                                                                         (gpointer)player);
5430
5431                         MMPLAYER_SIGNAL_CONNECT(player,
5432                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5433                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5434                                                                         "preroll-handoff",
5435                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5436                                                                         (gpointer)player);
5437                 }
5438                 break;
5439         }
5440         case MM_DISPLAY_SURFACE_REMOTE:
5441         {
5442                 if (player->set_mode.media_packet_video_stream) {
5443                         LOGE("add data probe at videosink");
5444                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5445                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5446
5447                         MMPLAYER_SIGNAL_CONNECT(player,
5448                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5449                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5450                                                                         "handoff",
5451                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5452                                                                         (gpointer)player);
5453
5454                         MMPLAYER_SIGNAL_CONNECT(player,
5455                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5456                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5457                                                                         "preroll-handoff",
5458                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5459                                                                         (gpointer)player);
5460                         if (attrs) {
5461                                 int gapless = 0;
5462
5463                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5464
5465                                 if (gapless > 0) {
5466                                         LOGD("disable last-sample");
5467                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5468                                 }
5469                         }
5470                 }
5471                 break;
5472         }
5473         default:
5474                 break;
5475         }
5476
5477         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5478                 goto ERROR;
5479
5480         if (videobin[MMPLAYER_V_SINK].gst) {
5481                 GstPad *sink_pad = NULL;
5482                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5483                 if (sink_pad) {
5484                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5485                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5486                         gst_object_unref(GST_OBJECT(sink_pad));
5487                 } else
5488                         LOGW("failed to get sink pad from videosink\n");
5489         }
5490
5491         /* store it as it's sink element */
5492         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5493
5494         /* adding created elements to bin */
5495         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5496                 LOGE("failed to add elements\n");
5497                 goto ERROR;
5498         }
5499
5500         /* Linking elements in the bucket by added order */
5501         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5502                 LOGE("failed to link elements\n");
5503                 goto ERROR;
5504         }
5505
5506         /* get first element's sinkpad for creating ghostpad */
5507         if (element_bucket)
5508                 first_element = (MMPlayerGstElement *)element_bucket->data;
5509         if (!first_element) {
5510                 LOGE("failed to get first element from bucket\n");
5511                 goto ERROR;
5512         }
5513
5514         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5515         if (!pad) {
5516                 LOGE("failed to get pad from first element\n");
5517                 goto ERROR;
5518         }
5519
5520         /* create ghostpad */
5521         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5522         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5523                 LOGE("failed to add ghostpad to videobin\n");
5524                 goto ERROR;
5525         }
5526         gst_object_unref(pad);
5527
5528         /* done. free allocated variables */
5529         if (element_bucket)
5530                 g_list_free(element_bucket);
5531
5532         MMPLAYER_FLEAVE();
5533
5534         return MM_ERROR_NONE;
5535
5536 ERROR:
5537         LOGE("ERROR : releasing videobin\n");
5538
5539         g_list_free(element_bucket);
5540
5541         if (pad)
5542                 gst_object_unref(GST_OBJECT(pad));
5543
5544         /* release videobin with it's childs */
5545         if (videobin[MMPLAYER_V_BIN].gst)
5546                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5547
5548
5549         MMPLAYER_FREEIF(videobin);
5550
5551         player->pipeline->videobin = NULL;
5552
5553         return MM_ERROR_PLAYER_INTERNAL;
5554 }
5555
5556 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5557 {
5558         GList *element_bucket = NULL;
5559         MMPlayerGstElement *textbin = player->pipeline->textbin;
5560
5561         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5562         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5563         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5564                                                         "signal-handoffs", FALSE,
5565                                                         NULL);
5566
5567         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5568         MMPLAYER_SIGNAL_CONNECT(player,
5569                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5570                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5571                                                         "handoff",
5572                                                         G_CALLBACK(__mmplayer_update_subtitle),
5573                                                         (gpointer)player);
5574
5575         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5576         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5577         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5578
5579         if (!player->play_subtitle) {
5580                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5581                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5582         }
5583
5584         /* adding created elements to bin */
5585         LOGD("adding created elements to bin\n");
5586         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5587                 LOGE("failed to add elements\n");
5588                 goto ERROR;
5589         }
5590
5591         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5592         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5593         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5594
5595         /* linking elements in the bucket by added order. */
5596         LOGD("Linking elements in the bucket by added order.\n");
5597         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5598                 LOGE("failed to link elements\n");
5599                 goto ERROR;
5600         }
5601
5602         /* done. free allocated variables */
5603         g_list_free(element_bucket);
5604
5605         if (textbin[MMPLAYER_T_QUEUE].gst) {
5606                 GstPad *pad = NULL;
5607                 GstPad *ghostpad = NULL;
5608
5609                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5610                 if (!pad) {
5611                         LOGE("failed to get sink pad of text queue");
5612                         goto ERROR;
5613                 }
5614
5615                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5616                 gst_object_unref(pad);
5617
5618                 if (!ghostpad) {
5619                         LOGE("failed to create ghostpad of textbin\n");
5620                         goto ERROR;
5621                 }
5622
5623                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5624                         LOGE("failed to add ghostpad to textbin\n");
5625                         gst_object_unref(ghostpad);
5626                         goto ERROR;
5627                 }
5628         }
5629
5630         return MM_ERROR_NONE;
5631
5632 ERROR:
5633         g_list_free(element_bucket);
5634
5635         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5636                 LOGE("remove textbin sink from sink list");
5637                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5638         }
5639
5640         /* release element at __mmplayer_gst_create_text_sink_bin */
5641         return MM_ERROR_PLAYER_INTERNAL;
5642 }
5643
5644 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5645 {
5646         MMPlayerGstElement *textbin = NULL;
5647         GList *element_bucket = NULL;
5648         int surface_type = 0;
5649         gint i = 0;
5650
5651         MMPLAYER_FENTER();
5652
5653         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5654
5655         /* alloc handles */
5656         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5657         if (!textbin) {
5658                 LOGE("failed to allocate memory for textbin\n");
5659                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5660         }
5661
5662         /* create bin */
5663         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5664         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5665         if (!textbin[MMPLAYER_T_BIN].gst) {
5666                 LOGE("failed to create textbin\n");
5667                 goto ERROR;
5668         }
5669
5670         /* take it */
5671         player->pipeline->textbin = textbin;
5672
5673         /* fakesink */
5674         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5675         LOGD("surface type for subtitle : %d", surface_type);
5676         switch (surface_type) {
5677         case MM_DISPLAY_SURFACE_OVERLAY:
5678         case MM_DISPLAY_SURFACE_NULL:
5679         case MM_DISPLAY_SURFACE_REMOTE:
5680                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5681                         LOGE("failed to make plain text elements\n");
5682                         goto ERROR;
5683                 }
5684                 break;
5685         default:
5686                 goto ERROR;
5687                 break;
5688         }
5689
5690         MMPLAYER_FLEAVE();
5691
5692         return MM_ERROR_NONE;
5693
5694 ERROR:
5695
5696         LOGD("ERROR : releasing textbin\n");
5697
5698         g_list_free(element_bucket);
5699
5700         /* release signal */
5701         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5702
5703         /* release element which are not added to bin */
5704         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5705                 /* NOTE : skip bin */
5706                 if (textbin[i].gst) {
5707                         GstObject* parent = NULL;
5708                         parent = gst_element_get_parent(textbin[i].gst);
5709
5710                         if (!parent) {
5711                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5712                                 textbin[i].gst = NULL;
5713                         } else {
5714                                 gst_object_unref(GST_OBJECT(parent));
5715                         }
5716                 }
5717         }
5718
5719         /* release textbin with it's childs */
5720         if (textbin[MMPLAYER_T_BIN].gst)
5721                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5722
5723         MMPLAYER_FREEIF(player->pipeline->textbin);
5724         player->pipeline->textbin = NULL;
5725
5726         MMPLAYER_FLEAVE();
5727         return MM_ERROR_PLAYER_INTERNAL;
5728 }
5729
5730
5731 static int
5732 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5733 {
5734         MMPlayerGstElement* mainbin = NULL;
5735         MMPlayerGstElement* textbin = NULL;
5736         MMHandleType attrs = 0;
5737         GstElement *subsrc = NULL;
5738         GstElement *subparse = NULL;
5739         gchar *subtitle_uri = NULL;
5740         const gchar *charset = NULL;
5741         GstPad *pad = NULL;
5742
5743         MMPLAYER_FENTER();
5744
5745         /* get mainbin */
5746         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5747                                                                 player->pipeline &&
5748                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5749
5750         mainbin = player->pipeline->mainbin;
5751
5752         attrs = MMPLAYER_GET_ATTRS(player);
5753         if (!attrs) {
5754                 LOGE("cannot get content attribute\n");
5755                 return MM_ERROR_PLAYER_INTERNAL;
5756         }
5757
5758         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5759         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5760                 LOGE("subtitle uri is not proper filepath.\n");
5761                 return MM_ERROR_PLAYER_INVALID_URI;
5762         }
5763
5764         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5765                 LOGE("failed to get storage info of subtitle path");
5766                 return MM_ERROR_PLAYER_INVALID_URI;
5767         }
5768
5769         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5770
5771         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5772         player->subtitle_language_list = NULL;
5773         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5774
5775         /* create the subtitle source */
5776         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5777         if (!subsrc) {
5778                 LOGE("failed to create filesrc element\n");
5779                 goto ERROR;
5780         }
5781         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5782
5783         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5784         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5785
5786         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5787                 LOGW("failed to add queue\n");
5788                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5789                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5790                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5791                 goto ERROR;
5792         }
5793
5794         /* subparse */
5795         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5796         if (!subparse) {
5797                 LOGE("failed to create subparse element\n");
5798                 goto ERROR;
5799         }
5800
5801         charset = util_get_charset(subtitle_uri);
5802         if (charset) {
5803                 LOGD("detected charset is %s\n", charset);
5804                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5805         }
5806
5807         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5808         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5809
5810         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5811                 LOGW("failed to add subparse\n");
5812                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5813                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5814                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5815                 goto ERROR;
5816         }
5817
5818         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5819                 LOGW("failed to link subsrc and subparse\n");
5820                 goto ERROR;
5821         }
5822
5823         player->play_subtitle = TRUE;
5824         player->adjust_subtitle_pos = 0;
5825
5826         LOGD("play subtitle using subtitle file\n");
5827
5828         if (player->pipeline->textbin == NULL) {
5829                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5830                         LOGE("failed to create text sink bin. continuing without text\n");
5831                         goto ERROR;
5832                 }
5833
5834                 textbin = player->pipeline->textbin;
5835
5836                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5837                         LOGW("failed to add textbin\n");
5838
5839                         /* release signal */
5840                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5841
5842                         /* release textbin with it's childs */
5843                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5844                         MMPLAYER_FREEIF(player->pipeline->textbin);
5845                         player->pipeline->textbin = textbin = NULL;
5846                         goto ERROR;
5847                 }
5848
5849                 LOGD("link text input selector and textbin ghost pad");
5850
5851                 player->textsink_linked = 1;
5852                 player->external_text_idx = 0;
5853                 LOGI("player->textsink_linked set to 1\n");
5854         } else {
5855                 textbin = player->pipeline->textbin;
5856                 LOGD("text bin has been created. reuse it.");
5857                 player->external_text_idx = 1;
5858         }
5859
5860         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5861                 LOGW("failed to link subparse and textbin\n");
5862                 goto ERROR;
5863         }
5864
5865         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5866         if (!pad) {
5867                 LOGE("failed to get sink pad from textsink to probe data");
5868                 goto ERROR;
5869         }
5870
5871         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5872                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5873
5874         gst_object_unref(pad);
5875         pad = NULL;
5876
5877         /* create dot. for debugging */
5878         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5879         MMPLAYER_FLEAVE();
5880
5881         return MM_ERROR_NONE;
5882
5883 ERROR:
5884         /* release text pipeline resource */
5885         player->textsink_linked = 0;
5886
5887         /* release signal */
5888         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5889
5890         if (player->pipeline->textbin) {
5891                 LOGE("remove textbin");
5892
5893                 /* release textbin with it's childs */
5894                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5895                 MMPLAYER_FREEIF(player->pipeline->textbin);
5896                 player->pipeline->textbin = NULL;
5897
5898         }
5899
5900         /* release subtitle elem */
5901         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5902         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5903
5904         return MM_ERROR_PLAYER_INTERNAL;
5905 }
5906
5907 gboolean
5908 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5909 {
5910         mm_player_t* player = (mm_player_t*) data;
5911         MMMessageParamType msg = {0, };
5912         GstClockTime duration = 0;
5913         gpointer text = NULL;
5914         guint text_size = 0;
5915         gboolean ret = TRUE;
5916         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5917
5918         MMPLAYER_FENTER();
5919
5920         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5921         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5922
5923         if (player->is_subtitle_force_drop) {
5924                 LOGW("subtitle is dropped forcedly.");
5925                 return ret;
5926         }
5927
5928         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5929         text = mapinfo.data;
5930         text_size = mapinfo.size;
5931         duration = GST_BUFFER_DURATION(buffer);
5932
5933         if (player->set_mode.subtitle_off) {
5934                 LOGD("subtitle is OFF.\n");
5935                 return TRUE;
5936         }
5937
5938         if (!text || (text_size == 0)) {
5939                 LOGD("There is no subtitle to be displayed.\n");
5940                 return TRUE;
5941         }
5942
5943         msg.data = (void *) text;
5944         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5945
5946         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5947
5948         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5949         gst_buffer_unmap(buffer, &mapinfo);
5950
5951         MMPLAYER_FLEAVE();
5952
5953         return ret;
5954 }
5955
5956 static GstPadProbeReturn
5957 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5958 {
5959         mm_player_t *player = (mm_player_t *) u_data;
5960         GstClockTime cur_timestamp = 0;
5961         gint64 adjusted_timestamp = 0;
5962         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5963
5964         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5965
5966         if (player->set_mode.subtitle_off) {
5967                 LOGD("subtitle is OFF.\n");
5968                 return TRUE;
5969         }
5970
5971         if (player->adjust_subtitle_pos == 0) {
5972                 LOGD("nothing to do");
5973                 return TRUE;
5974         }
5975
5976         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5977         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5978
5979         if (adjusted_timestamp < 0) {
5980                 LOGD("adjusted_timestamp under zero");
5981                 MMPLAYER_FLEAVE();
5982                 return FALSE;
5983         }
5984
5985         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5986         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5987                                 GST_TIME_ARGS(cur_timestamp),
5988                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5989
5990         return GST_PAD_PROBE_OK;
5991 }
5992 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5993 {
5994         MMPLAYER_FENTER();
5995
5996         /* check player and subtitlebin are created */
5997         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5998         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5999
6000         if (position == 0) {
6001                 LOGD("nothing to do\n");
6002                 MMPLAYER_FLEAVE();
6003                 return MM_ERROR_NONE;
6004         }
6005
6006         switch (format) {
6007         case MM_PLAYER_POS_FORMAT_TIME:
6008                 {
6009                         /* check current postion */
6010                         player->adjust_subtitle_pos = position;
6011
6012                         LOGD("save adjust_subtitle_pos in player") ;
6013                 }
6014                 break;
6015
6016         default:
6017                 {
6018                         LOGW("invalid format.\n");
6019                         MMPLAYER_FLEAVE();
6020                         return MM_ERROR_INVALID_ARGUMENT;
6021                 }
6022         }
6023
6024         MMPLAYER_FLEAVE();
6025
6026         return MM_ERROR_NONE;
6027 }
6028 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6029 {
6030         MMPLAYER_FENTER();
6031         LOGD("adjusting video_pos in player") ;
6032         int current_pos = 0;
6033         /* check player and videobin are created */
6034         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6035         if (!player->pipeline->videobin ||
6036                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6037                 LOGD("no video pipeline or sink is there");
6038                 return MM_ERROR_PLAYER_INVALID_STATE ;
6039         }
6040         if (offset == 0) {
6041                 LOGD("nothing to do\n");
6042                 MMPLAYER_FLEAVE();
6043                 return MM_ERROR_NONE;
6044         }
6045         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6046                 LOGD("failed to get current position");
6047                 return MM_ERROR_PLAYER_INTERNAL;
6048         }
6049         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6050                 LOGD("enter video delay is valid");
6051         } else {
6052                 LOGD("enter video delay is crossing content boundary");
6053                 return MM_ERROR_INVALID_ARGUMENT ;
6054         }
6055         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6056         LOGD("video delay has been done");
6057         MMPLAYER_FLEAVE();
6058
6059         return MM_ERROR_NONE;
6060 }
6061
6062 static void
6063 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6064 {
6065         GstElement *appsrc = element;
6066         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6067         GstBuffer *buffer = NULL;
6068         GstFlowReturn ret = GST_FLOW_OK;
6069         gint len = size;
6070
6071         MMPLAYER_RETURN_IF_FAIL(element);
6072         MMPLAYER_RETURN_IF_FAIL(buf);
6073
6074         buffer = gst_buffer_new();
6075
6076         if (buf->offset >= buf->len) {
6077                 LOGD("call eos appsrc\n");
6078                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6079                 return;
6080         }
6081
6082         if (buf->len - buf->offset < size)
6083                 len = buf->len - buf->offset;
6084
6085         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6086         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6087         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6088
6089         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6090         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6091
6092         buf->offset += len;
6093 }
6094
6095 static gboolean
6096 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6097 {
6098         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6099
6100         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6101
6102         buf->offset  = (int)size;
6103
6104         return TRUE;
6105 }
6106
6107 static GstBusSyncReply
6108 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6109 {
6110         mm_player_t *player = (mm_player_t *)data;
6111         GstBusSyncReply reply = GST_BUS_DROP;
6112
6113         if (!(player->pipeline && player->pipeline->mainbin)) {
6114                 LOGE("player pipeline handle is null");
6115                 return GST_BUS_PASS;
6116         }
6117
6118         if (!__mmplayer_check_useful_message(player, message)) {
6119                 gst_message_unref(message);
6120                 return GST_BUS_DROP;
6121         }
6122
6123         switch (GST_MESSAGE_TYPE(message)) {
6124         case GST_MESSAGE_STATE_CHANGED:
6125                 /* post directly for fast launch */
6126                 if (player->sync_handler) {
6127                         __mmplayer_gst_callback(message, player);
6128                         reply = GST_BUS_DROP;
6129                 } else
6130                         reply = GST_BUS_PASS;
6131                 break;
6132         case GST_MESSAGE_TAG:
6133                 __mmplayer_gst_extract_tag_from_msg(player, message);
6134
6135                 #if 0 // debug
6136                 {
6137                         GstTagList *tags = NULL;
6138
6139                         gst_message_parse_tag(message, &tags);
6140                         if (tags) {
6141                                 LOGE("TAGS received from element \"%s\".\n",
6142                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6143
6144                                 gst_tag_list_foreach(tags, print_tag, NULL);
6145                                 gst_tag_list_free(tags);
6146                                 tags = NULL;
6147                         }
6148                         break;
6149                 }
6150                 #endif
6151                 break;
6152
6153         case GST_MESSAGE_DURATION_CHANGED:
6154                 __mmplayer_gst_handle_duration(player, message);
6155                 break;
6156         case GST_MESSAGE_ASYNC_DONE:
6157                 /* NOTE:Don't call gst_callback directly
6158                  * because previous frame can be showed even though this message is received for seek.
6159                  */
6160         default:
6161                 reply = GST_BUS_PASS;
6162                 break;
6163         }
6164
6165         if (reply == GST_BUS_DROP)
6166                 gst_message_unref(message);
6167
6168         return reply;
6169 }
6170
6171 static gboolean
6172 __mmplayer_gst_create_decoder(mm_player_t *player,
6173                                                                 MMPlayerTrackType track,
6174                                                                 GstPad* srcpad,
6175                                                                 enum MainElementID elemId,
6176                                                                 const gchar* name)
6177 {
6178         gboolean ret = TRUE;
6179         GstPad *sinkpad = NULL;
6180
6181         MMPLAYER_FENTER();
6182
6183         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6184                                                 player->pipeline &&
6185                                                 player->pipeline->mainbin, FALSE);
6186         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6187         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6188         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6189
6190         GstElement *decodebin = NULL;
6191         GstCaps *dec_caps = NULL;
6192
6193         /* create decodebin */
6194         decodebin = gst_element_factory_make("decodebin", name);
6195
6196         if (!decodebin) {
6197                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6198                 ret = FALSE;
6199                 goto ERROR;
6200         }
6201
6202         /* raw pad handling signal */
6203         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6204                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6205
6206         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6207         before looking for any elements that can handle that stream.*/
6208         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6209                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6210
6211         /* This signal is emitted when a element is added to the bin.*/
6212         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6213                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6214
6215         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6216                 LOGE("failed to add new decodebin\n");
6217                 ret = FALSE;
6218                 goto ERROR;
6219         }
6220
6221         dec_caps = gst_pad_query_caps(srcpad, NULL);
6222         if (dec_caps) {
6223                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6224                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6225                 gst_caps_unref(dec_caps);
6226         }
6227
6228         player->pipeline->mainbin[elemId].id = elemId;
6229         player->pipeline->mainbin[elemId].gst = decodebin;
6230
6231         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6232
6233         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6234                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6235                 gst_object_unref(GST_OBJECT(decodebin));
6236         }
6237
6238         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6239                 LOGE("failed to sync second level decodebin state with parent\n");
6240
6241         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6242
6243 ERROR:
6244         if (sinkpad) {
6245                 gst_object_unref(GST_OBJECT(sinkpad));
6246                 sinkpad = NULL;
6247         }
6248         MMPLAYER_FLEAVE();
6249
6250         return ret;
6251 }
6252
6253 /**
6254  * This function is to create  audio or video pipeline for playing.
6255  *
6256  * @param       player          [in]    handle of player
6257  *
6258  * @return      This function returns zero on success.
6259  * @remark
6260  * @see
6261  */
6262 static int
6263 __mmplayer_gst_create_pipeline(mm_player_t* player)
6264 {
6265         GstBus  *bus = NULL;
6266         MMPlayerGstElement *mainbin = NULL;
6267         MMHandleType attrs = 0;
6268         GstElement* element = NULL;
6269         GstElement* elem_src_audio = NULL;
6270         GstElement* elem_src_subtitle = NULL;
6271         GstElement* es_video_queue = NULL;
6272         GstElement* es_audio_queue = NULL;
6273         GstElement* es_subtitle_queue = NULL;
6274         GList* element_bucket = NULL;
6275         gboolean need_state_holder = TRUE;
6276         gint i = 0;
6277 #ifdef SW_CODEC_ONLY
6278         int surface_type = 0;
6279 #endif
6280         MMPLAYER_FENTER();
6281
6282         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6283
6284         /* get profile attribute */
6285         attrs = MMPLAYER_GET_ATTRS(player);
6286         if (!attrs) {
6287                 LOGE("cannot get content attribute\n");
6288                 goto INIT_ERROR;
6289         }
6290
6291         /* create pipeline handles */
6292         if (player->pipeline) {
6293                 LOGW("pipeline should be released before create new one\n");
6294                 goto INIT_ERROR;
6295         }
6296
6297         player->video360_metadata.is_spherical = -1;
6298         player->is_openal_plugin_used = FALSE;
6299
6300         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6301         if (player->pipeline == NULL)
6302                 goto INIT_ERROR;
6303
6304         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6305
6306         /* create mainbin */
6307         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6308         if (mainbin == NULL)
6309                 goto INIT_ERROR;
6310
6311         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6312
6313         /* create pipeline */
6314         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6315         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6316         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6317                 LOGE("failed to create pipeline\n");
6318                 goto INIT_ERROR;
6319         }
6320         player->demux_pad_index = 0;
6321         player->subtitle_language_list = NULL;
6322
6323         player->is_subtitle_force_drop = FALSE;
6324         player->last_multiwin_status = FALSE;
6325
6326         _mmplayer_track_initialize(player);
6327         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6328
6329         /* create source element */
6330         switch (player->profile.uri_type) {
6331         /* rtsp streamming */
6332         case MM_PLAYER_URI_TYPE_URL_RTSP:
6333                 {
6334                         gchar *user_agent;
6335
6336                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6337
6338                         if (!element) {
6339                                 LOGE("failed to create streaming source element\n");
6340                                 break;
6341                         }
6342
6343                         /* make it zero */
6344                         user_agent = NULL;
6345
6346                         /* get attribute */
6347                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6348
6349                         SECURE_LOGD("user_agent : %s\n", user_agent);
6350
6351                         /* setting property to streaming source */
6352                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6353                         if (user_agent)
6354                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6355
6356                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6357                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6358                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6359                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6360                 }
6361                 break;
6362
6363         /* http streaming*/
6364         case MM_PLAYER_URI_TYPE_URL_HTTP:
6365                 {
6366                         gchar *user_agent, *cookies, **cookie_list;
6367                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6368                         user_agent = cookies = NULL;
6369                         cookie_list = NULL;
6370                         gint mode = MM_PLAYER_PD_MODE_NONE;
6371
6372                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6373
6374                         player->pd_mode = mode;
6375
6376                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6377
6378                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6379                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6380                                 if (!element) {
6381                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6382                                         break;
6383                                 }
6384                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6385
6386                                 /* get attribute */
6387                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6388                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6389
6390                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6391                                         LOGD("get timeout from ini\n");
6392                                         http_timeout = player->ini.http_timeout;
6393                                 }
6394
6395                                 /* get attribute */
6396                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6397                                 SECURE_LOGD("cookies : %s\n", cookies);
6398                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6399                                 LOGD("timeout : %d\n",  http_timeout);
6400
6401                                 /* setting property to streaming source */
6402                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6403                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6404                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6405
6406                                 /* parsing cookies */
6407                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6408                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6409                                         g_strfreev(cookie_list);
6410                                 }
6411                                 if (user_agent)
6412                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6413
6414                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6415                                         LOGW("it's dash. and it's still experimental feature.");
6416                         } else {
6417                                 // progressive download
6418                                 gchar* location = NULL;
6419
6420                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6421                                         gchar *path = NULL;
6422
6423                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6424
6425                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6426
6427                                         LOGD("PD Location : %s\n", path);
6428
6429                                         if (path) {
6430                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6431                                                         LOGE("failed to get storage info");
6432                                                         break;
6433                                                 }
6434                                                 player->pd_file_save_path = g_strdup(path);
6435                                         } else {
6436                                                 LOGE("can't find pd location so, it should be set \n");
6437                                                 break;
6438                                         }
6439                                 }
6440
6441                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6442                                 if (!element) {
6443                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6444                                         break;
6445                                 }
6446
6447                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6448                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6449                                 else
6450                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6451                                 g_object_get(element, "location", &location, NULL);
6452                                 LOGD("PD_LOCATION [%s].\n", location);
6453                                 if (location)
6454                                         g_free(location);
6455                         }
6456                 }
6457                 break;
6458
6459         /* file source */
6460         case MM_PLAYER_URI_TYPE_FILE:
6461                 {
6462                         LOGD("using filesrc for 'file://' handler.\n");
6463                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6464                                 LOGE("failed to get storage info");
6465                                 break;
6466                         }
6467
6468                         element = gst_element_factory_make("filesrc", "source");
6469                         if (!element) {
6470                                 LOGE("failed to create filesrc\n");
6471                                 break;
6472                         }
6473
6474                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6475                 }
6476                 break;
6477
6478         case MM_PLAYER_URI_TYPE_SS:
6479                 {
6480                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6481                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6482                         if (!element) {
6483                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6484                                 break;
6485                         }
6486
6487                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6488                                 LOGD("get timeout from ini\n");
6489                                 http_timeout = player->ini.http_timeout;
6490                         }
6491
6492                         /* setting property to streaming source */
6493                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6494                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6495                 }
6496                 break;
6497         case MM_PLAYER_URI_TYPE_MS_BUFF:
6498                 {
6499                         LOGD("MS buff src is selected\n");
6500
6501                         if (player->v_stream_caps) {
6502                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6503                                 if (!element) {
6504                                         LOGF("failed to create video app source element[appsrc].\n");
6505                                         break;
6506                                 }
6507
6508                                 if (player->a_stream_caps) {
6509                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6510                                         if (!elem_src_audio) {
6511                                                 LOGF("failed to create audio app source element[appsrc].\n");
6512                                                 break;
6513                                         }
6514                                 }
6515                         } else if (player->a_stream_caps) {
6516                                 /* no video, only audio pipeline*/
6517                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6518                                 if (!element) {
6519                                         LOGF("failed to create audio app source element[appsrc].\n");
6520                                         break;
6521                                 }
6522                         }
6523
6524                         if (player->s_stream_caps) {
6525                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6526                                 if (!elem_src_subtitle) {
6527                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6528                                         break;
6529                                 }
6530                         }
6531
6532                         LOGD("setting app sources properties.\n");
6533                         LOGD("location : %s\n", player->profile.uri);
6534
6535                         if (player->v_stream_caps && element) {
6536                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6537                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6538                                                                                                 "caps", player->v_stream_caps, NULL);
6539
6540                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6541                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6542                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6544
6545                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6546                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6547                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6548                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6549
6550                                 if (player->a_stream_caps && elem_src_audio) {
6551                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6552                                                                                                                         "caps", player->a_stream_caps, NULL);
6553
6554                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6555                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558
6559                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6560                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6561                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6562                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6563                                 }
6564                         } else if (player->a_stream_caps && element) {
6565                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6566                                                                                                 "caps", player->a_stream_caps, NULL);
6567
6568                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6569                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6570                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6572
6573                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6574                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6575                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6576                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6577                         }
6578
6579                         if (player->s_stream_caps && elem_src_subtitle) {
6580                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6581                                                                                                                  "caps", player->s_stream_caps, NULL);
6582
6583                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6584                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6585                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6587
6588                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6589
6590                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6591                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6592                         }
6593
6594                         if (player->v_stream_caps && element) {
6595                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6596                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6597                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6598                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6599
6600                                 if (player->a_stream_caps && elem_src_audio) {
6601                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6602                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6603                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6604                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6605                                 }
6606                         } else if (player->a_stream_caps && element) {
6607                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6608                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6609                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6610                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6611                         }
6612
6613                         if (player->s_stream_caps && elem_src_subtitle)
6614                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6615                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6616
6617                         need_state_holder = FALSE;
6618
6619                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6620                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6621                                 LOGE("failed to commit\n");
6622                 }
6623                 break;
6624         /* appsrc */
6625         case MM_PLAYER_URI_TYPE_MEM:
6626                 {
6627                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6628
6629                         LOGD("mem src is selected\n");
6630
6631                         element = gst_element_factory_make("appsrc", "mem-source");
6632                         if (!element) {
6633                                 LOGE("failed to create appsrc element\n");
6634                                 break;
6635                         }
6636
6637                         g_object_set(element, "stream-type", stream_type, NULL);
6638                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6639                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6640
6641                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6642                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6643                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6644                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6645                 }
6646                 break;
6647         case MM_PLAYER_URI_TYPE_URL:
6648                 break;
6649
6650         case MM_PLAYER_URI_TYPE_TEMP:
6651                 break;
6652
6653         case MM_PLAYER_URI_TYPE_NONE:
6654         default:
6655                 break;
6656         }
6657
6658         /* check source element is OK */
6659         if (!element) {
6660                 LOGE("no source element was created.\n");
6661                 goto INIT_ERROR;
6662         }
6663
6664         /* take source element */
6665         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6666         mainbin[MMPLAYER_M_SRC].gst = element;
6667         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6668
6669         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6670                 player->streamer = __mm_player_streaming_create();
6671                 __mm_player_streaming_initialize(player->streamer);
6672         }
6673
6674         if (MMPLAYER_IS_HTTP_PD(player)) {
6675                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6676
6677                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6678                 element = gst_element_factory_make("queue2", "queue2");
6679                 if (!element) {
6680                         LOGE("failed to create http streaming buffer element\n");
6681                         goto INIT_ERROR;
6682                 }
6683
6684                 /* take it */
6685                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6686                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6687                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6688
6689                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6690
6691                 player->streamer->is_pd_mode = TRUE;
6692
6693                 __mm_player_streaming_set_queue2(player->streamer,
6694                                 element,
6695                                 TRUE,
6696                                 player->ini.http_max_size_bytes + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6697                                 pre_buffering_time,
6698                                 1.0,
6699                                 player->ini.http_buffering_limit,
6700                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6701                                 NULL,
6702                                 0);
6703         }
6704         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6705                 if (player->v_stream_caps) {
6706                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6707                         if (!es_video_queue) {
6708                                 LOGE("create es_video_queue for es player failed\n");
6709                                 goto INIT_ERROR;
6710                         }
6711                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6712                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6713                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6714                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6715
6716                         /* Adding audio appsrc to bucket */
6717                         if (player->a_stream_caps && elem_src_audio) {
6718                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6719                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6720                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6721
6722                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6723                                 if (!es_audio_queue) {
6724                                         LOGE("create es_audio_queue for es player failed\n");
6725                                         goto INIT_ERROR;
6726                                 }
6727                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6728
6729                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6730                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6731                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6732                         }
6733                 } else if (player->a_stream_caps) {
6734                         /* Only audio stream, no video */
6735                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6736                         if (!es_audio_queue) {
6737                                 LOGE("create es_audio_queue for es player failed\n");
6738                                 goto INIT_ERROR;
6739                         }
6740                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6741                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6742                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6743                 }
6744
6745                 if (player->s_stream_caps && elem_src_subtitle) {
6746                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6747                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6748                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6749
6750                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6751                         if (!es_subtitle_queue) {
6752                                 LOGE("create es_subtitle_queue for es player failed\n");
6753                                 goto INIT_ERROR;
6754                         }
6755                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6756                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6757                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6758                 }
6759         }
6760
6761         /* create autoplugging element if src element is not a rtsp src */
6762         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6763                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6764                 element = NULL;
6765                 enum MainElementID elemId = MMPLAYER_M_NUM;
6766
6767                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6768                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6769                         elemId = MMPLAYER_M_AUTOPLUG;
6770                         element = __mmplayer_create_decodebin(player);
6771                         if (element) {
6772                                 /* default size of mq in decodebin is 2M
6773                                  * but it can cause blocking issue during seeking depends on content. */
6774                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6775                         }
6776                         need_state_holder = FALSE;
6777                 } else {
6778                         elemId = MMPLAYER_M_TYPEFIND;
6779                         element = gst_element_factory_make("typefind", "typefinder");
6780                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6781                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6782                 }
6783
6784
6785                 /* check autoplug element is OK */
6786                 if (!element) {
6787                         LOGE("can not create element(%d)\n", elemId);
6788                         goto INIT_ERROR;
6789                 }
6790
6791                 mainbin[elemId].id = elemId;
6792                 mainbin[elemId].gst = element;
6793
6794                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6795         }
6796
6797         /* add elements to pipeline */
6798         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6799                 LOGE("Failed to add elements to pipeline\n");
6800                 goto INIT_ERROR;
6801         }
6802
6803
6804         /* linking elements in the bucket by added order. */
6805         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6806                 LOGE("Failed to link some elements\n");
6807                 goto INIT_ERROR;
6808         }
6809
6810
6811         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6812         if (need_state_holder) {
6813                 /* create */
6814                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6815                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6816
6817                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6818                         LOGE("fakesink element could not be created\n");
6819                         goto INIT_ERROR;
6820                 }
6821                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6822
6823                 /* take ownership of fakesink. we are reusing it */
6824                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6825
6826                 /* add */
6827                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6828                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6829                         LOGE("failed to add fakesink to bin\n");
6830                         goto INIT_ERROR;
6831                 }
6832         }
6833
6834         /* now we have completed mainbin. take it */
6835         player->pipeline->mainbin = mainbin;
6836
6837         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6838                 GstPad *srcpad = NULL;
6839
6840                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6841                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6842                         if (srcpad) {
6843                                 __mmplayer_gst_create_decoder(player,
6844                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6845                                                                                                 srcpad,
6846                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6847                                                                                                 "video_decodebin");
6848
6849                                 gst_object_unref(GST_OBJECT(srcpad));
6850                                 srcpad = NULL;
6851                         }
6852                 }
6853
6854                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6855                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6856                         if (srcpad) {
6857                                 __mmplayer_gst_create_decoder(player,
6858                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6859                                                                                                 srcpad,
6860                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6861                                                                                                 "audio_decodebin");
6862
6863                                 gst_object_unref(GST_OBJECT(srcpad));
6864                                 srcpad = NULL;
6865                         } // else error
6866                 } //  else error
6867
6868                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6869                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6870         }
6871
6872         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6873         if (__mmplayer_check_subtitle(player)) {
6874                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6875                         LOGE("fail to create text pipeline");
6876         }
6877
6878         /* connect bus callback */
6879         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6880         if (!bus) {
6881                 LOGE("cannot get bus from pipeline.\n");
6882                 goto INIT_ERROR;
6883         }
6884
6885         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6886
6887         player->context.thread_default = g_main_context_get_thread_default();
6888
6889         if (player->context.thread_default == NULL) {
6890                 player->context.thread_default = g_main_context_default();
6891                 LOGD("thread-default context is the global default context");
6892         }
6893         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6894
6895         /* set sync handler to get tag synchronously */
6896         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6897
6898         /* finished */
6899         gst_object_unref(GST_OBJECT(bus));
6900         g_list_free(element_bucket);
6901
6902         /* create gst bus_msb_cb thread */
6903         g_mutex_init(&player->bus_msg_thread_mutex);
6904         g_cond_init(&player->bus_msg_thread_cond);
6905         player->bus_msg_thread_exit = FALSE;
6906         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6907         player->bus_msg_thread =
6908                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6909         if (!player->bus_msg_thread) {
6910                 LOGE("failed to create gst BUS msg thread");
6911                 g_mutex_clear(&player->bus_msg_thread_mutex);
6912                 g_cond_clear(&player->bus_msg_thread_cond);
6913                 goto INIT_ERROR;
6914         }
6915
6916         MMPLAYER_FLEAVE();
6917
6918         return MM_ERROR_NONE;
6919
6920 INIT_ERROR:
6921         __mmplayer_gst_destroy_pipeline(player);
6922         g_list_free(element_bucket);
6923
6924         if (mainbin) {
6925                 /* release element which are not added to bin */
6926                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6927                         /* NOTE : skip pipeline */
6928                         if (mainbin[i].gst) {
6929                                 GstObject* parent = NULL;
6930                                 parent = gst_element_get_parent(mainbin[i].gst);
6931
6932                                 if (!parent) {
6933                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6934                                         mainbin[i].gst = NULL;
6935                                 } else
6936                                         gst_object_unref(GST_OBJECT(parent));
6937                         }
6938                 }
6939
6940                 /* release pipeline with it's childs */
6941                 if (mainbin[MMPLAYER_M_PIPE].gst)
6942                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6943
6944                 MMPLAYER_FREEIF(mainbin);
6945         }
6946
6947         MMPLAYER_FREEIF(player->pipeline);
6948         return MM_ERROR_PLAYER_INTERNAL;
6949 }
6950
6951 static void
6952 __mmplayer_reset_gapless_state(mm_player_t* player)
6953 {
6954         MMPLAYER_FENTER();
6955         MMPLAYER_RETURN_IF_FAIL(player
6956                 && player->pipeline
6957                 && player->pipeline->audiobin
6958                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6959
6960         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6961
6962         MMPLAYER_FLEAVE();
6963         return;
6964 }
6965
6966 static int
6967 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6968 {
6969         gint timeout = 0;
6970         int ret = MM_ERROR_NONE;
6971
6972         MMPLAYER_FENTER();
6973
6974         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6975
6976         /* cleanup stuffs */
6977         MMPLAYER_FREEIF(player->type);
6978         player->have_dynamic_pad = FALSE;
6979         player->no_more_pad = FALSE;
6980         player->num_dynamic_pad = 0;
6981         player->demux_pad_index = 0;
6982         player->use_deinterleave = FALSE;
6983         player->max_audio_channels = 0;
6984         player->video_share_api_delta = 0;
6985         player->video_share_clock_delta = 0;
6986         player->video_hub_download_mode = 0;
6987
6988         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6989         player->subtitle_language_list = NULL;
6990         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6991
6992         __mmplayer_reset_gapless_state(player);
6993
6994         if (player->streamer) {
6995                 __mm_player_streaming_deinitialize(player->streamer);
6996                 __mm_player_streaming_destroy(player->streamer);
6997                 player->streamer = NULL;
6998         }
6999
7000         /* cleanup unlinked mime type */
7001         MMPLAYER_FREEIF(player->unlinked_audio_mime);
7002         MMPLAYER_FREEIF(player->unlinked_video_mime);
7003         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7004
7005         /* cleanup running stuffs */
7006         __mmplayer_cancel_eos_timer(player);
7007
7008         /* cleanup gst stuffs */
7009         if (player->pipeline) {
7010                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7011                 GstTagList* tag_list = player->pipeline->tag_list;
7012
7013                 /* first we need to disconnect all signal hander */
7014                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7015
7016                 if (player->bus_watcher)
7017                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7018                 player->bus_watcher = 0;
7019
7020                 if (mainbin) {
7021                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7022                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7023                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7024                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7025                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7026                         gst_object_unref(bus);
7027
7028                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7029                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7030                         if (ret != MM_ERROR_NONE) {
7031                                 LOGE("fail to change state to NULL\n");
7032                                 return MM_ERROR_PLAYER_INTERNAL;
7033                         }
7034
7035                         LOGW("succeeded in chaning state to NULL\n");
7036
7037                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7038
7039                         /* free fakesink */
7040                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7041                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7042
7043                         /* free avsysaudiosink
7044                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7045                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7046                         */
7047                         MMPLAYER_FREEIF(audiobin);
7048                         MMPLAYER_FREEIF(videobin);
7049                         MMPLAYER_FREEIF(textbin);
7050                         MMPLAYER_FREEIF(mainbin);
7051                 }
7052
7053                 if (tag_list)
7054                         gst_tag_list_free(tag_list);
7055
7056                 MMPLAYER_FREEIF(player->pipeline);
7057         }
7058         MMPLAYER_FREEIF(player->album_art);
7059
7060         if (player->v_stream_caps) {
7061                 gst_caps_unref(player->v_stream_caps);
7062                 player->v_stream_caps = NULL;
7063         }
7064         if (player->a_stream_caps) {
7065                 gst_caps_unref(player->a_stream_caps);
7066                 player->a_stream_caps = NULL;
7067         }
7068
7069         if (player->s_stream_caps) {
7070                 gst_caps_unref(player->s_stream_caps);
7071                 player->s_stream_caps = NULL;
7072         }
7073         _mmplayer_track_destroy(player);
7074
7075         if (player->sink_elements)
7076                 g_list_free(player->sink_elements);
7077         player->sink_elements = NULL;
7078
7079         if (player->bufmgr) {
7080                 tbm_bufmgr_deinit(player->bufmgr);
7081                 player->bufmgr = NULL;
7082         }
7083
7084         LOGW("finished destroy pipeline\n");
7085
7086         MMPLAYER_FLEAVE();
7087
7088         return ret;
7089 }
7090
7091 static int __gst_realize(mm_player_t* player)
7092 {
7093         gint timeout = 0;
7094         int ret = MM_ERROR_NONE;
7095
7096         MMPLAYER_FENTER();
7097
7098         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7099
7100         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7101
7102         ret = __mmplayer_gst_create_pipeline(player);
7103         if (ret) {
7104                 LOGE("failed to create pipeline\n");
7105                 return ret;
7106         }
7107
7108         /* set pipeline state to READY */
7109         /* NOTE : state change to READY must be performed sync. */
7110         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7111         ret = __mmplayer_gst_set_state(player,
7112                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7113
7114         if (ret != MM_ERROR_NONE) {
7115                 /* return error if failed to set state */
7116                 LOGE("failed to set READY state");
7117                 return ret;
7118         }
7119
7120         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7121
7122         /* create dot before error-return. for debugging */
7123         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7124
7125         MMPLAYER_FLEAVE();
7126
7127         return ret;
7128 }
7129
7130 static int __gst_unrealize(mm_player_t* player)
7131 {
7132         int ret = MM_ERROR_NONE;
7133
7134         MMPLAYER_FENTER();
7135
7136         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7137
7138         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7139         MMPLAYER_PRINT_STATE(player);
7140
7141         /* release miscellaneous information */
7142         __mmplayer_release_misc(player);
7143
7144         /* destroy pipeline */
7145         ret = __mmplayer_gst_destroy_pipeline(player);
7146         if (ret != MM_ERROR_NONE) {
7147                 LOGE("failed to destory pipeline\n");
7148                 return ret;
7149         }
7150
7151         /* release miscellaneous information.
7152            these info needs to be released after pipeline is destroyed. */
7153         __mmplayer_release_misc_post(player);
7154
7155         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7156
7157         MMPLAYER_FLEAVE();
7158
7159         return ret;
7160 }
7161
7162 static int __gst_pending_seek(mm_player_t* player)
7163 {
7164         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7165         int ret = MM_ERROR_NONE;
7166
7167         MMPLAYER_FENTER();
7168
7169         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7170
7171         if (!player->pending_seek.is_pending) {
7172                 LOGD("pending seek is not reserved. nothing to do.\n");
7173                 return ret;
7174         }
7175
7176         /* check player state if player could pending seek or not. */
7177         current_state = MMPLAYER_CURRENT_STATE(player);
7178
7179         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7180                 LOGW("try to pending seek in %s state, try next time. \n",
7181                         MMPLAYER_STATE_GET_NAME(current_state));
7182                 return ret;
7183         }
7184
7185         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7186
7187         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7188
7189         if (MM_ERROR_NONE != ret)
7190                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7191
7192         player->pending_seek.is_pending = FALSE;
7193
7194         MMPLAYER_FLEAVE();
7195
7196         return ret;
7197 }
7198
7199 static int __gst_start(mm_player_t* player)
7200 {
7201         gboolean sound_extraction = 0;
7202         int ret = MM_ERROR_NONE;
7203         gboolean async = FALSE;
7204
7205         MMPLAYER_FENTER();
7206
7207         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7208
7209         /* get sound_extraction property */
7210         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7211
7212         /* NOTE : if SetPosition was called before Start. do it now */
7213         /* streaming doesn't support it. so it should be always sync */
7214         /* !!create one more api to check if there is pending seek rather than checking variables */
7215         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7216                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7217                 ret = __gst_pause(player, FALSE);
7218                 if (ret != MM_ERROR_NONE) {
7219                         LOGE("failed to set state to PAUSED for pending seek\n");
7220                         return ret;
7221                 }
7222
7223                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7224
7225                 if (sound_extraction) {
7226                         LOGD("setting pcm extraction\n");
7227
7228                         ret = __mmplayer_set_pcm_extraction(player);
7229                         if (MM_ERROR_NONE != ret) {
7230                                 LOGW("failed to set pcm extraction\n");
7231                                 return ret;
7232                         }
7233                 } else {
7234                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7235                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7236                 }
7237         }
7238
7239         LOGD("current state before doing transition");
7240         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7241         MMPLAYER_PRINT_STATE(player);
7242
7243         /* set pipeline state to PLAYING  */
7244         if (player->es_player_push_mode)
7245                 async = TRUE;
7246         /* set pipeline state to PLAYING  */
7247         ret = __mmplayer_gst_set_state(player,
7248                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7249
7250         if (ret == MM_ERROR_NONE) {
7251                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7252         } else {
7253                 LOGE("failed to set state to PLAYING");
7254                 return ret;
7255         }
7256
7257         /* generating debug info before returning error */
7258         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7259
7260         MMPLAYER_FLEAVE();
7261
7262         return ret;
7263 }
7264
7265 static int __gst_stop(mm_player_t* player)
7266 {
7267         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7268         MMHandleType attrs = 0;
7269         gboolean rewind = FALSE;
7270         gint timeout = 0;
7271         int ret = MM_ERROR_NONE;
7272         gboolean async = FALSE;
7273
7274         MMPLAYER_FENTER();
7275
7276         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7277         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278
7279         LOGD("current state before doing transition");
7280         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7281         MMPLAYER_PRINT_STATE(player);
7282
7283         attrs = MMPLAYER_GET_ATTRS(player);
7284         if (!attrs) {
7285                 LOGE("cannot get content attribute\n");
7286                 return MM_ERROR_PLAYER_INTERNAL;
7287         }
7288
7289         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7290         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7291
7292         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7293                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7294                 rewind = TRUE;
7295
7296         if (player->es_player_push_mode)
7297                 async = TRUE;
7298         /* set gst state */
7299         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7300
7301         /* return if set_state has failed */
7302         if (ret != MM_ERROR_NONE) {
7303                 LOGE("failed to set state.\n");
7304                 return ret;
7305         }
7306
7307         /* rewind */
7308         if (rewind) {
7309                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7310                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7311                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7312                         LOGW("failed to rewind\n");
7313                         ret = MM_ERROR_PLAYER_SEEK;
7314                 }
7315         }
7316
7317         /* initialize */
7318         player->sent_bos = FALSE;
7319
7320         if (player->es_player_push_mode) //for cloudgame
7321                 timeout = 0;
7322
7323         /* wait for seek to complete */
7324         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7325         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7326                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7327         } else {
7328                 LOGE("fail to stop player.\n");
7329                 ret = MM_ERROR_PLAYER_INTERNAL;
7330                 __mmplayer_dump_pipeline_state(player);
7331         }
7332
7333         /* generate dot file if enabled */
7334         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7335
7336         MMPLAYER_FLEAVE();
7337
7338         return ret;
7339 }
7340
7341 int __gst_pause(mm_player_t* player, gboolean async)
7342 {
7343         int ret = MM_ERROR_NONE;
7344
7345         MMPLAYER_FENTER();
7346
7347         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7348         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7349
7350         LOGD("current state before doing transition");
7351         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7352         MMPLAYER_PRINT_STATE(player);
7353
7354         /* set pipeline status to PAUSED */
7355         ret = __mmplayer_gst_set_state(player,
7356                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7357
7358         if (FALSE == async) {
7359                 if (ret != MM_ERROR_NONE) {
7360                         GstMessage *msg = NULL;
7361                         GTimer *timer = NULL;
7362                         gdouble MAX_TIMEOUT_SEC = 3;
7363
7364                         LOGE("failed to set state to PAUSED");
7365
7366                         if (player->msg_posted) {
7367                                 LOGE("error msg is already posted.");
7368                                 return ret;
7369                         }
7370
7371                         timer = g_timer_new();
7372                         g_timer_start(timer);
7373
7374                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7375
7376                         do {
7377                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7378                                 if (msg) {
7379                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7380                                                 GError *error = NULL;
7381
7382                                                 /* parse error code */
7383                                                 gst_message_parse_error(msg, &error, NULL);
7384
7385                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7386                                                         /* Note : the streaming error from the streaming source is handled
7387                                                          *   using __mmplayer_handle_streaming_error.
7388                                                          */
7389                                                         __mmplayer_handle_streaming_error(player, msg);
7390
7391                                                 } else if (error) {
7392                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7393
7394                                                         if (error->domain == GST_STREAM_ERROR)
7395                                                                 ret = __gst_handle_stream_error(player, error, msg);
7396                                                         else if (error->domain == GST_RESOURCE_ERROR)
7397                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7398                                                         else if (error->domain == GST_LIBRARY_ERROR)
7399                                                                 ret = __gst_handle_library_error(player, error->code);
7400                                                         else if (error->domain == GST_CORE_ERROR)
7401                                                                 ret = __gst_handle_core_error(player, error->code);
7402
7403                                                         g_error_free(error);
7404                                                 }
7405                                                 player->msg_posted = TRUE;
7406                                         }
7407                                         gst_message_unref(msg);
7408                                 }
7409                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7410                         /* clean */
7411                         gst_object_unref(bus);
7412                         g_timer_stop(timer);
7413                         g_timer_destroy(timer);
7414
7415                         return ret;
7416
7417                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7418                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7419
7420                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7421
7422                 } else if (ret == MM_ERROR_NONE) {
7423
7424                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7425                 }
7426         }
7427
7428         /* generate dot file before returning error */
7429         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7430
7431         MMPLAYER_FLEAVE();
7432
7433         return ret;
7434 }
7435
7436 int __gst_resume(mm_player_t* player, gboolean async)
7437 {
7438         int ret = MM_ERROR_NONE;
7439         gint timeout = 0;
7440
7441         MMPLAYER_FENTER();
7442
7443         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7444                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7445
7446         LOGD("current state before doing transition");
7447         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7448         MMPLAYER_PRINT_STATE(player);
7449
7450         /* generate dot file before returning error */
7451         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7452
7453         if (async)
7454                 LOGD("do async state transition to PLAYING.\n");
7455
7456         /* set pipeline state to PLAYING */
7457         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7458
7459         ret = __mmplayer_gst_set_state(player,
7460                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7461         if (ret != MM_ERROR_NONE) {
7462                 LOGE("failed to set state to PLAYING\n");
7463                 return ret;
7464         } else {
7465                 if (async == FALSE) {
7466                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7467                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7468                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7469                 }
7470         }
7471
7472         /* generate dot file before returning error */
7473         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7474
7475         MMPLAYER_FLEAVE();
7476
7477         return ret;
7478 }
7479
7480 static int
7481 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7482 {
7483         unsigned long dur_msec = 0;
7484         gint64 dur_nsec = 0;
7485         gint64 pos_nsec = 0;
7486         gboolean ret = TRUE;
7487         gboolean accurated = FALSE;
7488         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7489
7490         MMPLAYER_FENTER();
7491         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7492         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7493
7494         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7495                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7496                 goto PENDING;
7497
7498         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7499                 /* check duration */
7500                 /* NOTE : duration cannot be zero except live streaming.
7501                  *              Since some element could have some timing problemn with quering duration, try again.
7502                  */
7503                 if (!player->duration) {
7504                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7505                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7506                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7507                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7508                                         player->pending_seek.is_pending = TRUE;
7509                                         player->pending_seek.format = format;
7510                                         player->pending_seek.pos = position;
7511                                         player->doing_seek = FALSE;
7512                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7513                                         return MM_ERROR_NONE;
7514                                 } else {
7515                                         goto SEEK_ERROR;
7516                                 }
7517                         }
7518                         player->duration = dur_nsec;
7519                 }
7520
7521                 if (player->duration) {
7522                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7523                 } else {
7524                         LOGE("could not get the duration. fail to seek.\n");
7525                         goto SEEK_ERROR;
7526                 }
7527         }
7528         LOGD("playback rate: %f\n", player->playback_rate);
7529
7530         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7531         if (accurated)
7532                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7533         else
7534                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7535
7536         /* do seek */
7537         switch (format) {
7538         case MM_PLAYER_POS_FORMAT_TIME:
7539         {
7540                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7541                         GstQuery *query = NULL;
7542                         gboolean seekable = FALSE;
7543
7544                         /* check position is valid or not */
7545                         if (position > dur_msec)
7546                                 goto INVALID_ARGS;
7547
7548                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7549                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7550                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7551                                 gst_query_unref(query);
7552
7553                                 if (!seekable) {
7554                                         LOGW("non-seekable content");
7555                                         player->doing_seek = FALSE;
7556                                         return MM_ERROR_PLAYER_NO_OP;
7557                                 }
7558                         } else {
7559                                 LOGW("failed to get seeking query");
7560                                 gst_query_unref(query); /* keep seeking operation */
7561                         }
7562
7563                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7564
7565                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7566                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7567                            This causes problem is position calculation during normal pause resume scenarios also.
7568                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7569                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7570                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7571                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7572                                         LOGW("getting current position failed in seek\n");
7573
7574                                 player->last_position = pos_nsec;
7575                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7576                         }
7577
7578                         if (player->doing_seek) {
7579                                 LOGD("not completed seek");
7580                                 return MM_ERROR_PLAYER_DOING_SEEK;
7581                         }
7582                 }
7583
7584                 if (!internal_called)
7585                         player->doing_seek = TRUE;
7586
7587                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7588
7589                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7590                         gint64 cur_time = 0;
7591
7592                         /* get current position */
7593                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7594
7595                         /* flush */
7596                         GstEvent *event = gst_event_new_seek(1.0,
7597                                                         GST_FORMAT_TIME,
7598                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7599                                                         GST_SEEK_TYPE_SET, cur_time,
7600                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7601                         if (event)
7602                                 __gst_send_event_to_sink(player, event);
7603
7604                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7605                                 __gst_pause(player, FALSE);
7606                 }
7607
7608                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7609                         that's why set position through property. */
7610                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7611                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7612                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7613                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7614
7615                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7616                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7617                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7618                         player->doing_seek = FALSE;
7619                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7620                 } else {
7621                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7622                                                         GST_FORMAT_TIME, seek_flags,
7623                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7624                 }
7625
7626                 if (!ret) {
7627                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7628                         goto SEEK_ERROR;
7629                 }
7630         }
7631         break;
7632
7633         case MM_PLAYER_POS_FORMAT_PERCENT:
7634         {
7635                 LOGD("seeking to(%lu)%% \n", position);
7636
7637                 if (player->doing_seek) {
7638                         LOGD("not completed seek");
7639                         return MM_ERROR_PLAYER_DOING_SEEK;
7640                 }
7641
7642                 if (!internal_called)
7643                         player->doing_seek = TRUE;
7644
7645                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7646                 pos_nsec = (gint64)((position * player->duration) / 100);
7647                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7648                                                 GST_FORMAT_TIME, seek_flags,
7649                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7650                 if (!ret) {
7651                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7652                         goto SEEK_ERROR;
7653                 }
7654         }
7655         break;
7656
7657         default:
7658                 goto INVALID_ARGS;
7659         }
7660
7661         /* NOTE : store last seeking point to overcome some bad operation
7662           *     (returning zero when getting current position) of some elements
7663           */
7664         player->last_position = pos_nsec;
7665
7666         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7667         if (player->playback_rate > 1.0)
7668                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7669
7670         MMPLAYER_FLEAVE();
7671         return MM_ERROR_NONE;
7672
7673 PENDING:
7674         player->pending_seek.is_pending = TRUE;
7675         player->pending_seek.format = format;
7676         player->pending_seek.pos = position;
7677
7678         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7679                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7680
7681         return MM_ERROR_NONE;
7682
7683 INVALID_ARGS:
7684         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7685         return MM_ERROR_INVALID_ARGUMENT;
7686
7687 SEEK_ERROR:
7688         player->doing_seek = FALSE;
7689         return MM_ERROR_PLAYER_SEEK;
7690 }
7691
7692 #define TRICKPLAY_OFFSET GST_MSECOND
7693
7694 static int
7695 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7696 {
7697         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7698         gint64 pos_msec = 0;
7699         gboolean ret = TRUE;
7700
7701         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7702                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7703
7704         current_state = MMPLAYER_CURRENT_STATE(player);
7705
7706         /* NOTE : query position except paused state to overcome some bad operation
7707          * please refer to below comments in details
7708          */
7709         if (current_state != MM_PLAYER_STATE_PAUSED)
7710                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7711
7712         /* NOTE : get last point to overcome some bad operation of some elements
7713          *(returning zero when getting current position in paused state
7714          * and when failed to get postion during seeking
7715          */
7716         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7717                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7718
7719                 if (player->playback_rate < 0.0)
7720                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7721                 else
7722                         pos_msec = player->last_position;
7723
7724                 if (!ret)
7725                         pos_msec = player->last_position;
7726                 else
7727                         player->last_position = pos_msec;
7728
7729                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7730
7731         } else {
7732                 if (player->duration > 0 && pos_msec > player->duration)
7733                         pos_msec = player->duration;
7734
7735                 player->last_position = pos_msec;
7736         }
7737
7738         switch (format) {
7739         case MM_PLAYER_POS_FORMAT_TIME:
7740                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7741                 break;
7742
7743         case MM_PLAYER_POS_FORMAT_PERCENT:
7744         {
7745                 if (player->duration <= 0) {
7746                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7747                         *position = 0;
7748                 } else {
7749                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7750                         *position = pos_msec * 100 / player->duration;
7751                 }
7752                 break;
7753         }
7754         default:
7755                 return MM_ERROR_PLAYER_INTERNAL;
7756         }
7757
7758         return MM_ERROR_NONE;
7759 }
7760
7761
7762 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7763 {
7764 #define STREAMING_IS_FINISHED   0
7765 #define BUFFERING_MAX_PER       100
7766 #define DEFAULT_PER_VALUE       -1
7767 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7768
7769         MMPlayerGstElement *mainbin = NULL;
7770         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7771         gint64 buffered_total = 0;
7772         unsigned long position = 0;
7773         gint buffered_sec = -1;
7774         GstBufferingMode mode = GST_BUFFERING_STREAM;
7775         gint64 content_size_time = player->duration;
7776         guint64 content_size_bytes = player->http_content_size;
7777
7778         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7779                                                 player->pipeline &&
7780                                                 player->pipeline->mainbin,
7781                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7782
7783         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7784
7785         *start_pos = 0;
7786         *stop_pos = 0;
7787
7788         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7789                 /* and rtsp is not ready yet. */
7790                 LOGW("it's only used for http streaming case.\n");
7791                 return MM_ERROR_PLAYER_NO_OP;
7792         }
7793
7794         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7795                 LOGW("Time format is not supported yet.\n");
7796                 return MM_ERROR_INVALID_ARGUMENT;
7797         }
7798
7799         if (content_size_time <= 0 || content_size_bytes <= 0) {
7800                 LOGW("there is no content size.");
7801                 return MM_ERROR_NONE;
7802         }
7803
7804         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7805                 LOGW("fail to get current position.");
7806                 return MM_ERROR_NONE;
7807         }
7808
7809         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7810                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7811
7812         mainbin = player->pipeline->mainbin;
7813         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7814
7815         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7816                 GstQuery *query = NULL;
7817                 gint byte_in_rate = 0, byte_out_rate = 0;
7818                 gint64 estimated_total = 0;
7819
7820                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7821                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7822                         LOGW("fail to get buffering query from queue2");
7823                         if (query)
7824                                 gst_query_unref(query);
7825                         return MM_ERROR_NONE;
7826                 }
7827
7828                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7829                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7830
7831                 if (mode == GST_BUFFERING_STREAM) {
7832                         /* using only queue in case of push mode(ts / mp3) */
7833                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7834                                 GST_FORMAT_BYTES, &buffered_total)) {
7835                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7836                                 stop_per = 100 * buffered_total / content_size_bytes;
7837                         }
7838                 } else {
7839                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7840                         guint idx = 0;
7841                         guint num_of_ranges = 0;
7842                         gint64 start_byte = 0, stop_byte = 0;
7843
7844                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7845                         if (estimated_total != STREAMING_IS_FINISHED) {
7846                                 /* buffered size info from queue2 */
7847                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7848                                 for (idx = 0; idx < num_of_ranges; idx++) {
7849                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7850                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7851
7852                                         buffered_total += (stop_byte - start_byte);
7853                                 }
7854                         } else
7855                                 stop_per = BUFFERING_MAX_PER;
7856                 }
7857                 gst_query_unref(query);
7858         }
7859
7860         if (stop_per == DEFAULT_PER_VALUE) {
7861                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7862                 if (dur_sec > 0) {
7863                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7864
7865                         /* buffered size info from multiqueue */
7866                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7867                                 guint curr_size_bytes = 0;
7868                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7869                                         "curr-size-bytes", &curr_size_bytes, NULL);
7870                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7871                                 buffered_total += curr_size_bytes;
7872                         }
7873
7874                         if (avg_byterate > 0)
7875                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7876                         else if (player->total_maximum_bitrate > 0)
7877                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7878                         else if (player->total_bitrate > 0)
7879                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7880
7881                         if (buffered_sec >= 0)
7882                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7883                 }
7884         }
7885
7886         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7887         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7888
7889         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7890                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7891
7892         return MM_ERROR_NONE;
7893 }
7894
7895 static int
7896 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7897 {
7898         MMPLAYER_FENTER();
7899
7900         if (!player) {
7901                 LOGW("set_message_callback is called with invalid player handle\n");
7902                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7903         }
7904
7905         player->msg_cb = callback;
7906         player->msg_cb_param = user_param;
7907
7908         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7909
7910         MMPLAYER_FLEAVE();
7911
7912         return MM_ERROR_NONE;
7913 }
7914
7915 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7916 {
7917         int ret = MM_ERROR_PLAYER_INVALID_URI;
7918         char *path = NULL;
7919
7920         MMPLAYER_FENTER();
7921
7922         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7923         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7924         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7925
7926         memset(data, 0, sizeof(MMPlayerParseProfile));
7927
7928         if ((path = strstr(uri, "es_buff://"))) {
7929                 if (strlen(path)) {
7930                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7931                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7932                         ret = MM_ERROR_NONE;
7933                 }
7934         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7935                 if (strlen(path)) {
7936                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7937                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7938                         ret = MM_ERROR_NONE;
7939                 }
7940         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7941                 if (strlen(path)) {
7942                         gchar *tmp = NULL;
7943                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7944                         tmp = g_ascii_strdown(uri, strlen(uri));
7945
7946                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7947                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7948                         else
7949                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7950
7951                         ret = MM_ERROR_NONE;
7952                         g_free(tmp);
7953                 }
7954         } else if ((path = strstr(uri, "rtspu://"))) {
7955                 if (strlen(path)) {
7956                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7957                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958                         ret = MM_ERROR_NONE;
7959                 }
7960         } else if ((path = strstr(uri, "rtspr://"))) {
7961                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7962                 char *separater = strstr(path, "*");
7963
7964                 if (separater) {
7965                         int urgent_len = 0;
7966                         char *urgent = separater + strlen("*");
7967
7968                         if ((urgent_len = strlen(urgent))) {
7969                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7970                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7971                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7972                                 ret = MM_ERROR_NONE;
7973                         }
7974                 }
7975         } else if ((path = strstr(uri, "mms://"))) {
7976                 if (strlen(path)) {
7977                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7978                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7979                         ret = MM_ERROR_NONE;
7980                 }
7981         } else if ((path = strstr(uri, "mem://"))) {
7982                 if (strlen(path)) {
7983                         int mem_size = 0;
7984                         char *buffer = NULL;
7985                         char *seperator = strchr(path, ',');
7986                         char ext[100] = {0,}, size[100] = {0,};
7987
7988                         if (seperator) {
7989                                 if ((buffer = strstr(path, "ext="))) {
7990                                         buffer += strlen("ext=");
7991
7992                                         if (strlen(buffer)) {
7993                                                 strncpy(ext, buffer, 99);
7994
7995                                                 if ((seperator = strchr(ext, ','))
7996                                                         || (seperator = strchr(ext, ' '))
7997                                                         || (seperator = strchr(ext, '\0'))) {
7998                                                         seperator[0] = '\0';
7999                                                 }
8000                                         }
8001                                 }
8002
8003                                 if ((buffer = strstr(path, "size="))) {
8004                                         buffer += strlen("size=");
8005
8006                                         if (strlen(buffer) > 0) {
8007                                                 strncpy(size, buffer, 99);
8008
8009                                                 if ((seperator = strchr(size, ','))
8010                                                         || (seperator = strchr(size, ' '))
8011                                                         || (seperator = strchr(size, '\0'))) {
8012                                                         seperator[0] = '\0';
8013                                                 }
8014
8015                                                 mem_size = atoi(size);
8016                                         }
8017                                 }
8018                         }
8019
8020                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8021                         if (mem_size && param) {
8022                                 if (data->input_mem.buf)
8023                                         free(data->input_mem.buf);
8024                                 data->input_mem.buf = malloc(mem_size);
8025
8026                                 if (data->input_mem.buf) {
8027                                         memcpy(data->input_mem.buf, param, mem_size);
8028                                         data->input_mem.len = mem_size;
8029                                         ret = MM_ERROR_NONE;
8030                                 } else {
8031                                         LOGE("failed to alloc mem %d", mem_size);
8032                                         ret = MM_ERROR_PLAYER_INTERNAL;
8033                                 }
8034
8035                                 data->input_mem.offset = 0;
8036                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8037                         }
8038                 }
8039         } else {
8040                 gchar *location = NULL;
8041                 GError *err = NULL;
8042
8043                 if ((path = strstr(uri, "file://"))) {
8044
8045                         location = g_filename_from_uri(uri, NULL, &err);
8046
8047                         if (!location || (err != NULL)) {
8048                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8049                                  (err != NULL) ? err->message : "unknown error");
8050
8051                           if (err) g_error_free(err);
8052                           if (location) g_free(location);
8053
8054                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8055                           goto exit;
8056                         }
8057
8058                         LOGD("path from uri: %s", location);
8059                 }
8060
8061                 path = (location != NULL) ? (location) : ((char*)uri);
8062                 int file_stat = MM_ERROR_NONE;
8063
8064                 file_stat = util_exist_file_path(path);
8065
8066                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8067                 if (file_stat == MM_ERROR_NONE) {
8068                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8069
8070                         if (util_is_sdp_file(path)) {
8071                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8072                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8073                         } else {
8074                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8075                         }
8076                         ret = MM_ERROR_NONE;
8077                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8078                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8079                 } else {
8080                         LOGE("invalid uri, could not play..\n");
8081                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8082                 }
8083
8084                 if (location) g_free(location);
8085         }
8086
8087 exit:
8088         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8089                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8090         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8091                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8092
8093         /* dump parse result */
8094         SECURE_LOGW("incomming uri : %s\n", uri);
8095         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8096                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8097
8098         MMPLAYER_FLEAVE();
8099
8100         return ret;
8101 }
8102
8103 gboolean
8104 __mmplayer_can_do_interrupt(mm_player_t *player)
8105 {
8106         if (!player || !player->pipeline || !player->attrs) {
8107                 LOGW("not initialized");
8108                 goto FAILED;
8109         }
8110
8111         if (player->set_mode.pcm_extraction) {
8112                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8113                 goto FAILED;
8114         }
8115
8116         /* check if seeking */
8117         if (player->doing_seek) {
8118                 MMMessageParamType msg_param;
8119                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8120                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8121                 player->doing_seek = FALSE;
8122                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8123                 goto FAILED;
8124         }
8125
8126         /* check other thread */
8127         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8128                 LOGW("locked already, cmd state : %d", player->cmd);
8129
8130                 /* check application command */
8131                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8132                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8133
8134                         /* lock will be released at mrp_resource_release_cb() */
8135                         MMPLAYER_CMD_LOCK(player);
8136                         goto INTERRUPT;
8137                 }
8138                 LOGW("nothing to do");
8139                 goto FAILED;
8140         } else {
8141                 LOGW("can interrupt immediately");
8142                 goto INTERRUPT;
8143         }
8144
8145 FAILED:    /* with CMD UNLOCKED */
8146         return FALSE;
8147
8148 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8149         return TRUE;
8150 }
8151
8152 static int
8153 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8154                 void *user_data)
8155 {
8156         mm_player_t *player = NULL;
8157
8158         MMPLAYER_FENTER();
8159
8160         if (user_data == NULL) {
8161                 LOGE("- user_data is null\n");
8162                 return FALSE;
8163         }
8164         player = (mm_player_t *)user_data;
8165
8166         /* do something to release resource here.
8167          * player stop and interrupt forwarding */
8168         if (!__mmplayer_can_do_interrupt(player)) {
8169                 LOGW("no need to interrupt, so leave");
8170         } else {
8171                 MMMessageParamType msg = {0, };
8172                 unsigned long pos = 0;
8173
8174                 player->interrupted_by_resource = TRUE;
8175
8176                 /* get last play position */
8177                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8178                         LOGW("failed to get play position.");
8179                 } else {
8180                         msg.union_type = MM_MSG_UNION_TIME;
8181                         msg.time.elapsed = (unsigned int)pos;
8182                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8183                 }
8184                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8185                 if (_mmplayer_unrealize((MMHandleType)player))
8186                         LOGW("failed to unrealize");
8187
8188                 /* lock is called in __mmplayer_can_do_interrupt() */
8189                 MMPLAYER_CMD_UNLOCK(player);
8190         }
8191
8192         if (res == player->video_overlay_resource)
8193                 player->video_overlay_resource = FALSE;
8194         else
8195                 player->video_decoder_resource = FALSE;
8196
8197         MMPLAYER_FLEAVE();
8198
8199         return FALSE;
8200 }
8201
8202 int
8203 _mmplayer_create_player(MMHandleType handle)
8204 {
8205         int ret = MM_ERROR_PLAYER_INTERNAL;
8206         bool enabled = false;
8207
8208         mm_player_t* player = MM_PLAYER_CAST(handle);
8209
8210         MMPLAYER_FENTER();
8211
8212         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8213
8214         /* initialize player state */
8215         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8216         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8217         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8218         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8219
8220         /* check current state */
8221         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8222
8223         /* construct attributes */
8224         player->attrs = _mmplayer_construct_attribute(handle);
8225
8226         if (!player->attrs) {
8227                 LOGE("Failed to construct attributes\n");
8228                 return ret;
8229         }
8230
8231         /* initialize gstreamer with configured parameter */
8232         if (!__mmplayer_init_gstreamer(player)) {
8233                 LOGE("Initializing gstreamer failed\n");
8234                 _mmplayer_deconstruct_attribute(handle);
8235                 return ret;
8236         }
8237
8238         /* create lock. note that g_tread_init() has already called in gst_init() */
8239         g_mutex_init(&player->fsink_lock);
8240
8241         /* create update tag lock */
8242         g_mutex_init(&player->update_tag_lock);
8243
8244         /* create next play mutex */
8245         g_mutex_init(&player->next_play_thread_mutex);
8246
8247         /* create next play cond */
8248         g_cond_init(&player->next_play_thread_cond);
8249
8250         /* create next play thread */
8251         player->next_play_thread =
8252                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8253         if (!player->next_play_thread) {
8254                 LOGE("failed to create next play thread");
8255                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8256                 g_mutex_clear(&player->next_play_thread_mutex);
8257                 g_cond_clear(&player->next_play_thread_cond);
8258                 goto ERROR;
8259         }
8260
8261         player->bus_msg_q = g_queue_new();
8262         if (!player->bus_msg_q) {
8263                 LOGE("failed to create queue for bus_msg");
8264                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8265                 goto ERROR;
8266         }
8267
8268         ret = _mmplayer_initialize_video_capture(player);
8269         if (ret != MM_ERROR_NONE) {
8270                 LOGE("failed to initialize video capture\n");
8271                 goto ERROR;
8272         }
8273
8274         /* initialize resource manager */
8275         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8276                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8277                         &player->resource_manager)) {
8278                 LOGE("failed to initialize resource manager\n");
8279                 goto ERROR;
8280         }
8281
8282         if (MMPLAYER_IS_HTTP_PD(player)) {
8283                 player->pd_downloader = NULL;
8284                 player->pd_file_save_path = NULL;
8285         }
8286
8287         /* create video bo lock and cond */
8288         g_mutex_init(&player->video_bo_mutex);
8289         g_cond_init(&player->video_bo_cond);
8290
8291         /* create media stream callback mutex */
8292         g_mutex_init(&player->media_stream_cb_lock);
8293
8294         /* create subtitle info lock and cond */
8295         g_mutex_init(&player->subtitle_info_mutex);
8296         g_cond_init(&player->subtitle_info_cond);
8297
8298         player->streaming_type = STREAMING_SERVICE_NONE;
8299
8300         /* give default value of audio effect setting */
8301         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8302         player->sound.rg_enable = false;
8303         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8304
8305         player->play_subtitle = FALSE;
8306         player->use_deinterleave = FALSE;
8307         player->max_audio_channels = 0;
8308         player->video_share_api_delta = 0;
8309         player->video_share_clock_delta = 0;
8310         player->has_closed_caption = FALSE;
8311         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8312         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8313         player->pending_resume = FALSE;
8314         if (player->ini.dump_element_keyword[0][0] == '\0')
8315                 player->ini.set_dump_element_flag = FALSE;
8316         else
8317                 player->ini.set_dump_element_flag = TRUE;
8318
8319         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8320         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8321         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8322
8323         /* Set video360 settings to their defaults for just-created player.
8324          * */
8325
8326         player->is_360_feature_enabled = FALSE;
8327         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8328                 LOGI("spherical feature info: %d", enabled);
8329                 if (enabled)
8330                         player->is_360_feature_enabled = TRUE;
8331         } else {
8332                 LOGE("failed to get spherical feature info");
8333         }
8334
8335         player->is_content_spherical = FALSE;
8336         player->is_video360_enabled = TRUE;
8337         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8338         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8339         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8340         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8341         player->video360_zoom = 1.0f;
8342         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8343         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8344
8345         /* set player state to null */
8346         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8347         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8348
8349         return MM_ERROR_NONE;
8350
8351 ERROR:
8352         /* free lock */
8353         g_mutex_clear(&player->fsink_lock);
8354
8355         /* free update tag lock */
8356         g_mutex_clear(&player->update_tag_lock);
8357
8358         g_queue_free(player->bus_msg_q);
8359
8360         /* free next play thread */
8361         if (player->next_play_thread) {
8362                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8363                 player->next_play_thread_exit = TRUE;
8364                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8365                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8366
8367                 g_thread_join(player->next_play_thread);
8368                 player->next_play_thread = NULL;
8369
8370                 g_mutex_clear(&player->next_play_thread_mutex);
8371                 g_cond_clear(&player->next_play_thread_cond);
8372         }
8373
8374         /* release attributes */
8375         _mmplayer_deconstruct_attribute(handle);
8376
8377         MMPLAYER_FLEAVE();
8378
8379         return ret;
8380 }
8381
8382 static gboolean
8383 __mmplayer_init_gstreamer(mm_player_t* player)
8384 {
8385         static gboolean initialized = FALSE;
8386         static const int max_argc = 50;
8387         gint* argc = NULL;
8388         gchar** argv = NULL;
8389         gchar** argv2 = NULL;
8390         GError *err = NULL;
8391         int i = 0;
8392         int arg_count = 0;
8393
8394         if (initialized) {
8395                 LOGD("gstreamer already initialized.\n");
8396                 return TRUE;
8397         }
8398
8399         /* alloc */
8400         argc = malloc(sizeof(int));
8401         argv = malloc(sizeof(gchar*) * max_argc);
8402         argv2 = malloc(sizeof(gchar*) * max_argc);
8403
8404         if (!argc || !argv || !argv2)
8405                 goto ERROR;
8406
8407         memset(argv, 0, sizeof(gchar*) * max_argc);
8408         memset(argv2, 0, sizeof(gchar*) * max_argc);
8409
8410         /* add initial */
8411         *argc = 1;
8412         argv[0] = g_strdup("mmplayer");
8413
8414         /* add gst_param */
8415         for (i = 0; i < 5; i++) {
8416                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8417                 if (strlen(player->ini.gst_param[i]) > 0) {
8418                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8419                         (*argc)++;
8420                 }
8421         }
8422
8423         /* we would not do fork for scanning plugins */
8424         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8425         (*argc)++;
8426
8427         /* check disable registry scan */
8428         if (player->ini.skip_rescan) {
8429                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8430                 (*argc)++;
8431         }
8432
8433         /* check disable segtrap */
8434         if (player->ini.disable_segtrap) {
8435                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8436                 (*argc)++;
8437         }
8438
8439         LOGD("initializing gstreamer with following parameter\n");
8440         LOGD("argc : %d\n", *argc);
8441         arg_count = *argc;
8442
8443         for (i = 0; i < arg_count; i++) {
8444                 argv2[i] = argv[i];
8445                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8446         }
8447
8448         /* initializing gstreamer */
8449         if (!gst_init_check(argc, &argv, &err)) {
8450                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8451                 if (err)
8452                         g_error_free(err);
8453
8454                 goto ERROR;
8455         }
8456         /* release */
8457         for (i = 0; i < arg_count; i++) {
8458                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8459                 MMPLAYER_FREEIF(argv2[i]);
8460         }
8461
8462         MMPLAYER_FREEIF(argv);
8463         MMPLAYER_FREEIF(argv2);
8464         MMPLAYER_FREEIF(argc);
8465
8466         /* done */
8467         initialized = TRUE;
8468
8469         return TRUE;
8470
8471 ERROR:
8472
8473         /* release */
8474         for (i = 0; i < arg_count; i++) {
8475                 LOGD("free[%d] : %s\n", i, argv2[i]);
8476                 MMPLAYER_FREEIF(argv2[i]);
8477         }
8478
8479         MMPLAYER_FREEIF(argv);
8480         MMPLAYER_FREEIF(argv2);
8481         MMPLAYER_FREEIF(argc);
8482
8483         return FALSE;
8484 }
8485
8486 int
8487 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8488 {
8489         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8490
8491         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8492                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8493                 MMPLAYER_FREEIF(player->pd_file_save_path);
8494         }
8495
8496         return MM_ERROR_NONE;
8497 }
8498
8499 static void
8500 __mmplayer_check_async_state_transition(mm_player_t* player)
8501 {
8502         GstState element_state = GST_STATE_VOID_PENDING;
8503         GstState element_pending_state = GST_STATE_VOID_PENDING;
8504         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8505         GstElement * element = NULL;
8506         gboolean async = FALSE;
8507
8508         /* check player handle */
8509         MMPLAYER_RETURN_IF_FAIL(player &&
8510                                                 player->pipeline &&
8511                                                 player->pipeline->mainbin &&
8512                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8513
8514         if (player->attrs)
8515                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8516
8517         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8518                 LOGD("don't need to check the pipeline state");
8519                 return;
8520         }
8521
8522         MMPLAYER_PRINT_STATE(player);
8523
8524         /* wait for state transition */
8525         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8526         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8527
8528         if (ret == GST_STATE_CHANGE_FAILURE) {
8529                 LOGE(" [%s] state : %s   pending : %s \n",
8530                         GST_ELEMENT_NAME(element),
8531                         gst_element_state_get_name(element_state),
8532                         gst_element_state_get_name(element_pending_state));
8533
8534                 /* dump state of all element */
8535                 __mmplayer_dump_pipeline_state(player);
8536
8537                 return;
8538         }
8539
8540         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8541         return;
8542 }
8543
8544 int
8545 _mmplayer_destroy(MMHandleType handle)
8546 {
8547         mm_player_t* player = MM_PLAYER_CAST(handle);
8548
8549         MMPLAYER_FENTER();
8550
8551         /* check player handle */
8552         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8553
8554         /* destroy can called at anytime */
8555         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8556
8557         /* check async state transition */
8558         __mmplayer_check_async_state_transition(player);
8559
8560         __mmplayer_destroy_streaming_ext(player);
8561
8562         /* release next play thread */
8563         if (player->next_play_thread) {
8564                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8565                 player->next_play_thread_exit = TRUE;
8566                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8567                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8568
8569                 LOGD("waitting for next play thread exit\n");
8570                 g_thread_join(player->next_play_thread);
8571                 g_mutex_clear(&player->next_play_thread_mutex);
8572                 g_cond_clear(&player->next_play_thread_cond);
8573                 LOGD("next play thread released\n");
8574         }
8575
8576         _mmplayer_release_video_capture(player);
8577
8578         /* de-initialize resource manager */
8579         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8580                         player->resource_manager))
8581                 LOGE("failed to deinitialize resource manager\n");
8582
8583         /* release pipeline */
8584         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8585                 LOGE("failed to destory pipeline\n");
8586                 return MM_ERROR_PLAYER_INTERNAL;
8587         }
8588
8589         g_queue_free(player->bus_msg_q);
8590
8591         /* release subtitle info lock and cond */
8592         g_mutex_clear(&player->subtitle_info_mutex);
8593         g_cond_clear(&player->subtitle_info_cond);
8594
8595         __mmplayer_release_dump_list(player->dump_list);
8596
8597         /* release miscellaneous information */
8598         __mmplayer_release_misc(player);
8599
8600         /* release miscellaneous information.
8601            these info needs to be released after pipeline is destroyed. */
8602         __mmplayer_release_misc_post(player);
8603
8604         /* release attributes */
8605         _mmplayer_deconstruct_attribute(handle);
8606
8607         /* release lock */
8608         g_mutex_clear(&player->fsink_lock);
8609
8610         /* release lock */
8611         g_mutex_clear(&player->update_tag_lock);
8612
8613         /* release video bo lock and cond */
8614         g_mutex_clear(&player->video_bo_mutex);
8615         g_cond_clear(&player->video_bo_cond);
8616
8617         /* release media stream callback lock */
8618         g_mutex_clear(&player->media_stream_cb_lock);
8619
8620         MMPLAYER_FLEAVE();
8621
8622         return MM_ERROR_NONE;
8623 }
8624
8625 int
8626 __mmplayer_realize_streaming_ext(mm_player_t* player)
8627 {
8628         int ret = MM_ERROR_NONE;
8629
8630         MMPLAYER_FENTER();
8631         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8632
8633         if (MMPLAYER_IS_HTTP_PD(player)) {
8634                 gboolean bret = FALSE;
8635
8636                 player->pd_downloader = _mmplayer_create_pd_downloader();
8637                 if (!player->pd_downloader) {
8638                         LOGE("Unable to create PD Downloader...");
8639                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8640                 }
8641
8642                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8643
8644                 if (FALSE == bret) {
8645                         LOGE("Unable to create PD Downloader...");
8646                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8647                 }
8648         }
8649
8650         MMPLAYER_FLEAVE();
8651         return ret;
8652 }
8653
8654 int
8655 _mmplayer_realize(MMHandleType hplayer)
8656 {
8657         mm_player_t* player = (mm_player_t*)hplayer;
8658         char *uri = NULL;
8659         void *param = NULL;
8660         MMHandleType attrs = 0;
8661         int ret = MM_ERROR_NONE;
8662
8663         MMPLAYER_FENTER();
8664
8665         /* check player handle */
8666         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8667
8668         /* check current state */
8669         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8670
8671         attrs = MMPLAYER_GET_ATTRS(player);
8672         if (!attrs) {
8673                 LOGE("fail to get attributes.\n");
8674                 return MM_ERROR_PLAYER_INTERNAL;
8675         }
8676         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8677         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8678
8679         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8680                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8681
8682                 if (ret != MM_ERROR_NONE) {
8683                         LOGE("failed to parse profile\n");
8684                         return ret;
8685                 }
8686         }
8687
8688         if (uri && (strstr(uri, "es_buff://"))) {
8689                 if (strstr(uri, "es_buff://push_mode"))
8690                         player->es_player_push_mode = TRUE;
8691                 else
8692                         player->es_player_push_mode = FALSE;
8693         }
8694
8695         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8696                 LOGW("mms protocol is not supported format.\n");
8697                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8698         }
8699
8700         if (MMPLAYER_IS_STREAMING(player))
8701                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8702         else
8703                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8704
8705         player->smooth_streaming = FALSE;
8706         player->videodec_linked  = 0;
8707         player->videosink_linked = 0;
8708         player->audiodec_linked  = 0;
8709         player->audiosink_linked = 0;
8710         player->textsink_linked = 0;
8711         player->is_external_subtitle_present = FALSE;
8712         player->is_external_subtitle_added_now = FALSE;
8713         /* set the subtitle ON default */
8714         player->is_subtitle_off = FALSE;
8715
8716         /* realize pipeline */
8717         ret = __gst_realize(player);
8718         if (ret != MM_ERROR_NONE)
8719                 LOGE("fail to realize the player.\n");
8720         else
8721                 ret = __mmplayer_realize_streaming_ext(player);
8722
8723         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8724         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8725
8726         MMPLAYER_FLEAVE();
8727
8728         return ret;
8729 }
8730
8731 int
8732 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8733 {
8734         MMPLAYER_FENTER();
8735         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736
8737         /* destroy can called at anytime */
8738         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8739                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8740
8741         MMPLAYER_FLEAVE();
8742         return MM_ERROR_NONE;
8743 }
8744
8745 int
8746 _mmplayer_unrealize(MMHandleType hplayer)
8747 {
8748         mm_player_t* player = (mm_player_t*)hplayer;
8749         int ret = MM_ERROR_NONE;
8750
8751         MMPLAYER_FENTER();
8752
8753         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8754
8755         MMPLAYER_CMD_UNLOCK(player);
8756         /* destroy the gst bus msg thread which is created during realize.
8757            this funct have to be called before getting cmd lock. */
8758         _mmplayer_bus_msg_thread_destroy(player);
8759         MMPLAYER_CMD_LOCK(player);
8760
8761         /* check current state */
8762         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8763
8764         /* check async state transition */
8765         __mmplayer_check_async_state_transition(player);
8766
8767         __mmplayer_unrealize_streaming_ext(player);
8768
8769         /* unrealize pipeline */
8770         ret = __gst_unrealize(player);
8771
8772         /* set asm stop if success */
8773         if (MM_ERROR_NONE == ret) {
8774                 if (!player->interrupted_by_resource) {
8775                         if (player->video_decoder_resource != NULL) {
8776                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8777                                                 player->video_decoder_resource);
8778                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8779                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8780                                 else
8781                                         player->video_decoder_resource = NULL;
8782                         }
8783
8784                         if (player->video_overlay_resource != NULL) {
8785                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8786                                                 player->video_overlay_resource);
8787                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8788                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8789                                 else
8790                                         player->video_overlay_resource = NULL;
8791                         }
8792
8793                         ret = mm_resource_manager_commit(player->resource_manager);
8794                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8795                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8796                 }
8797         } else
8798                 LOGE("failed and don't change asm state to stop");
8799
8800         MMPLAYER_FLEAVE();
8801
8802         return ret;
8803 }
8804
8805 int
8806 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8807 {
8808         mm_player_t* player = (mm_player_t*)hplayer;
8809
8810         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8811
8812         return __gst_set_message_callback(player, callback, user_param);
8813 }
8814
8815 int
8816 _mmplayer_get_state(MMHandleType hplayer, int* state)
8817 {
8818         mm_player_t *player = (mm_player_t*)hplayer;
8819
8820         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8821
8822         *state = MMPLAYER_CURRENT_STATE(player);
8823
8824         return MM_ERROR_NONE;
8825 }
8826
8827
8828 int
8829 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8830 {
8831         mm_player_t* player = (mm_player_t*) hplayer;
8832         GstElement* vol_element = NULL;
8833         int i = 0;
8834
8835         MMPLAYER_FENTER();
8836
8837         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8838
8839         LOGD("volume [L]=%f:[R]=%f\n",
8840                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8841
8842         /* invalid factor range or not */
8843         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8844                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8845                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8846                         return MM_ERROR_INVALID_ARGUMENT;
8847                 }
8848         }
8849
8850         /* not support to set other value into each channel */
8851         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8852                 return MM_ERROR_INVALID_ARGUMENT;
8853
8854         /* Save volume to handle. Currently the first array element will be saved. */
8855         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8856
8857         /* check pipeline handle */
8858         if (!player->pipeline || !player->pipeline->audiobin) {
8859                 LOGD("audiobin is not created yet\n");
8860                 LOGD("but, current stored volume will be set when it's created.\n");
8861
8862                 /* NOTE : stored volume will be used in create_audiobin
8863                  * returning MM_ERROR_NONE here makes application to able to
8864                  * set volume at anytime.
8865                  */
8866                 return MM_ERROR_NONE;
8867         }
8868
8869         /* setting volume to volume element */
8870         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8871
8872         if (vol_element) {
8873                 LOGD("volume is set [%f]\n", player->sound.volume);
8874                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8875         }
8876
8877         MMPLAYER_FLEAVE();
8878
8879         return MM_ERROR_NONE;
8880 }
8881
8882
8883 int
8884 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8885 {
8886         mm_player_t* player = (mm_player_t*) hplayer;
8887         int i = 0;
8888
8889         MMPLAYER_FENTER();
8890
8891         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8892         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8893
8894         /* returning stored volume */
8895         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8896                 volume->level[i] = player->sound.volume;
8897
8898         MMPLAYER_FLEAVE();
8899
8900         return MM_ERROR_NONE;
8901 }
8902
8903 int
8904 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8905 {
8906         mm_player_t* player = (mm_player_t*) hplayer;
8907         GstElement* vol_element = NULL;
8908
8909         MMPLAYER_FENTER();
8910
8911         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8912
8913         /* mute value shoud 0 or 1 */
8914         if (mute != 0 && mute != 1) {
8915                 LOGE("bad mute value\n");
8916
8917                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8918                 return MM_ERROR_INVALID_ARGUMENT;
8919         }
8920
8921         player->sound.mute = mute;
8922
8923         /* just hold mute value if pipeline is not ready */
8924         if (!player->pipeline || !player->pipeline->audiobin) {
8925                 LOGD("pipeline is not ready. holding mute value\n");
8926                 return MM_ERROR_NONE;
8927         }
8928
8929         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8930
8931         /* NOTE : volume will only created when the bt is enabled */
8932         if (vol_element) {
8933                 LOGD("mute : %d\n", mute);
8934                 g_object_set(vol_element, "mute", mute, NULL);
8935         } else
8936                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8937
8938         MMPLAYER_FLEAVE();
8939
8940         return MM_ERROR_NONE;
8941 }
8942
8943 int
8944 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
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         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8952
8953         /* just hold mute value if pipeline is not ready */
8954         if (!player->pipeline || !player->pipeline->audiobin) {
8955                 LOGD("pipeline is not ready. returning stored value\n");
8956                 *pmute = player->sound.mute;
8957                 return MM_ERROR_NONE;
8958         }
8959
8960         *pmute = player->sound.mute;
8961
8962         MMPLAYER_FLEAVE();
8963
8964         return MM_ERROR_NONE;
8965 }
8966
8967 int
8968 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8969 {
8970         mm_player_t* player = (mm_player_t*) hplayer;
8971
8972         MMPLAYER_FENTER();
8973
8974         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8975
8976         player->video_stream_changed_cb = callback;
8977         player->video_stream_changed_cb_user_param = user_param;
8978         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8979
8980         MMPLAYER_FLEAVE();
8981
8982         return MM_ERROR_NONE;
8983 }
8984
8985 int
8986 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_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_changed_cb = callback;
8995         player->audio_stream_changed_cb_user_param = user_param;
8996         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8997
8998         MMPLAYER_FLEAVE();
8999
9000         return MM_ERROR_NONE;
9001 }
9002
9003 int
9004 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9005 {
9006         mm_player_t* player = (mm_player_t*) hplayer;
9007
9008         MMPLAYER_FENTER();
9009
9010         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9011
9012         player->audio_stream_render_cb_ex = callback;
9013         player->audio_stream_cb_user_param = user_param;
9014         player->audio_stream_sink_sync = sync;
9015         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);
9016
9017         MMPLAYER_FLEAVE();
9018
9019         return MM_ERROR_NONE;
9020 }
9021
9022 int
9023 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9024 {
9025         mm_player_t* player = (mm_player_t*) hplayer;
9026
9027         MMPLAYER_FENTER();
9028
9029         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030
9031         if (callback && !player->bufmgr)
9032                 player->bufmgr = tbm_bufmgr_init(-1);
9033
9034         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9035         player->video_stream_cb = callback;
9036         player->video_stream_cb_user_param = user_param;
9037
9038         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9039
9040         MMPLAYER_FLEAVE();
9041
9042         return MM_ERROR_NONE;
9043 }
9044
9045 int
9046 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9047 {
9048         mm_player_t* player = (mm_player_t*) hplayer;
9049
9050         MMPLAYER_FENTER();
9051
9052         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9053
9054         player->audio_stream_cb = callback;
9055         player->audio_stream_cb_user_param = user_param;
9056         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9057
9058         MMPLAYER_FLEAVE();
9059
9060         return MM_ERROR_NONE;
9061 }
9062
9063 static int
9064 __mmplayer_start_streaming_ext(mm_player_t *player)
9065 {
9066         gint ret = MM_ERROR_NONE;
9067
9068         MMPLAYER_FENTER();
9069         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9070
9071         if (MMPLAYER_IS_HTTP_PD(player)) {
9072                 if (!player->pd_downloader) {
9073                         ret = __mmplayer_realize_streaming_ext(player);
9074
9075                         if (ret != MM_ERROR_NONE) {
9076                                 LOGE("failed to realize streaming ext\n");
9077                                 return ret;
9078                         }
9079                 }
9080
9081                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9082                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9083                         if (!ret) {
9084                                 LOGE("ERROR while starting PD...\n");
9085                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9086                         }
9087                         ret = MM_ERROR_NONE;
9088                 }
9089         }
9090
9091         MMPLAYER_FLEAVE();
9092         return ret;
9093 }
9094
9095 int
9096 _mmplayer_start(MMHandleType hplayer)
9097 {
9098         mm_player_t* player = (mm_player_t*) hplayer;
9099         gint ret = MM_ERROR_NONE;
9100
9101         MMPLAYER_FENTER();
9102
9103         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9104
9105         /* check current state */
9106         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9107
9108         /* NOTE : we should check and create pipeline again if not created as we destroy
9109          * whole pipeline when stopping in streamming playback
9110          */
9111         if (!player->pipeline) {
9112                 ret = __gst_realize(player);
9113                 if (MM_ERROR_NONE != ret) {
9114                         LOGE("failed to realize before starting. only in streamming\n");
9115                         /* unlock */
9116                         return ret;
9117                 }
9118         }
9119
9120         ret = __mmplayer_start_streaming_ext(player);
9121         if (ret != MM_ERROR_NONE) {
9122                 LOGE("failed to start streaming ext 0x%X", ret);
9123                 return ret;
9124         }
9125
9126         /* start pipeline */
9127         ret = __gst_start(player);
9128         if (ret != MM_ERROR_NONE)
9129                 LOGE("failed to start player.\n");
9130
9131         MMPLAYER_FLEAVE();
9132
9133         return ret;
9134 }
9135
9136 /* NOTE: post "not supported codec message" to application
9137  * when one codec is not found during AUTOPLUGGING in MSL.
9138  * So, it's separated with error of __mmplayer_gst_callback().
9139  * And, if any codec is not found, don't send message here.
9140  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9141  */
9142 int
9143 __mmplayer_handle_missed_plugin(mm_player_t* player)
9144 {
9145         MMMessageParamType msg_param;
9146         memset(&msg_param, 0, sizeof(MMMessageParamType));
9147         gboolean post_msg_direct = FALSE;
9148
9149         MMPLAYER_FENTER();
9150
9151         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9152
9153         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9154                         player->not_supported_codec, player->can_support_codec);
9155
9156         if (player->not_found_demuxer) {
9157                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9158                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9159
9160                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9161                 MMPLAYER_FREEIF(msg_param.data);
9162
9163                 return MM_ERROR_NONE;
9164         }
9165
9166         if (player->not_supported_codec) {
9167                 if (player->can_support_codec) {
9168                         // There is one codec to play
9169                         post_msg_direct = TRUE;
9170                 } else {
9171                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9172                                 post_msg_direct = TRUE;
9173                 }
9174
9175                 if (post_msg_direct) {
9176                         MMMessageParamType msg_param;
9177                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9178
9179                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9180                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9181
9182                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9183                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9184                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9185                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9186
9187                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9188                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9189                         }
9190
9191                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9192
9193                         MMPLAYER_FREEIF(msg_param.data);
9194
9195                         return MM_ERROR_NONE;
9196                 } else {
9197                         // no any supported codec case
9198                         LOGW("not found any codec, posting error code to application.\n");
9199
9200                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9201                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9202                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9203                         } else {
9204                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9205                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9206                         }
9207
9208                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9209
9210                         MMPLAYER_FREEIF(msg_param.data);
9211                 }
9212         }
9213
9214         MMPLAYER_FLEAVE();
9215
9216         return MM_ERROR_NONE;
9217 }
9218
9219 static void __mmplayer_check_pipeline(mm_player_t* player)
9220 {
9221         GstState element_state = GST_STATE_VOID_PENDING;
9222         GstState element_pending_state = GST_STATE_VOID_PENDING;
9223         gint timeout = 0;
9224         int ret = MM_ERROR_NONE;
9225
9226         if (player->gapless.reconfigure) {
9227                 LOGW("pipeline is under construction.\n");
9228
9229                 MMPLAYER_PLAYBACK_LOCK(player);
9230                 MMPLAYER_PLAYBACK_UNLOCK(player);
9231
9232                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9233
9234                 /* wait for state transition */
9235                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9236
9237                 if (ret == GST_STATE_CHANGE_FAILURE)
9238                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9239         }
9240 }
9241
9242 /* NOTE : it should be able to call 'stop' anytime*/
9243 int
9244 _mmplayer_stop(MMHandleType hplayer)
9245 {
9246         mm_player_t* player = (mm_player_t*)hplayer;
9247         int ret = MM_ERROR_NONE;
9248
9249         MMPLAYER_FENTER();
9250
9251         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9252
9253         /* check current state */
9254         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9255
9256         /* check pipline building state */
9257         __mmplayer_check_pipeline(player);
9258         __mmplayer_reset_gapless_state(player);
9259
9260         /* NOTE : application should not wait for EOS after calling STOP */
9261         __mmplayer_cancel_eos_timer(player);
9262
9263         __mmplayer_unrealize_streaming_ext(player);
9264
9265         /* reset */
9266         player->doing_seek = FALSE;
9267
9268         /* stop pipeline */
9269         ret = __gst_stop(player);
9270
9271         if (ret != MM_ERROR_NONE)
9272                 LOGE("failed to stop player.\n");
9273
9274         MMPLAYER_FLEAVE();
9275
9276         return ret;
9277 }
9278
9279 int
9280 _mmplayer_pause(MMHandleType hplayer)
9281 {
9282         mm_player_t* player = (mm_player_t*)hplayer;
9283         gint64 pos_msec = 0;
9284         gboolean async = FALSE;
9285         gint ret = MM_ERROR_NONE;
9286
9287         MMPLAYER_FENTER();
9288
9289         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9290
9291         /* check current state */
9292         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9293
9294         /* check pipline building state */
9295         __mmplayer_check_pipeline(player);
9296
9297         switch (MMPLAYER_CURRENT_STATE(player)) {
9298         case MM_PLAYER_STATE_READY:
9299                 {
9300                         /* check prepare async or not.
9301                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9302                          */
9303                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9304                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9305
9306                         /* Changing back sync of rtspsrc to async */
9307                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9308                                 LOGD("async prepare working mode for rtsp");
9309                                 async = TRUE;
9310                         }
9311                 }
9312                 break;
9313
9314         case MM_PLAYER_STATE_PLAYING:
9315                 {
9316                         /* NOTE : store current point to overcome some bad operation
9317                         *(returning zero when getting current position in paused state) of some
9318                         * elements
9319                         */
9320                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9321                                 LOGW("getting current position failed in paused\n");
9322
9323                         player->last_position = pos_msec;
9324
9325                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9326                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9327                            This causes problem is position calculation during normal pause resume scenarios also.
9328                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9329                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9330                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9331                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9332                         }
9333                 }
9334                 break;
9335         }
9336
9337         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9338                 LOGD("doing async pause in case of ms buff src");
9339                 async = TRUE;
9340         }
9341
9342         /* pause pipeline */
9343         ret = __gst_pause(player, async);
9344
9345         if (ret != MM_ERROR_NONE)
9346                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9347
9348         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9349                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9350                         LOGE("failed to update display_rotation");
9351         }
9352
9353         MMPLAYER_FLEAVE();
9354
9355         return ret;
9356 }
9357
9358 int
9359 _mmplayer_resume(MMHandleType hplayer)
9360 {
9361         mm_player_t* player = (mm_player_t*)hplayer;
9362         int ret = MM_ERROR_NONE;
9363         gboolean async = FALSE;
9364
9365         MMPLAYER_FENTER();
9366
9367         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9368
9369         /* Changing back sync mode rtspsrc to async */
9370         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9371                 LOGD("async resume for rtsp case");
9372                 async = TRUE;
9373         }
9374
9375         /* check current state */
9376         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9377
9378         ret = __gst_resume(player, async);
9379
9380         if (ret != MM_ERROR_NONE)
9381                 LOGE("failed to resume player.\n");
9382
9383         MMPLAYER_FLEAVE();
9384
9385         return ret;
9386 }
9387
9388 static int
9389 __mmplayer_set_pcm_extraction(mm_player_t* player)
9390 {
9391         gint64 start_nsec = 0;
9392         gint64 end_nsec = 0;
9393         gint64 dur_nsec = 0;
9394         gint64 dur_msec = 0;
9395         int required_start = 0;
9396         int required_end = 0;
9397         int ret = 0;
9398
9399         MMPLAYER_FENTER();
9400
9401         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9402
9403         mm_attrs_multiple_get(player->attrs,
9404                 NULL,
9405                 "pcm_extraction_start_msec", &required_start,
9406                 "pcm_extraction_end_msec", &required_end,
9407                 NULL);
9408
9409         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9410
9411         if (required_start == 0 && required_end == 0) {
9412                 LOGD("extracting entire stream");
9413                 return MM_ERROR_NONE;
9414         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9415                 LOGD("invalid range for pcm extraction");
9416                 return MM_ERROR_INVALID_ARGUMENT;
9417         }
9418
9419         /* get duration */
9420         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9421         if (!ret) {
9422                 LOGE("failed to get duration");
9423                 return MM_ERROR_PLAYER_INTERNAL;
9424         }
9425         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9426
9427         if (dur_msec < required_end) {
9428                 // FIXME
9429                 LOGD("invalid end pos for pcm extraction");
9430                 return MM_ERROR_INVALID_ARGUMENT;
9431         }
9432
9433         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9434         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9435
9436         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9437                                         1.0,
9438                                         GST_FORMAT_TIME,
9439                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9440                                         GST_SEEK_TYPE_SET, start_nsec,
9441                                         GST_SEEK_TYPE_SET, end_nsec))) {
9442                 LOGE("failed to seek for pcm extraction\n");
9443
9444                 return MM_ERROR_PLAYER_SEEK;
9445         }
9446
9447         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9448
9449         MMPLAYER_FLEAVE();
9450
9451         return MM_ERROR_NONE;
9452 }
9453
9454 int
9455 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9456 {
9457         mm_player_t* player = (mm_player_t*)hplayer;
9458         gint64 pos_msec = 0;
9459         int ret = MM_ERROR_NONE;
9460         int mute = FALSE;
9461         signed long long start = 0, stop = 0;
9462         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9463         MMPLAYER_FENTER();
9464
9465         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9466         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9467
9468         /* The sound of video is not supported under 0.0 and over 2.0. */
9469         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9470                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9471                         mute = TRUE;
9472         }
9473         _mmplayer_set_mute(hplayer, mute);
9474
9475         if (player->playback_rate == rate)
9476                 return MM_ERROR_NONE;
9477
9478         /* If the position is reached at start potion during fast backward, EOS is posted.
9479          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9480          * */
9481         player->playback_rate = rate;
9482
9483         current_state = MMPLAYER_CURRENT_STATE(player);
9484
9485         if (current_state != MM_PLAYER_STATE_PAUSED)
9486                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9487
9488         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9489
9490         if ((current_state == MM_PLAYER_STATE_PAUSED)
9491                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9492                 LOGW("returning last point : %lld\n", player->last_position);
9493                 pos_msec = player->last_position;
9494         }
9495
9496         if (rate >= 0) {
9497                 start = pos_msec;
9498                 stop = GST_CLOCK_TIME_NONE;
9499         } else {
9500                 start = GST_CLOCK_TIME_NONE;
9501                 stop = pos_msec;
9502         }
9503
9504         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9505                                 player->playback_rate,
9506                                 GST_FORMAT_TIME,
9507                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9508                                 GST_SEEK_TYPE_SET, start,
9509                                 GST_SEEK_TYPE_SET, stop)) {
9510                 LOGE("failed to set speed playback\n");
9511                 return MM_ERROR_PLAYER_SEEK;
9512         }
9513
9514         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9515
9516         MMPLAYER_FLEAVE();
9517
9518         return MM_ERROR_NONE;;
9519 }
9520
9521 int
9522 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9523 {
9524         mm_player_t* player = (mm_player_t*)hplayer;
9525         int ret = MM_ERROR_NONE;
9526
9527         MMPLAYER_FENTER();
9528
9529         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9530
9531         /* check pipline building state */
9532         __mmplayer_check_pipeline(player);
9533
9534         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9535
9536         MMPLAYER_FLEAVE();
9537
9538         return ret;
9539 }
9540
9541 int
9542 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9543 {
9544         mm_player_t* player = (mm_player_t*)hplayer;
9545         int ret = MM_ERROR_NONE;
9546
9547         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9548
9549         ret = __gst_get_position(player, format, position);
9550
9551         return ret;
9552 }
9553
9554 int
9555 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9556 {
9557         mm_player_t* player = (mm_player_t*)hplayer;
9558         int ret = MM_ERROR_NONE;
9559
9560         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9561
9562         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9563
9564         return ret;
9565 }
9566
9567 int
9568 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9569 {
9570         mm_player_t* player = (mm_player_t*)hplayer;
9571         int ret = MM_ERROR_NONE;
9572
9573         MMPLAYER_FENTER();
9574
9575         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9576
9577         ret = __gst_adjust_subtitle_position(player, format, position);
9578
9579         MMPLAYER_FLEAVE();
9580
9581         return ret;
9582 }
9583 int
9584 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9585 {
9586         mm_player_t* player = (mm_player_t*)hplayer;
9587         int ret = MM_ERROR_NONE;
9588
9589         MMPLAYER_FENTER();
9590
9591         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9592
9593         ret = __gst_adjust_video_position(player, offset);
9594
9595         MMPLAYER_FLEAVE();
9596
9597         return ret;
9598 }
9599
9600 static gboolean
9601 __mmplayer_is_midi_type(gchar* str_caps)
9602 {
9603         if ((g_strrstr(str_caps, "audio/midi")) ||
9604                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9605                 (g_strrstr(str_caps, "application/x-smaf")) ||
9606                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9607                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9608                 (g_strrstr(str_caps, "audio/xmf")) ||
9609                 (g_strrstr(str_caps, "audio/mxmf"))) {
9610                 LOGD("midi\n");
9611                 return TRUE;
9612         }
9613
9614         return FALSE;
9615 }
9616
9617 static gboolean
9618 __mmplayer_is_only_mp3_type(gchar *str_caps)
9619 {
9620         if (g_strrstr(str_caps, "application/x-id3") ||
9621                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9622                 return TRUE;
9623         return FALSE;
9624 }
9625
9626 static void
9627 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9628 {
9629         GstStructure* caps_structure = NULL;
9630         gint samplerate = 0;
9631         gint channels = 0;
9632
9633         MMPLAYER_FENTER();
9634         MMPLAYER_RETURN_IF_FAIL(player && caps);
9635
9636         caps_structure = gst_caps_get_structure(caps, 0);
9637
9638         /* set stream information */
9639         gst_structure_get_int(caps_structure, "rate", &samplerate);
9640         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9641
9642         gst_structure_get_int(caps_structure, "channels", &channels);
9643         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9644
9645         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9646 }
9647
9648 static void
9649 __mmplayer_update_content_type_info(mm_player_t* player)
9650 {
9651         MMPLAYER_FENTER();
9652         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9653
9654         if (__mmplayer_is_midi_type(player->type)) {
9655                 player->bypass_audio_effect = TRUE;
9656         } else if (g_strrstr(player->type, "application/x-hls")) {
9657                 /* If it can't know exact type when it parses uri because of redirection case,
9658                  * it will be fixed by typefinder or when doing autoplugging.
9659                  */
9660                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9661                 if (player->streamer) {
9662                         player->streamer->is_adaptive_streaming = TRUE;
9663                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9664                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9665                 }
9666         } else if (g_strrstr(player->type, "application/dash+xml")) {
9667                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9668         }
9669
9670         MMPLAYER_FLEAVE();
9671 }
9672
9673 static void
9674 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9675 GstCaps *caps, gpointer data)
9676 {
9677         mm_player_t* player = (mm_player_t*)data;
9678         GstPad* pad = NULL;
9679
9680         MMPLAYER_FENTER();
9681
9682         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9683
9684         /* store type string */
9685         MMPLAYER_FREEIF(player->type);
9686         player->type = gst_caps_to_string(caps);
9687         if (player->type) {
9688                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9689                                 player, player->type, probability, gst_caps_get_size(caps));
9690         }
9691
9692         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9693                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9694                 LOGE("not support media format\n");
9695
9696                 if (player->msg_posted == FALSE) {
9697                         MMMessageParamType msg_param;
9698                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9699
9700                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9701                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9702
9703                         /* don't post more if one was sent already */
9704                         player->msg_posted = TRUE;
9705                 }
9706                 return;
9707         }
9708
9709         __mmplayer_update_content_type_info(player);
9710
9711         pad = gst_element_get_static_pad(tf, "src");
9712         if (!pad) {
9713                 LOGE("fail to get typefind src pad.\n");
9714                 return;
9715         }
9716
9717         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9718                 gboolean async = FALSE;
9719                 LOGE("failed to autoplug %s\n", player->type);
9720
9721                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9722
9723                 if (async && player->msg_posted == FALSE)
9724                         __mmplayer_handle_missed_plugin(player);
9725
9726                 goto DONE;
9727         }
9728
9729 DONE:
9730         gst_object_unref(GST_OBJECT(pad));
9731
9732         MMPLAYER_FLEAVE();
9733
9734         return;
9735 }
9736
9737 static GstElement *
9738 __mmplayer_create_decodebin(mm_player_t* player)
9739 {
9740         GstElement *decodebin = NULL;
9741
9742         MMPLAYER_FENTER();
9743
9744         /* create decodebin */
9745         decodebin = gst_element_factory_make("decodebin", NULL);
9746
9747         if (!decodebin) {
9748                 LOGE("fail to create decodebin\n");
9749                 goto ERROR;
9750         }
9751
9752         /* raw pad handling signal */
9753         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9754                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9755
9756         /* no-more-pad pad handling signal */
9757         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9758                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9759
9760         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9761                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9762
9763         /* This signal is emitted when a pad for which there is no further possible
9764            decoding is added to the decodebin.*/
9765         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9766                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9767
9768         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9769            before looking for any elements that can handle that stream.*/
9770         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9771                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9772
9773         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9774            before looking for any elements that can handle that stream.*/
9775         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9776                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9777
9778         /* This signal is emitted once decodebin has finished decoding all the data.*/
9779         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9780                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9781
9782         /* This signal is emitted when a element is added to the bin.*/
9783         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9784                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9785
9786 ERROR:
9787         return decodebin;
9788 }
9789
9790 static gboolean
9791 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9792 {
9793         MMPlayerGstElement* mainbin = NULL;
9794         GstElement* decodebin = NULL;
9795         GstElement* queue2 = NULL;
9796         GstPad* sinkpad = NULL;
9797         GstPad* qsrcpad = NULL;
9798         gint64 dur_bytes = 0L;
9799
9800         guint max_buffer_size_bytes = 0;
9801         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9802
9803         MMPLAYER_FENTER();
9804         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9805
9806         mainbin = player->pipeline->mainbin;
9807
9808         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9809                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9810                 LOGD("creating http streaming buffering queue(queue2)\n");
9811
9812                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9813                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9814                 } else {
9815                         queue2 = gst_element_factory_make("queue2", "queue2");
9816                         if (!queue2) {
9817                                 LOGE("failed to create buffering queue element\n");
9818                                 goto ERROR;
9819                         }
9820
9821                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9822                                 LOGE("failed to add buffering queue\n");
9823                                 goto ERROR;
9824                         }
9825
9826                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9827                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9828
9829                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9830                                 LOGE("failed to link buffering queue\n");
9831                                 goto ERROR;
9832                         }
9833
9834                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9835                                 LOGE("fail to get duration.\n");
9836
9837                         LOGD("dur_bytes = %lld\n", dur_bytes);
9838
9839                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9840
9841                         if (dur_bytes > 0) {
9842                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9843                                         type = MUXED_BUFFER_TYPE_FILE;
9844                                 } else {
9845                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9846                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9847                                 }
9848                         } else {
9849                                 dur_bytes = 0;
9850                         }
9851
9852                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9853                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9854                         if (!g_strrstr(player->type, "video/mpegts")) {
9855                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9856                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9857
9858                                 // FIXME : pass ini setting directly. is this ok?
9859                                 __mm_player_streaming_set_queue2(player->streamer,
9860                                                                                                 queue2,
9861                                                                                                 FALSE,
9862                                                                                                 max_buffer_size_bytes,
9863                                                                                                 player->ini.http_buffering_time,
9864                                                                                                 1.0,                                                            // no meaning
9865                                                                                                 player->ini.http_buffering_limit,       // no meaning
9866                                                                                                 type,
9867                                                                                                 player->http_file_buffering_path,
9868                                                                                                 (guint64)dur_bytes);
9869                         }
9870
9871                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9872                                 LOGE("failed to sync queue2 state with parent\n");
9873                                 goto ERROR;
9874                         }
9875
9876                         srcpad = qsrcpad;
9877
9878                         gst_object_unref(GST_OBJECT(sinkpad));
9879
9880                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9881                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9882                 }
9883         }
9884
9885         /* create decodebin */
9886         decodebin = __mmplayer_create_decodebin(player);
9887
9888         if (!decodebin) {
9889                 LOGE("can not create autoplug element\n");
9890                 goto ERROR;
9891         }
9892
9893         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9894                 LOGE("failed to add decodebin\n");
9895                 goto ERROR;
9896         }
9897
9898         /* to force caps on the decodebin element and avoid reparsing stuff by
9899         * typefind. It also avoids a deadlock in the way typefind activates pads in
9900         * the state change */
9901         g_object_set(decodebin, "sink-caps", caps, NULL);
9902
9903         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9904
9905         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9906                 LOGE("failed to link decodebin\n");
9907                 goto ERROR;
9908         }
9909
9910         gst_object_unref(GST_OBJECT(sinkpad));
9911
9912         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9913         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9914
9915         /* set decodebin property about buffer in streaming playback. *
9916          * in case of HLS/DASH, it does not need to have big buffer        *
9917          * because it is kind of adaptive streaming.                  */
9918         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9919                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9920                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9921                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9922
9923                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9924                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9925                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9926                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9927                 }
9928
9929                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9930                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9931                                                                                         "low-percent", 1,   // 1%
9932                                                                                         "max-size-bytes", max_size_bytes,
9933                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9934                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9935         }
9936
9937         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9938                 LOGE("failed to sync decodebin state with parent\n");
9939                 goto ERROR;
9940         }
9941
9942         MMPLAYER_FLEAVE();
9943
9944         return TRUE;
9945
9946 ERROR:
9947
9948         if (sinkpad)
9949                 gst_object_unref(GST_OBJECT(sinkpad));
9950
9951         if (queue2) {
9952                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9953                  * You need to explicitly set elements to the NULL state before
9954                  * dropping the final reference, to allow them to clean up.
9955                  */
9956                 gst_element_set_state(queue2, GST_STATE_NULL);
9957
9958                 /* And, it still has a parent "player".
9959                  * You need to let the parent manage the object instead of unreffing the object directly.
9960                  */
9961                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9962                 gst_object_unref(queue2);
9963                 queue2 = NULL;
9964         }
9965
9966         if (decodebin) {
9967                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9968                  * You need to explicitly set elements to the NULL state before
9969                  * dropping the final reference, to allow them to clean up.
9970                  */
9971                 gst_element_set_state(decodebin, GST_STATE_NULL);
9972
9973                 /* And, it still has a parent "player".
9974                  * You need to let the parent manage the object instead of unreffing the object directly.
9975                  */
9976
9977                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9978                 gst_object_unref(decodebin);
9979                 decodebin = NULL;
9980         }
9981
9982         return FALSE;
9983 }
9984
9985 static int
9986 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9987 {
9988         MMPLAYER_FENTER();
9989
9990         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9991         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9992
9993         LOGD("class : %s, mime : %s \n", factory_class, mime);
9994
9995         /* add missing plugin */
9996         /* NOTE : msl should check missing plugin for image mime type.
9997          * Some motion jpeg clips can have playable audio track.
9998          * So, msl have to play audio after displaying popup written video format not supported.
9999          */
10000         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10001                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10002                         LOGD("not found demuxer\n");
10003                         player->not_found_demuxer = TRUE;
10004                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10005
10006                         goto DONE;
10007                 }
10008         }
10009
10010         if (!g_strrstr(factory_class, "Demuxer")) {
10011                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10012                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10013                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10014
10015                         /* check that clip have multi tracks or not */
10016                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10017                                 LOGD("video plugin is already linked\n");
10018                         } else {
10019                                 LOGW("add VIDEO to missing plugin\n");
10020                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10021                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10022                         }
10023                 } else if (g_str_has_prefix(mime, "audio")) {
10024                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10025                                 LOGD("audio plugin is already linked\n");
10026                         } else {
10027                                 LOGW("add AUDIO to missing plugin\n");
10028                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10029                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10030                         }
10031                 }
10032         }
10033
10034 DONE:
10035         MMPLAYER_FLEAVE();
10036
10037         return MM_ERROR_NONE;
10038 }
10039
10040
10041 static void
10042 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10043 {
10044         mm_player_t* player = (mm_player_t*)data;
10045
10046         MMPLAYER_FENTER();
10047
10048         MMPLAYER_RETURN_IF_FAIL(player);
10049
10050         /* remove fakesink. */
10051         if (!__mmplayer_gst_remove_fakesink(player,
10052                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10053                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10054                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10055                  * source element are not same. To overcome this situation, this function will called
10056                  * several places and several times. Therefore, this is not an error case.
10057                  */
10058                 return;
10059         }
10060
10061         LOGD("[handle: %p] pipeline has completely constructed", player);
10062
10063         if ((player->ini.async_start) &&
10064                 (player->msg_posted == FALSE) &&
10065                 (player->cmd >= MMPLAYER_COMMAND_START))
10066                 __mmplayer_handle_missed_plugin(player);
10067
10068         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10069 }
10070
10071 static gboolean
10072 __mmplayer_verify_next_play_path(mm_player_t *player)
10073 {
10074         MMHandleType attrs = 0;
10075         MMPlayerParseProfile profile;
10076         gint uri_idx = 0, check_cnt = 0;
10077         char *uri = NULL;
10078         gint mode = MM_PLAYER_PD_MODE_NONE;
10079         gint video = 0;
10080         gint count = 0;
10081         gint gapless = 0;
10082         guint num_of_list = 0;
10083         static int profile_tv = -1;
10084
10085         MMPLAYER_FENTER();
10086
10087         LOGD("checking for gapless play");
10088
10089         if (player->pipeline->textbin) {
10090                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10091                 goto ERROR;
10092         }
10093
10094         attrs = MMPLAYER_GET_ATTRS(player);
10095         if (!attrs) {
10096                 LOGE("fail to get attributes.\n");
10097                 goto ERROR;
10098         }
10099
10100         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10101
10102         if (__builtin_expect(profile_tv == -1, 0)) {
10103                 char *profileName;
10104                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10105                 switch (*profileName) {
10106                 case 't':
10107                 case 'T':
10108                         profile_tv = 1;
10109                         break;
10110                 default:
10111                         profile_tv = 0;
10112                 }
10113                 free(profileName);
10114         }
10115         /* gapless playback is not supported in case of video at TV profile. */
10116         if (profile_tv && video) {
10117                 LOGW("not support video gapless playback");
10118                 goto ERROR;
10119         }
10120
10121         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10122                 if (mode == TRUE) {
10123                         LOGW("pd mode\n");
10124                         goto ERROR;
10125                 }
10126         }
10127
10128         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10129                 LOGE("can not get play count\n");
10130
10131         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10132                 LOGE("can not get gapless mode\n");
10133
10134         if (video && !gapless) {
10135                 LOGW("not enabled video gapless playback");
10136                 goto ERROR;
10137         }
10138
10139         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10140                 gapless = 1;
10141
10142         if (!gapless) {
10143                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10144                 goto ERROR;
10145         }
10146
10147         num_of_list = g_list_length(player->uri_info.uri_list);
10148
10149         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10150
10151         if (num_of_list == 0) {
10152                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10153                         LOGE("can not get profile_uri\n");
10154                         goto ERROR;
10155                 }
10156
10157                 if (!uri) {
10158                         LOGE("uri list is empty.\n");
10159                         goto ERROR;
10160                 }
10161
10162                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10163                 LOGD("add original path : %s ", uri);
10164
10165                 num_of_list = 1;
10166                 uri = NULL;
10167         }
10168
10169         uri_idx = player->uri_info.uri_idx;
10170
10171         while (TRUE) {
10172                 check_cnt++;
10173
10174                 if (check_cnt > num_of_list) {
10175                         LOGE("there is no valid uri.");
10176                         goto ERROR;
10177                 }
10178
10179                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10180
10181                 if (uri_idx < num_of_list-1) {
10182                         uri_idx++;
10183                 } else {
10184                         if ((count <= 1) && (count != -1)) {
10185                                 LOGD("no repeat.");
10186                                 goto ERROR;
10187                         } else if (count > 1) {
10188                                 /* decrease play count */
10189                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10190                                 count--;
10191
10192                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10193
10194                                 /* commit attribute */
10195                                 if (mmf_attrs_commit(attrs))
10196                                         LOGE("failed to commit attribute\n");
10197                         }
10198
10199                         /* count < 0 : repeat continually */
10200                         uri_idx = 0;
10201                 }
10202
10203                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10204                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10205
10206                 if (uri == NULL) {
10207                         LOGW("next uri does not exist\n");
10208                         continue;
10209                 }
10210
10211                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10212                         LOGE("failed to parse profile\n");
10213                         continue;
10214                 }
10215
10216                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10217                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10218                         LOGW("uri type is not supported(%d).", profile.uri_type);
10219                         continue;
10220                 }
10221
10222                 break;
10223         }
10224
10225         player->uri_info.uri_idx = uri_idx;
10226         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10227
10228         if (mmf_attrs_commit(player->attrs)) {
10229                 LOGE("failed to commit.\n");
10230                 goto ERROR;
10231         }
10232
10233         LOGD("next uri %s(%d)\n", uri, uri_idx);
10234
10235         return TRUE;
10236
10237 ERROR:
10238
10239         LOGE("unable to play next path. EOS will be posted soon.\n");
10240         return FALSE;
10241 }
10242
10243 static void
10244 __mmplayer_initialize_next_play(mm_player_t *player)
10245 {
10246         int i;
10247
10248         MMPLAYER_FENTER();
10249
10250         player->smooth_streaming = FALSE;
10251         player->videodec_linked = 0;
10252         player->audiodec_linked = 0;
10253         player->videosink_linked = 0;
10254         player->audiosink_linked = 0;
10255         player->textsink_linked = 0;
10256         player->is_external_subtitle_present = FALSE;
10257         player->is_external_subtitle_added_now = FALSE;
10258         player->not_supported_codec = MISSING_PLUGIN_NONE;
10259         player->can_support_codec = FOUND_PLUGIN_NONE;
10260         player->pending_seek.is_pending = FALSE;
10261         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10262         player->pending_seek.pos = 0;
10263         player->msg_posted = FALSE;
10264         player->has_many_types = FALSE;
10265         player->no_more_pad = FALSE;
10266         player->not_found_demuxer = 0;
10267         player->doing_seek = FALSE;
10268         player->max_audio_channels = 0;
10269         player->is_subtitle_force_drop = FALSE;
10270         player->play_subtitle = FALSE;
10271         player->adjust_subtitle_pos = 0;
10272
10273         player->total_bitrate = 0;
10274         player->total_maximum_bitrate = 0;
10275
10276         _mmplayer_track_initialize(player);
10277         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10278
10279         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10280                 player->bitrate[i] = 0;
10281                 player->maximum_bitrate[i] = 0;
10282         }
10283
10284         if (player->v_stream_caps) {
10285                 gst_caps_unref(player->v_stream_caps);
10286                 player->v_stream_caps = NULL;
10287         }
10288
10289         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10290
10291         /* clean found parsers */
10292         if (player->parsers) {
10293                 GList *parsers = player->parsers;
10294                 for (; parsers; parsers = g_list_next(parsers)) {
10295                         gchar *name = parsers->data;
10296                         MMPLAYER_FREEIF(name);
10297                 }
10298                 g_list_free(player->parsers);
10299                 player->parsers = NULL;
10300         }
10301
10302         /* clean found audio decoders */
10303         if (player->audio_decoders) {
10304                 GList *a_dec = player->audio_decoders;
10305                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10306                         gchar *name = a_dec->data;
10307                         MMPLAYER_FREEIF(name);
10308                 }
10309                 g_list_free(player->audio_decoders);
10310                 player->audio_decoders = NULL;
10311         }
10312
10313         MMPLAYER_FLEAVE();
10314 }
10315
10316 static void
10317 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10318 {
10319         MMPlayerGstElement *mainbin = NULL;
10320         MMMessageParamType msg_param = {0,};
10321         GstElement *element = NULL;
10322         MMHandleType attrs = 0;
10323         char *uri = NULL;
10324         enum MainElementID elemId = MMPLAYER_M_NUM;
10325
10326         MMPLAYER_FENTER();
10327
10328         if ((player == NULL) ||
10329                 (player->pipeline == NULL) ||
10330                 (player->pipeline->mainbin == NULL)) {
10331                 LOGE("player is null.\n");
10332                 goto ERROR;
10333         }
10334
10335         mainbin = player->pipeline->mainbin;
10336         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10337
10338         attrs = MMPLAYER_GET_ATTRS(player);
10339         if (!attrs) {
10340                 LOGE("fail to get attributes.\n");
10341                 goto ERROR;
10342         }
10343
10344         /* Initialize Player values */
10345         __mmplayer_initialize_next_play(player);
10346
10347         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10348
10349         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10350                 LOGE("failed to parse profile\n");
10351                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10352                 goto ERROR;
10353         }
10354
10355         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10356                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10357                 LOGE("it's dash or hls. not support.");
10358                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10359                 goto ERROR;
10360         }
10361
10362         /* setup source */
10363         switch (player->profile.uri_type) {
10364         /* file source */
10365         case MM_PLAYER_URI_TYPE_FILE:
10366         {
10367                 LOGD("using filesrc for 'file://' handler.\n");
10368                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10369                         LOGE("failed to get storage info");
10370                         break;
10371                 }
10372
10373                 element = gst_element_factory_make("filesrc", "source");
10374
10375                 if (!element) {
10376                         LOGE("failed to create filesrc\n");
10377                         break;
10378                 }
10379
10380                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10381                 break;
10382         }
10383         case MM_PLAYER_URI_TYPE_URL_HTTP:
10384         {
10385                 gchar *user_agent, *cookies, **cookie_list;
10386                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10387                 user_agent = cookies = NULL;
10388                 cookie_list = NULL;
10389
10390                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10391                 if (!element) {
10392                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10393                         break;
10394                 }
10395                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10396
10397                 /* get attribute */
10398                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10399                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10400
10401                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10402                         LOGD("get timeout from ini\n");
10403                         http_timeout = player->ini.http_timeout;
10404                 }
10405
10406                 /* get attribute */
10407                 SECURE_LOGD("location : %s\n", player->profile.uri);
10408                 SECURE_LOGD("cookies : %s\n", cookies);
10409                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10410                 LOGD("timeout : %d\n", http_timeout);
10411
10412                 /* setting property to streaming source */
10413                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10414                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10415                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10416
10417                 /* parsing cookies */
10418                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10419                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10420                 if (user_agent)
10421                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10422                 break;
10423         }
10424         default:
10425                 LOGE("not support uri type %d\n", player->profile.uri_type);
10426                 break;
10427         }
10428
10429         if (!element) {
10430                 LOGE("no source element was created.\n");
10431                 goto ERROR;
10432         }
10433
10434         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10435                 LOGE("failed to add source element to pipeline\n");
10436                 gst_object_unref(GST_OBJECT(element));
10437                 element = NULL;
10438                 goto ERROR;
10439         }
10440
10441         /* take source element */
10442         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10443         mainbin[MMPLAYER_M_SRC].gst = element;
10444
10445         element = NULL;
10446
10447         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10448                 if (player->streamer == NULL) {
10449                         player->streamer = __mm_player_streaming_create();
10450                         __mm_player_streaming_initialize(player->streamer);
10451                 }
10452
10453                 elemId = MMPLAYER_M_TYPEFIND;
10454                 element = gst_element_factory_make("typefind", "typefinder");
10455                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10456                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10457         } else {
10458                 elemId = MMPLAYER_M_AUTOPLUG;
10459                 element = __mmplayer_create_decodebin(player);
10460         }
10461
10462         /* check autoplug element is OK */
10463         if (!element) {
10464                 LOGE("can not create element(%d)\n", elemId);
10465                 goto ERROR;
10466         }
10467
10468         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10469                 LOGE("failed to add sinkbin to pipeline\n");
10470                 gst_object_unref(GST_OBJECT(element));
10471                 element = NULL;
10472                 goto ERROR;
10473         }
10474
10475         mainbin[elemId].id = elemId;
10476         mainbin[elemId].gst = element;
10477
10478         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10479                 LOGE("Failed to link src - autoplug(or typefind)\n");
10480                 goto ERROR;
10481         }
10482
10483         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10484                 LOGE("Failed to change state of src element\n");
10485                 goto ERROR;
10486         }
10487
10488         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10489                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10490                         LOGE("Failed to change state of decodebin\n");
10491                         goto ERROR;
10492                 }
10493         } else {
10494                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10495                         LOGE("Failed to change state of src element\n");
10496                         goto ERROR;
10497                 }
10498         }
10499
10500         player->gapless.stream_changed = TRUE;
10501         player->gapless.running = TRUE;
10502         MMPLAYER_FLEAVE();
10503         return;
10504
10505 ERROR:
10506         if (player) {
10507                 MMPLAYER_PLAYBACK_UNLOCK(player);
10508
10509                 if (!player->msg_posted) {
10510                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10511                         player->msg_posted = TRUE;
10512                 }
10513         }
10514         return;
10515 }
10516
10517 static gboolean
10518 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10519 {
10520         mm_player_selector_t *selector = &player->selector[type];
10521         MMPlayerGstElement *sinkbin = NULL;
10522         enum MainElementID selectorId = MMPLAYER_M_NUM;
10523         enum MainElementID sinkId = MMPLAYER_M_NUM;
10524         GstPad *srcpad = NULL;
10525         GstPad *sinkpad = NULL;
10526         gboolean send_notice = FALSE;
10527
10528         MMPLAYER_FENTER();
10529         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10530
10531         LOGD("type %d", type);
10532
10533         switch (type) {
10534         case MM_PLAYER_TRACK_TYPE_AUDIO:
10535                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10536                 sinkId = MMPLAYER_A_BIN;
10537                 sinkbin = player->pipeline->audiobin;
10538                 break;
10539         case MM_PLAYER_TRACK_TYPE_VIDEO:
10540                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10541                 sinkId = MMPLAYER_V_BIN;
10542                 sinkbin = player->pipeline->videobin;
10543                 send_notice = TRUE;
10544                 break;
10545         case MM_PLAYER_TRACK_TYPE_TEXT:
10546                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10547                 sinkId = MMPLAYER_T_BIN;
10548                 sinkbin = player->pipeline->textbin;
10549                 break;
10550         default:
10551                 LOGE("requested type is not supportable");
10552                 return FALSE;
10553                 break;
10554         }
10555
10556         if (player->pipeline->mainbin[selectorId].gst) {
10557                 gint n;
10558
10559                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10560
10561                 if (selector->event_probe_id != 0)
10562                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10563                 selector->event_probe_id = 0;
10564
10565                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10566                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10567
10568                         if (srcpad && sinkpad) {
10569                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10570                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10571                                 gst_pad_unlink(srcpad, sinkpad);
10572
10573                                 /* send custom event to sink pad to handle it at video sink */
10574                                 if (send_notice) {
10575                                         LOGD("send custom event to sinkpad");
10576                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10577                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10578                                         gst_pad_send_event(sinkpad, event);
10579                                 }
10580                         }
10581
10582                         gst_object_unref(sinkpad);
10583                         sinkpad = NULL;
10584                 }
10585                 gst_object_unref(srcpad);
10586                 srcpad = NULL;
10587
10588                 LOGD("selector release");
10589
10590                 /* release and unref requests pad from the selector */
10591                 for (n = 0; n < selector->channels->len; n++) {
10592                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10593                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10594                 }
10595                 g_ptr_array_set_size(selector->channels, 0);
10596
10597                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10598                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10599
10600                 player->pipeline->mainbin[selectorId].gst = NULL;
10601                 selector = NULL;
10602         }
10603
10604         return TRUE;
10605 }
10606
10607 static void
10608 __mmplayer_deactivate_old_path(mm_player_t *player)
10609 {
10610         MMPLAYER_FENTER();
10611         MMPLAYER_RETURN_IF_FAIL(player);
10612
10613         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10614                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10615                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10616                 LOGE("deactivate selector error");
10617                 goto ERROR;
10618         }
10619
10620         _mmplayer_track_destroy(player);
10621         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10622
10623         if (player->streamer) {
10624                 __mm_player_streaming_deinitialize(player->streamer);
10625                 __mm_player_streaming_destroy(player->streamer);
10626                 player->streamer = NULL;
10627         }
10628
10629         MMPLAYER_PLAYBACK_LOCK(player);
10630         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10631
10632         MMPLAYER_FLEAVE();
10633         return;
10634
10635 ERROR:
10636
10637         if (!player->msg_posted) {
10638                 MMMessageParamType msg = {0,};
10639
10640                 /*post error*/
10641                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10642                 LOGE("next_uri_play> deactivate error");
10643
10644                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10645                 player->msg_posted = TRUE;
10646         }
10647         return;
10648 }
10649
10650 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10651 {
10652         int result = MM_ERROR_NONE;
10653         mm_player_t* player = (mm_player_t*) hplayer;
10654         MMPLAYER_FENTER();
10655
10656         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10657
10658         if (file_path) {
10659                 player->http_file_buffering_path = (gchar*)file_path;
10660                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10661         }
10662         MMPLAYER_FLEAVE();
10663         return result;
10664 }
10665
10666 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10667 {
10668         int result = MM_ERROR_NONE;
10669         mm_player_t* player = (mm_player_t*) hplayer;
10670         MMPLAYER_FENTER();
10671
10672         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10673
10674         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10675         if (mmf_attrs_commit(player->attrs)) {
10676                 LOGE("failed to commit the original uri.\n");
10677                 result = MM_ERROR_PLAYER_INTERNAL;
10678         } else {
10679                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10680                         LOGE("failed to add the original uri in the uri list.\n");
10681         }
10682
10683         MMPLAYER_FLEAVE();
10684         return result;
10685 }
10686
10687 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10688 {
10689         mm_player_t* player = (mm_player_t*) hplayer;
10690         guint num_of_list = 0;
10691
10692         MMPLAYER_FENTER();
10693
10694         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10695         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10696
10697         if (player->pipeline && player->pipeline->textbin) {
10698                 LOGE("subtitle path is enabled.\n");
10699                 return MM_ERROR_PLAYER_INVALID_STATE;
10700         }
10701
10702         num_of_list = g_list_length(player->uri_info.uri_list);
10703
10704         if (is_first_path == TRUE) {
10705                 if (num_of_list == 0) {
10706                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10707                         LOGD("add original path : %s", uri);
10708                 } else {
10709                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10710                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10711
10712                         LOGD("change original path : %s", uri);
10713                 }
10714         } else {
10715                 MMHandleType attrs = 0;
10716                 attrs = MMPLAYER_GET_ATTRS(player);
10717
10718                 if (num_of_list == 0) {
10719                         char *original_uri = NULL;
10720
10721                         if (attrs) {
10722                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10723
10724                                 if (!original_uri) {
10725                                         LOGE("there is no original uri.");
10726                                         return MM_ERROR_PLAYER_INVALID_STATE;
10727                                 }
10728
10729                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10730                                 player->uri_info.uri_idx = 0;
10731
10732                                 LOGD("add original path at first : %s(%d)", original_uri);
10733                         }
10734                 }
10735
10736                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10737                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10738         }
10739
10740         MMPLAYER_FLEAVE();
10741         return MM_ERROR_NONE;
10742 }
10743
10744 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10745 {
10746         mm_player_t* player = (mm_player_t*) hplayer;
10747         char *next_uri = NULL;
10748         guint num_of_list = 0;
10749
10750         MMPLAYER_FENTER();
10751         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10752
10753         num_of_list = g_list_length(player->uri_info.uri_list);
10754
10755         if (num_of_list > 0) {
10756                 gint uri_idx = player->uri_info.uri_idx;
10757
10758                 if (uri_idx < num_of_list-1)
10759                         uri_idx++;
10760                 else
10761                         uri_idx = 0;
10762
10763                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10764                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10765
10766                 *uri = g_strdup(next_uri);
10767         }
10768
10769         MMPLAYER_FLEAVE();
10770         return MM_ERROR_NONE;
10771 }
10772
10773 static void
10774 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10775 GstCaps *caps, gpointer data)
10776 {
10777         mm_player_t* player = (mm_player_t*)data;
10778         const gchar* klass = NULL;
10779         const gchar* mime = NULL;
10780         gchar* caps_str = NULL;
10781
10782         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10783         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10784         caps_str = gst_caps_to_string(caps);
10785
10786         LOGW("unknown type of caps : %s from %s",
10787                                         caps_str, GST_ELEMENT_NAME(elem));
10788
10789         MMPLAYER_FREEIF(caps_str);
10790
10791         /* There is no available codec. */
10792         __mmplayer_check_not_supported_codec(player, klass, mime);
10793 }
10794
10795 static gboolean
10796 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10797 GstCaps * caps,  gpointer data)
10798 {
10799         mm_player_t* player = (mm_player_t*)data;
10800         const char* mime = NULL;
10801         gboolean ret = TRUE;
10802
10803         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10804         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10805
10806         if (g_str_has_prefix(mime, "audio")) {
10807                 GstStructure* caps_structure = NULL;
10808                 gint samplerate = 0;
10809                 gint channels = 0;
10810                 gchar *caps_str = NULL;
10811
10812                 caps_structure = gst_caps_get_structure(caps, 0);
10813                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10814                 gst_structure_get_int(caps_structure, "channels", &channels);
10815
10816                 if ((channels > 0 && samplerate == 0)) {
10817                         LOGD("exclude audio...");
10818                         ret = FALSE;
10819                 }
10820
10821                 caps_str = gst_caps_to_string(caps);
10822                 /* set it directly because not sent by TAG */
10823                 if (g_strrstr(caps_str, "mobile-xmf"))
10824                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10825                 MMPLAYER_FREEIF(caps_str);
10826         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10827                 MMMessageParamType msg_param;
10828                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10829                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10830                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10831                 LOGD("video file is not supported on this device");
10832                 ret = FALSE;
10833         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10834                 LOGD("already video linked");
10835                 ret = FALSE;
10836         } else {
10837                 LOGD("found new stream");
10838         }
10839
10840         return ret;
10841 }
10842
10843 static int
10844 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10845 {
10846         int ret = MM_ERROR_NONE;
10847         int idx = 0;
10848         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10849
10850         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10851                 GstStructure* str = NULL;
10852                 gint channels = 0;
10853                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10854
10855                 LOGD("audio codec type: %d", codec_type);
10856                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10857                         /* sw codec will be skipped */
10858                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10859                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10860                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10861                                         ret = MM_ERROR_PLAYER_INTERNAL;
10862                                         goto DONE;
10863                                 }
10864                         }
10865                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10866                         /* hw codec will be skipped */
10867                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10868                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10869                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10870                                 ret = MM_ERROR_PLAYER_INTERNAL;
10871                                 goto DONE;
10872                         }
10873                 }
10874
10875                 str = gst_caps_get_structure(caps, 0);
10876                 if (str) {
10877                         gst_structure_get_int(str, "channels", &channels);
10878
10879                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10880                         if (player->max_audio_channels < channels)
10881                                 player->max_audio_channels = channels;
10882                 }
10883                 /* set stream information */
10884                 if (!player->audiodec_linked)
10885                         __mmplayer_set_audio_attrs(player, caps);
10886
10887                 /* update codec info */
10888                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10889                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10890                 player->audiodec_linked = 1;
10891
10892         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10893
10894                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10895
10896                 LOGD("video codec type: %d", codec_type);
10897                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10898                         /* sw codec is skipped */
10899                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10900                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10901                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10902                                         ret = MM_ERROR_PLAYER_INTERNAL;
10903                                         goto DONE;
10904                                 }
10905                         }
10906                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10907                         /* hw codec is skipped */
10908                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10909                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10910                                 ret = MM_ERROR_PLAYER_INTERNAL;
10911                                 goto DONE;
10912                         }
10913                 }
10914
10915                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10916                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10917
10918                         /* mark video decoder for acquire */
10919                         if (player->video_decoder_resource == NULL) {
10920                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10921                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10922                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10923                                                 &player->video_decoder_resource)
10924                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10925                                         LOGE("could not mark video_decoder resource for acquire");
10926                                         ret = MM_ERROR_PLAYER_INTERNAL;
10927                                         goto DONE;
10928                                 }
10929                         } else {
10930                                 LOGW("video decoder resource is already acquired, skip it.");
10931                                 ret = MM_ERROR_PLAYER_INTERNAL;
10932                                 goto DONE;
10933                         }
10934
10935                         player->interrupted_by_resource = FALSE;
10936                         /* acquire resources for video playing */
10937                         if (mm_resource_manager_commit(player->resource_manager)
10938                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10939                                 LOGE("could not acquire resources for video decoding\n");
10940                                 ret = MM_ERROR_PLAYER_INTERNAL;
10941                                 goto DONE;
10942                         }
10943                 }
10944
10945                 /* update codec info */
10946                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10947                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10948                 player->videodec_linked = 1;
10949         }
10950
10951 DONE:
10952         return ret;
10953 }
10954
10955 static gint
10956 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10957 GstCaps* caps, GstElementFactory* factory, gpointer data)
10958 {
10959         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10960          We are defining our own and will be removed when it actually exposed */
10961         typedef enum {
10962                 GST_AUTOPLUG_SELECT_TRY,
10963                 GST_AUTOPLUG_SELECT_EXPOSE,
10964                 GST_AUTOPLUG_SELECT_SKIP
10965         } GstAutoplugSelectResult;
10966
10967         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10968         mm_player_t* player = (mm_player_t*)data;
10969
10970         gchar* factory_name = NULL;
10971         gchar* caps_str = NULL;
10972         const gchar* klass = NULL;
10973         gint idx = 0;
10974
10975         factory_name = GST_OBJECT_NAME(factory);
10976         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10977         caps_str = gst_caps_to_string(caps);
10978
10979         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10980
10981         /* store type string */
10982         if (player->type == NULL) {
10983                 player->type = gst_caps_to_string(caps);
10984                 __mmplayer_update_content_type_info(player);
10985         }
10986
10987         /* filtering exclude keyword */
10988         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10989                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10990                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10991                                         factory_name, player->ini.exclude_element_keyword[idx]);
10992
10993                         result = GST_AUTOPLUG_SELECT_SKIP;
10994                         goto DONE;
10995                 }
10996         }
10997
10998         /* exclude webm format */
10999         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11000          * because webm format is not supportable.
11001          * If webm is disabled in "autoplug-continue", there is no state change
11002          * failure or error because the decodebin will expose the pad directly.
11003          * It make MSL invoke _prepare_async_callback.
11004          * So, we need to disable webm format in "autoplug-select" */
11005         if (caps_str && strstr(caps_str, "webm")) {
11006                 LOGW("webm is not supported");
11007                 result = GST_AUTOPLUG_SELECT_SKIP;
11008                 goto DONE;
11009         }
11010
11011         /* check factory class for filtering */
11012         /* NOTE : msl don't need to use image plugins.
11013          * So, those plugins should be skipped for error handling.
11014          */
11015         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11016                 LOGD("skipping [%s] by not required\n", factory_name);
11017                 result = GST_AUTOPLUG_SELECT_SKIP;
11018                 goto DONE;
11019         }
11020
11021         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11022                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11023                 // TO CHECK : subtitle if needed, add subparse exception.
11024                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11025                 result = GST_AUTOPLUG_SELECT_SKIP;
11026                 goto DONE;
11027         }
11028
11029         if (g_strrstr(factory_name, "mpegpsdemux")) {
11030                 LOGD("skipping PS container - not support\n");
11031                 result = GST_AUTOPLUG_SELECT_SKIP;
11032                 goto DONE;
11033         }
11034
11035         if (g_strrstr(factory_name, "mssdemux"))
11036                 player->smooth_streaming = TRUE;
11037
11038         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11039                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11040                 gint stype = 0;
11041                 gint width = 0;
11042                 GstStructure *str = NULL;
11043                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11044
11045                 /* don't make video because of not required */
11046                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11047                         (player->set_mode.media_packet_video_stream == FALSE)) {
11048                         LOGD("no video because it's not required. -> return expose");
11049                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11050                         goto DONE;
11051                 }
11052
11053                 /* get w/h for omx state-tune */
11054                 /* FIXME: deprecated? */
11055                 str = gst_caps_get_structure(caps, 0);
11056                 gst_structure_get_int(str, "width", &width);
11057
11058                 if (width != 0) {
11059                         if (player->v_stream_caps) {
11060                                 gst_caps_unref(player->v_stream_caps);
11061                                 player->v_stream_caps = NULL;
11062                         }
11063
11064                         player->v_stream_caps = gst_caps_copy(caps);
11065                         LOGD("take caps for video state tune");
11066                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11067                 }
11068         }
11069
11070         if (g_strrstr(klass, "Codec/Decoder")) {
11071                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11072                         LOGD("skipping %s codec", factory_name);
11073                         result = GST_AUTOPLUG_SELECT_SKIP;
11074                         goto DONE;
11075                 }
11076         }
11077
11078 DONE:
11079         MMPLAYER_FREEIF(caps_str);
11080
11081         return result;
11082 }
11083
11084 static void
11085 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11086 gpointer data)
11087 {
11088         //mm_player_t* player = (mm_player_t*)data;
11089         GstCaps* caps = NULL;
11090
11091         LOGD("[Decodebin2] pad-removed signal\n");
11092
11093         caps = gst_pad_query_caps(new_pad, NULL);
11094         if (caps) {
11095                 gchar* caps_str = NULL;
11096                 caps_str = gst_caps_to_string(caps);
11097
11098                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11099
11100                 MMPLAYER_FREEIF(caps_str);
11101                 gst_caps_unref(caps);
11102         }
11103 }
11104
11105 static void
11106 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11107 {
11108         mm_player_t* player = (mm_player_t*)data;
11109         GstIterator *iter = NULL;
11110         GValue item = { 0, };
11111         GstPad *pad = NULL;
11112         gboolean done = FALSE;
11113         gboolean is_all_drained = TRUE;
11114
11115         MMPLAYER_FENTER();
11116         MMPLAYER_RETURN_IF_FAIL(player);
11117
11118         LOGD("__mmplayer_gst_decode_drained");
11119
11120         if (player->use_deinterleave == TRUE) {
11121                 LOGD("group playing mode.");
11122                 return;
11123         }
11124
11125         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11126                 LOGW("Fail to get cmd lock");
11127                 return;
11128         }
11129
11130         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11131                 !__mmplayer_verify_next_play_path(player)) {
11132                 LOGD("decoding is finished.");
11133                 __mmplayer_reset_gapless_state(player);
11134                 MMPLAYER_CMD_UNLOCK(player);
11135                 return;
11136         }
11137
11138         player->gapless.reconfigure = TRUE;
11139
11140         /* check decodebin src pads whether they received EOS or not */
11141         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11142
11143         while (!done) {
11144                 switch (gst_iterator_next(iter, &item)) {
11145                 case GST_ITERATOR_OK:
11146                         pad = g_value_get_object(&item);
11147                         if (pad && !GST_PAD_IS_EOS(pad)) {
11148                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11149                                 is_all_drained = FALSE;
11150                                 break;
11151                         }
11152                         g_value_reset(&item);
11153                         break;
11154                 case GST_ITERATOR_RESYNC:
11155                         gst_iterator_resync(iter);
11156                         break;
11157                 case GST_ITERATOR_ERROR:
11158                 case GST_ITERATOR_DONE:
11159                         done = TRUE;
11160                         break;
11161                 }
11162         }
11163         g_value_unset(&item);
11164         gst_iterator_free(iter);
11165
11166         if (!is_all_drained) {
11167                 LOGD("Wait util the all pads get EOS.");
11168                 MMPLAYER_CMD_UNLOCK(player);
11169                 MMPLAYER_FLEAVE();
11170                 return;
11171         }
11172
11173         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11174         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11175
11176         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11177         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11178         __mmplayer_deactivate_old_path(player);
11179         MMPLAYER_CMD_UNLOCK(player);
11180
11181         MMPLAYER_FLEAVE();
11182 }
11183
11184 static void
11185 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11186 {
11187         mm_player_t* player = (mm_player_t*)data;
11188         const gchar* klass = NULL;
11189         gchar* factory_name = NULL;
11190
11191         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11192         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11193
11194         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11195
11196         if (__mmplayer_add_dump_buffer_probe(player, element))
11197                 LOGD("add buffer probe");
11198
11199         //<-
11200         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11201                 gchar* selected = NULL;
11202                 selected = g_strdup(GST_ELEMENT_NAME(element));
11203                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11204         }
11205         //-> temp code
11206
11207         if (g_strrstr(klass, "Parser")) {
11208                 gchar* selected = NULL;
11209
11210                 selected = g_strdup(factory_name);
11211                 player->parsers = g_list_append(player->parsers, selected);
11212         }
11213
11214         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11215                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11216                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11217
11218                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11219                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11220
11221                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11222                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11223                                                 "max-video-width", player->adaptive_info.limit.width,
11224                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11225
11226         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11227                 /* FIXIT : first value will be overwritten if there's more
11228                  * than 1 demuxer/parser
11229                  */
11230
11231                 //LOGD("plugged element is demuxer. take it\n");
11232                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11233                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11234
11235                 /*Added for multi audio support */ // Q. del?
11236                 if (g_strrstr(klass, "Demux")) {
11237                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11238                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11239                 }
11240         }
11241
11242         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11243                 int surface_type = 0;
11244
11245                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11246         }
11247
11248         // to support trust-zone only
11249         if (g_strrstr(factory_name, "asfdemux")) {
11250                 LOGD("set file-location %s\n", player->profile.uri);
11251                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11252
11253                 if (player->video_hub_download_mode == TRUE)
11254                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11255         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11256                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11257                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11258         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11259                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11260                         (__mmplayer_is_only_mp3_type(player->type))) {
11261                         LOGD("[mpegaudioparse] set streaming pull mode.");
11262                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11263                 }
11264         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11265                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11266         }
11267
11268         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11269                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11270                 LOGD("plugged element is multiqueue. take it\n");
11271
11272                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11273                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11274
11275                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11276                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11277                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11278                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11279                         __mm_player_streaming_set_multiqueue(player->streamer,
11280                                 element,
11281                                 TRUE,
11282                                 player->ini.http_buffering_time,
11283                                 1.0,
11284                                 player->ini.http_buffering_limit);
11285
11286                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11287                 }
11288         }
11289
11290         return;
11291 }
11292
11293 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11294 {
11295         MMPLAYER_FENTER();
11296         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11297
11298         if (MMPLAYER_IS_STREAMING(player))
11299                 return FALSE;
11300
11301         /* This callback can be set to music player only. */
11302         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11303                 LOGW("audio callback is not supported for video");
11304                 return FALSE;
11305         }
11306
11307         if (player->audio_stream_cb) {
11308                 GstPad *pad = NULL;
11309
11310                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11311
11312                 if (!pad) {
11313                         LOGE("failed to get sink pad from audiosink to probe data\n");
11314                         return FALSE;
11315                 }
11316                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11317                         __mmplayer_audio_stream_probe, player, NULL);
11318
11319                 gst_object_unref(pad);
11320
11321                 pad = NULL;
11322         } else {
11323                 LOGE("There is no audio callback to configure.\n");
11324                 return FALSE;
11325         }
11326
11327         MMPLAYER_FLEAVE();
11328
11329         return TRUE;
11330 }
11331
11332 static void
11333 __mmplayer_release_misc(mm_player_t* player)
11334 {
11335         int i;
11336         bool cur_mode = player->set_mode.rich_audio;
11337         MMPLAYER_FENTER();
11338
11339         MMPLAYER_RETURN_IF_FAIL(player);
11340
11341         player->video_stream_cb = NULL;
11342         player->video_stream_cb_user_param = NULL;
11343         player->video_stream_prerolled = FALSE;
11344
11345         player->audio_stream_cb = NULL;
11346         player->audio_stream_render_cb_ex = NULL;
11347         player->audio_stream_cb_user_param = NULL;
11348         player->audio_stream_sink_sync = false;
11349
11350         player->video_stream_changed_cb = NULL;
11351         player->video_stream_changed_cb_user_param = NULL;
11352
11353         player->audio_stream_changed_cb = NULL;
11354         player->audio_stream_changed_cb_user_param = NULL;
11355
11356         player->sent_bos = FALSE;
11357         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11358
11359         player->doing_seek = FALSE;
11360
11361         player->total_bitrate = 0;
11362         player->total_maximum_bitrate = 0;
11363
11364         player->not_found_demuxer = 0;
11365
11366         player->last_position = 0;
11367         player->duration = 0;
11368         player->http_content_size = 0;
11369         player->not_supported_codec = MISSING_PLUGIN_NONE;
11370         player->can_support_codec = FOUND_PLUGIN_NONE;
11371         player->pending_seek.is_pending = FALSE;
11372         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11373         player->pending_seek.pos = 0;
11374         player->msg_posted = FALSE;
11375         player->has_many_types = FALSE;
11376         player->max_audio_channels = 0;
11377         player->video_share_api_delta = 0;
11378         player->video_share_clock_delta = 0;
11379         player->is_subtitle_force_drop = FALSE;
11380         player->play_subtitle = FALSE;
11381         player->adjust_subtitle_pos = 0;
11382         player->last_multiwin_status = FALSE;
11383         player->has_closed_caption = FALSE;
11384         player->set_mode.media_packet_video_stream = FALSE;
11385         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11386         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11387         /* recover mode */
11388         player->set_mode.rich_audio = cur_mode;
11389
11390         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11391                 player->bitrate[i] = 0;
11392                 player->maximum_bitrate[i] = 0;
11393         }
11394
11395         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11396
11397         /* remove media stream cb(appsrc cb) */
11398         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11399                 player->media_stream_buffer_status_cb[i] = NULL;
11400                 player->media_stream_seek_data_cb[i] = NULL;
11401                 player->buffer_cb_user_param[i] = NULL;
11402                 player->seek_cb_user_param[i] = NULL;
11403         }
11404         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11405
11406         /* free memory related to audio effect */
11407         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11408
11409         if (player->adaptive_info.var_list) {
11410                 g_list_free_full(player->adaptive_info.var_list, g_free);
11411                 player->adaptive_info.var_list = NULL;
11412         }
11413
11414         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11415         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11416         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11417
11418         /* Reset video360 settings to their defaults in case if the pipeline is to be
11419          * re-created.
11420          * */
11421         player->video360_metadata.is_spherical = -1;
11422         player->is_openal_plugin_used = FALSE;
11423
11424         player->is_content_spherical = FALSE;
11425         player->is_video360_enabled = TRUE;
11426         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11427         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11428         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11429         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11430         player->video360_zoom = 1.0f;
11431         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11432         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11433
11434         player->sound.rg_enable = false;
11435
11436         MMPLAYER_FLEAVE();
11437 }
11438
11439 static void
11440 __mmplayer_release_misc_post(mm_player_t* player)
11441 {
11442         char *original_uri = NULL;
11443         MMPLAYER_FENTER();
11444
11445         /* player->pipeline is already released before. */
11446
11447         MMPLAYER_RETURN_IF_FAIL(player);
11448
11449         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11450
11451         /* clean found parsers */
11452         if (player->parsers) {
11453                 GList *parsers = player->parsers;
11454                 for (; parsers; parsers = g_list_next(parsers)) {
11455                         gchar *name = parsers->data;
11456                         MMPLAYER_FREEIF(name);
11457                 }
11458                 g_list_free(player->parsers);
11459                 player->parsers = NULL;
11460         }
11461
11462         /* clean found audio decoders */
11463         if (player->audio_decoders) {
11464                 GList *a_dec = player->audio_decoders;
11465                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11466                         gchar *name = a_dec->data;
11467                         MMPLAYER_FREEIF(name);
11468                 }
11469                 g_list_free(player->audio_decoders);
11470                 player->audio_decoders = NULL;
11471         }
11472
11473         /* clean the uri list except original uri */
11474         if (player->uri_info.uri_list) {
11475                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11476
11477                 if (player->attrs) {
11478                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11479                         LOGD("restore original uri = %s\n", original_uri);
11480
11481                         if (mmf_attrs_commit(player->attrs))
11482                                 LOGE("failed to commit the original uri.\n");
11483                 }
11484
11485                 GList *uri_list = player->uri_info.uri_list;
11486                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11487                         gchar *uri = uri_list->data;
11488                         MMPLAYER_FREEIF(uri);
11489                 }
11490                 g_list_free(player->uri_info.uri_list);
11491                 player->uri_info.uri_list = NULL;
11492         }
11493
11494         /* clear the audio stream buffer list */
11495         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11496
11497         /* clear the video stream bo list */
11498         __mmplayer_video_stream_destroy_bo_list(player);
11499         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11500
11501         if (player->profile.input_mem.buf) {
11502                 free(player->profile.input_mem.buf);
11503                 player->profile.input_mem.buf = NULL;
11504         }
11505         player->profile.input_mem.len = 0;
11506         player->profile.input_mem.offset = 0;
11507
11508         player->uri_info.uri_idx = 0;
11509         MMPLAYER_FLEAVE();
11510 }
11511
11512 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11513 {
11514         GstElement *element = NULL;
11515         GstPad *sinkpad;
11516
11517         LOGD("creating %s to plug\n", name);
11518
11519         element = gst_element_factory_make(name, NULL);
11520         if (!element) {
11521                 LOGE("failed to create queue\n");
11522                 return NULL;
11523         }
11524
11525         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11526                 LOGE("failed to set state READY to %s\n", name);
11527                 gst_object_unref(element);
11528                 return NULL;
11529         }
11530
11531         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11532                 LOGE("failed to add %s\n", name);
11533                 gst_object_unref(element);
11534                 return NULL;
11535         }
11536
11537         sinkpad = gst_element_get_static_pad(element, "sink");
11538
11539         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11540                 LOGE("failed to link %s\n", name);
11541                 gst_object_unref(sinkpad);
11542                 gst_object_unref(element);
11543                 return NULL;
11544         }
11545
11546         LOGD("linked %s to pipeline successfully\n", name);
11547
11548         gst_object_unref(sinkpad);
11549
11550         return element;
11551 }
11552
11553 gboolean
11554 __mmplayer_check_subtitle(mm_player_t* player)
11555 {
11556         MMHandleType attrs = 0;
11557         char *subtitle_uri = NULL;
11558
11559         MMPLAYER_FENTER();
11560
11561         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11562
11563         /* get subtitle attribute */
11564         attrs = MMPLAYER_GET_ATTRS(player);
11565         if (!attrs)
11566                 return FALSE;
11567
11568         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11569         if (!subtitle_uri || !strlen(subtitle_uri))
11570                 return FALSE;
11571
11572         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11573         player->is_external_subtitle_present = TRUE;
11574
11575         MMPLAYER_FLEAVE();
11576
11577         return TRUE;
11578 }
11579
11580 static gboolean
11581 __mmplayer_can_extract_pcm(mm_player_t* player)
11582 {
11583         MMHandleType attrs = 0;
11584         gboolean sound_extraction = FALSE;
11585
11586         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11587
11588         attrs = MMPLAYER_GET_ATTRS(player);
11589         if (!attrs) {
11590                 LOGE("fail to get attributes.");
11591                 return FALSE;
11592         }
11593
11594         /* get sound_extraction property */
11595         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11596
11597         if (!sound_extraction) {
11598                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11599                 return FALSE;
11600         }
11601
11602         return TRUE;
11603 }
11604
11605 static gboolean
11606 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11607 {
11608         LOGD("\n");
11609         MMMessageParamType msg_param;
11610         gchar *msg_src_element = NULL;
11611         GstStructure *s = NULL;
11612         guint error_id = 0;
11613         gchar *error_string = NULL;
11614
11615         MMPLAYER_FENTER();
11616
11617         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11618         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11619
11620         s = gst_structure_copy(gst_message_get_structure(message));
11621
11622
11623         if (!gst_structure_get_uint(s, "error_id", &error_id))
11624                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11625
11626         switch (error_id) {
11627         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11628                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11629                 break;
11630         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11631                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11632                 break;
11633         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11634                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11635                 break;
11636         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11637                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11638                 break;
11639         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11640                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11641                 break;
11642         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11643                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11644                 break;
11645         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11646                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11647                 break;
11648         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11649                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11650                 break;
11651         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11652                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11653                 break;
11654         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11655                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11656                 break;
11657         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11658                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11659                 break;
11660         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11661                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11662                 break;
11663         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11664                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11665                 break;
11666         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11667                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11668                 break;
11669         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11670                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11671                 break;
11672         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11673                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11674                 break;
11675         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11676                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11677                 break;
11678         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11679                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11680                 break;
11681         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11682                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11683                 break;
11684         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11685                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11686                 break;
11687         case MMPLAYER_STREAMING_ERROR_GONE:
11688                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11689                 break;
11690         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11691                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11692                 break;
11693         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11694                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11695                 break;
11696         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11697                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11698                 break;
11699         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11700                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11701                 break;
11702         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11703                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11704                 break;
11705         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11706                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11707                 break;
11708         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11709                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11710                 break;
11711         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11712                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11713                 break;
11714         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11715                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11716                 break;
11717         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11718                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11719                 break;
11720         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11721                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11722                 break;
11723         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11724                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11725                 break;
11726         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11727                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11728                 break;
11729         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11730                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11731                 break;
11732         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11733                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11734                 break;
11735         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11736                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11737                 break;
11738         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11739                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11740                 break;
11741         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11742                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11743                 break;
11744         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11745                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11746                 break;
11747         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11748                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11749                 break;
11750         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11751                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11752                 break;
11753         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11754                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11755                 break;
11756         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11757                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11758                 break;
11759         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11760                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11761                 break;
11762         default:
11763                 {
11764                         gst_structure_free(s);
11765                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11766                 }
11767         }
11768
11769         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11770         if (error_string)
11771                 msg_param.data = (void *) error_string;
11772
11773         if (message->src) {
11774                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11775
11776                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11777                         msg_src_element, msg_param.code, (char*)msg_param.data);
11778         }
11779
11780         /* post error to application */
11781         if (!player->msg_posted) {
11782                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11783
11784                 /* don't post more if one was sent already */
11785                 player->msg_posted = TRUE;
11786         } else
11787                 LOGD("skip error post because it's sent already.\n");
11788
11789         gst_structure_free(s);
11790         MMPLAYER_FLEAVE();
11791         g_free(error_string);
11792
11793         return TRUE;
11794
11795 }
11796
11797 static void
11798 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11799 {
11800         MMPLAYER_RETURN_IF_FAIL(player);
11801
11802         /* post now if delay is zero */
11803         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11804                 LOGD("eos delay is zero. posting EOS now\n");
11805                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11806
11807                 if (player->set_mode.pcm_extraction)
11808                         __mmplayer_cancel_eos_timer(player);
11809
11810                 return;
11811         }
11812
11813         /* cancel if existing */
11814         __mmplayer_cancel_eos_timer(player);
11815
11816         /* init new timeout */
11817         /* NOTE : consider give high priority to this timer */
11818         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11819
11820         player->eos_timer = g_timeout_add(delay_in_ms,
11821                 __mmplayer_eos_timer_cb, player);
11822
11823         player->context.global_default = g_main_context_default();
11824         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11825
11826         /* check timer is valid. if not, send EOS now */
11827         if (player->eos_timer == 0) {
11828                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11829                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11830         }
11831 }
11832
11833 static void
11834 __mmplayer_cancel_eos_timer(mm_player_t* player)
11835 {
11836         MMPLAYER_RETURN_IF_FAIL(player);
11837
11838         if (player->eos_timer) {
11839                 LOGD("cancel eos timer");
11840                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11841                 player->eos_timer = 0;
11842         }
11843
11844         return;
11845 }
11846
11847 static gboolean
11848 __mmplayer_eos_timer_cb(gpointer u_data)
11849 {
11850         mm_player_t* player = NULL;
11851         MMHandleType attrs = 0;
11852         int count = 0;
11853
11854         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11855
11856         player = (mm_player_t*) u_data;
11857         attrs = MMPLAYER_GET_ATTRS(player);
11858
11859         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11860
11861         if (count == -1) {
11862                 gint ret_value = 0;
11863                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11864                 if (ret_value != MM_ERROR_NONE)
11865                         LOGE("seeking to 0 failed in repeat play");
11866         } else {
11867                 /* posting eos */
11868                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11869         }
11870
11871         /* we are returning FALSE as we need only one posting */
11872         return FALSE;
11873 }
11874
11875 /* sending event to one of sinkelements */
11876 static gboolean
11877 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11878 {
11879         GstEvent * event2 = NULL;
11880         GList *sinks = NULL;
11881         gboolean res = FALSE;
11882         MMPLAYER_FENTER();
11883
11884         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11885         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11886
11887         /* While adding subtitles in live feeds seek is getting called.
11888            Adding defensive check in framework layer.*/
11889         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11890                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11891                         LOGE("Should not send seek event during live playback");
11892                         return TRUE;
11893                 }
11894         }
11895
11896         if (player->play_subtitle)
11897                 event2 = gst_event_copy((const GstEvent *)event);
11898
11899         sinks = player->sink_elements;
11900         while (sinks) {
11901                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11902
11903                 if (GST_IS_ELEMENT(sink)) {
11904                         /* keep ref to the event */
11905                         gst_event_ref(event);
11906
11907                         if ((res = gst_element_send_event(sink, event))) {
11908                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11909                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11910
11911                                 /* rtsp case, asyn_done is not called after seek during pause state */
11912                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11913                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11914                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11915                                                         LOGD("RTSP seek completed, after pause state..\n");
11916                                                         player->doing_seek = FALSE;
11917                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11918                                                 }
11919
11920                                         }
11921                                 }
11922
11923                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11924                                         sinks = g_list_next(sinks);
11925                                         continue;
11926                                 } else {
11927                                         break;
11928                                 }
11929                         }
11930
11931                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11932                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11933                 }
11934
11935                 sinks = g_list_next(sinks);
11936         }
11937
11938         /* Note : Textbin is not linked to the video or audio bin.
11939          * It needs to send the event to the text sink seperatelly.
11940          */
11941          if (player->play_subtitle && player->pipeline) {
11942                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11943
11944                 if (GST_IS_ELEMENT(text_sink)) {
11945                         /* keep ref to the event */
11946                         gst_event_ref(event2);
11947
11948                         if ((res = gst_element_send_event(text_sink, event2)))
11949                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11950                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11951                         else
11952                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11953                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11954
11955                         gst_event_unref(event2);
11956                 }
11957          }
11958
11959         gst_event_unref(event);
11960
11961         MMPLAYER_FLEAVE();
11962
11963         return res;
11964 }
11965
11966 static void
11967 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11968 {
11969         MMPLAYER_FENTER();
11970
11971         MMPLAYER_RETURN_IF_FAIL(player);
11972         MMPLAYER_RETURN_IF_FAIL(sink);
11973
11974         player->sink_elements =
11975                 g_list_append(player->sink_elements, sink);
11976
11977         MMPLAYER_FLEAVE();
11978 }
11979
11980 static void
11981 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11982 {
11983         MMPLAYER_FENTER();
11984
11985         MMPLAYER_RETURN_IF_FAIL(player);
11986         MMPLAYER_RETURN_IF_FAIL(sink);
11987
11988         player->sink_elements =
11989                         g_list_remove(player->sink_elements, sink);
11990
11991         MMPLAYER_FLEAVE();
11992 }
11993
11994 static gboolean
11995 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11996                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11997                         gint64 cur, GstSeekType stop_type, gint64 stop)
11998 {
11999         GstEvent* event = NULL;
12000         gboolean result = FALSE;
12001
12002         MMPLAYER_FENTER();
12003
12004         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12005
12006         if (player->pipeline && player->pipeline->textbin)
12007                 __mmplayer_drop_subtitle(player, FALSE);
12008
12009         event = gst_event_new_seek(rate, format, flags, cur_type,
12010                 cur, stop_type, stop);
12011
12012         result = __gst_send_event_to_sink(player, event);
12013
12014         MMPLAYER_FLEAVE();
12015
12016         return result;
12017 }
12018
12019 /* NOTE : be careful with calling this api. please refer to below glib comment
12020  * glib comment : Note that there is a bug in GObject that makes this function much
12021  * less useful than it might seem otherwise. Once gobject is disposed, the callback
12022  * will no longer be called, but, the signal handler is not currently disconnected.
12023  * If the instance is itself being freed at the same time than this doesn't matter,
12024  * since the signal will automatically be removed, but if instance persists,
12025  * then the signal handler will leak. You should not remove the signal yourself
12026  * because in a future versions of GObject, the handler will automatically be
12027  * disconnected.
12028  *
12029  * It's possible to work around this problem in a way that will continue to work
12030  * with future versions of GObject by checking that the signal handler is still
12031  * connected before disconnected it:
12032  *
12033  *  if (g_signal_handler_is_connected(instance, id))
12034  *    g_signal_handler_disconnect(instance, id);
12035  */
12036 static void
12037 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12038 {
12039         GList* sig_list = NULL;
12040         MMPlayerSignalItem* item = NULL;
12041
12042         MMPLAYER_FENTER();
12043
12044         MMPLAYER_RETURN_IF_FAIL(player);
12045
12046         LOGD("release signals type : %d", type);
12047
12048         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12049                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12050                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12051                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12052                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12053                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12054                 return;
12055         }
12056
12057         sig_list = player->signals[type];
12058
12059         for (; sig_list; sig_list = sig_list->next) {
12060                 item = sig_list->data;
12061
12062                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12063                         if (g_signal_handler_is_connected(item->obj, item->sig))
12064                                 g_signal_handler_disconnect(item->obj, item->sig);
12065                 }
12066
12067                 MMPLAYER_FREEIF(item);
12068         }
12069
12070         g_list_free(player->signals[type]);
12071         player->signals[type] = NULL;
12072
12073         MMPLAYER_FLEAVE();
12074
12075         return;
12076 }
12077
12078 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12079 {
12080         mm_player_t* player = 0;
12081         int prev_display_surface_type = 0;
12082         void *prev_display_overlay = NULL;
12083         const gchar *klass = NULL;
12084         gchar *cur_videosink_name = NULL;
12085         int ret = 0;
12086         int i = 0;
12087         int num_of_dec = 2; /* DEC1, DEC2 */
12088
12089         MMPLAYER_FENTER();
12090
12091         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12092         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12093
12094         player = MM_PLAYER_CAST(handle);
12095
12096         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12097                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12098                 MMPLAYER_FLEAVE();
12099                 return MM_ERROR_INVALID_ARGUMENT;
12100         }
12101
12102         /* load previous attributes */
12103         if (player->attrs) {
12104                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12105                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12106                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12107                 if (prev_display_surface_type == surface_type) {
12108                         LOGD("incoming display surface type is same as previous one, do nothing..");
12109                         MMPLAYER_FLEAVE();
12110                         return MM_ERROR_NONE;
12111                 }
12112         } else {
12113                 LOGE("failed to load attributes");
12114                 MMPLAYER_FLEAVE();
12115                 return MM_ERROR_PLAYER_INTERNAL;
12116         }
12117
12118         /* check videosink element is created */
12119         if (!player->pipeline || !player->pipeline->videobin ||
12120                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12121                 LOGD("videosink element is not yet ready");
12122
12123                 /* videobin is not created yet, so we just set attributes related to display surface */
12124                 LOGD("store display attribute for given surface type(%d)", surface_type);
12125                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12126                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12127                 if (mmf_attrs_commit(player->attrs)) {
12128                         LOGE("failed to commit attribute");
12129                         MMPLAYER_FLEAVE();
12130                         return MM_ERROR_PLAYER_INTERNAL;
12131                 }
12132                 MMPLAYER_FLEAVE();
12133                 return MM_ERROR_NONE;
12134         } else {
12135                 /* get player command status */
12136                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12137                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12138                         MMPLAYER_FLEAVE();
12139                         return MM_ERROR_PLAYER_INVALID_STATE;
12140                 }
12141
12142                 /* surface change */
12143                 for (i = 0 ; i < num_of_dec ; i++) {
12144                         if (player->pipeline->mainbin &&
12145                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12146                                 GstElementFactory *decfactory;
12147                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12148
12149                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12150                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12151                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12152                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12153                                                 if (ret) {
12154                                                         goto ERROR_CASE;
12155                                                 } else {
12156                                                         LOGW("success to changing display surface(%d)", surface_type);
12157                                                         MMPLAYER_FLEAVE();
12158                                                         return MM_ERROR_NONE;
12159                                                 }
12160                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12161                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12162                                                 if (ret) {
12163                                                         goto ERROR_CASE;
12164                                                 } else {
12165                                                         LOGW("success to changing display surface(%d)", surface_type);
12166                                                         MMPLAYER_FLEAVE();
12167                                                         return MM_ERROR_NONE;
12168                                                 }
12169                                         } else {
12170                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12171                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12172                                                 goto ERROR_CASE;
12173                                         }
12174                                 }
12175                         }
12176                 }
12177         }
12178
12179 ERROR_CASE:
12180         /* rollback to previous attributes */
12181         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12182         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12183         if (mmf_attrs_commit(player->attrs)) {
12184                 LOGE("failed to commit attributes to rollback");
12185                 MMPLAYER_FLEAVE();
12186                 return MM_ERROR_PLAYER_INTERNAL;
12187         }
12188         MMPLAYER_FLEAVE();
12189         return ret;
12190 }
12191
12192 /* NOTE : It does not support some use cases, eg using colorspace converter */
12193 int
12194 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12195 {
12196         GstPad *src_pad_dec = NULL;
12197         GstPad *sink_pad_videosink = NULL;
12198         GstPad *sink_pad_videobin = NULL;
12199         GstClock *clock = NULL;
12200         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12201         int ret = MM_ERROR_NONE;
12202         gboolean is_audiobin_created = TRUE;
12203
12204         MMPLAYER_FENTER();
12205
12206         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12207         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12208         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12209
12210         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12211         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12212
12213         /* get information whether if audiobin is created */
12214         if (!player->pipeline->audiobin ||
12215                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12216                 LOGW("audiobin is null, this video content may not have audio data");
12217                 is_audiobin_created = FALSE;
12218         }
12219
12220         /* get current state of player */
12221         previous_state = MMPLAYER_CURRENT_STATE(player);
12222         LOGD("previous state(%d)", previous_state);
12223
12224
12225         /* get src pad of decoder and block it */
12226         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12227         if (!src_pad_dec) {
12228                 LOGE("failed to get src pad from decode in mainbin");
12229                 return MM_ERROR_PLAYER_INTERNAL;
12230         }
12231
12232         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12233                 LOGW("trying to block pad(video)");
12234 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12235                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12236                         NULL, NULL, NULL);
12237                 {
12238                         LOGE("failed to set block pad(video)");
12239                         return MM_ERROR_PLAYER_INTERNAL;
12240                 }
12241                 LOGW("pad is blocked(video)");
12242         } else {
12243                 /* no data flows, so no need to do pad_block */
12244                 if (player->doing_seek)
12245                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12246
12247                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12248         }
12249
12250         /* remove pad */
12251         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12252                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12253                 LOGE("failed to remove previous ghost_pad for videobin");
12254                 return MM_ERROR_PLAYER_INTERNAL;
12255         }
12256
12257         /* change state of videobin to NULL */
12258         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12259         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12260         if (ret != GST_STATE_CHANGE_SUCCESS) {
12261                 LOGE("failed to change state of videobin to NULL");
12262                 return MM_ERROR_PLAYER_INTERNAL;
12263         }
12264
12265         /* unlink between decoder and videobin and remove previous videosink from videobin */
12266         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12267         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12268                 LOGE("failed to remove former videosink from videobin");
12269                 return MM_ERROR_PLAYER_INTERNAL;
12270         }
12271
12272         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12273
12274         /* create a new videosink and add it to videobin */
12275         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12276         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12277                 LOGE("failed to create videosink element\n");
12278                 MMPLAYER_FLEAVE();
12279                 return MM_ERROR_PLAYER_INTERNAL;
12280         }
12281         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12282         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12283         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12284
12285         /* save attributes */
12286         if (player->attrs) {
12287                 /* set a new display surface type */
12288                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12289                 /* set a new diplay overlay */
12290                 switch (surface_type) {
12291                 case MM_DISPLAY_SURFACE_OVERLAY:
12292                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12293                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12294                         break;
12295                 default:
12296                         LOGE("invalid type(%d) for changing display surface", surface_type);
12297                         MMPLAYER_FLEAVE();
12298                         return MM_ERROR_INVALID_ARGUMENT;
12299                 }
12300                 if (mmf_attrs_commit(player->attrs)) {
12301                         LOGE("failed to commit");
12302                         MMPLAYER_FLEAVE();
12303                         return MM_ERROR_PLAYER_INTERNAL;
12304                 }
12305         } else {
12306                 LOGE("player->attrs is null, failed to save attributes");
12307                 MMPLAYER_FLEAVE();
12308                 return MM_ERROR_PLAYER_INTERNAL;
12309         }
12310
12311         /* update video param */
12312         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12313                 LOGE("failed to update video param");
12314                 return MM_ERROR_PLAYER_INTERNAL;
12315         }
12316
12317         /* change state of videobin to READY */
12318         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12319         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12320         if (ret != GST_STATE_CHANGE_SUCCESS) {
12321                 LOGE("failed to change state of videobin to READY");
12322                 return MM_ERROR_PLAYER_INTERNAL;
12323         }
12324
12325         /* change ghostpad */
12326         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12327         if (!sink_pad_videosink) {
12328                 LOGE("failed to get sink pad from videosink element");
12329                 return MM_ERROR_PLAYER_INTERNAL;
12330         }
12331         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12332         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12333                 LOGE("failed to set active to ghost_pad");
12334                 return MM_ERROR_PLAYER_INTERNAL;
12335         }
12336         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12337                 LOGE("failed to change ghostpad for videobin");
12338                 return MM_ERROR_PLAYER_INTERNAL;
12339         }
12340         gst_object_unref(sink_pad_videosink);
12341
12342         /* link decoder with videobin */
12343         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12344         if (!sink_pad_videobin) {
12345                 LOGE("failed to get sink pad from videobin");
12346                 return MM_ERROR_PLAYER_INTERNAL;
12347         }
12348         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12349                 LOGE("failed to link");
12350                 return MM_ERROR_PLAYER_INTERNAL;
12351         }
12352         gst_object_unref(sink_pad_videobin);
12353
12354         /* clock setting for a new videosink plugin */
12355         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12356                         so we set it from audiosink plugin or pipeline(system clock) */
12357         if (!is_audiobin_created) {
12358                 LOGW("audiobin is not created, get clock from pipeline..");
12359                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12360         } else {
12361                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12362         }
12363         if (clock) {
12364                 GstClockTime now;
12365                 GstClockTime base_time;
12366                 LOGD("set the clock to videosink");
12367                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12368                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12369                 if (clock) {
12370                         LOGD("got clock of videosink");
12371                         now = gst_clock_get_time(clock);
12372                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12373                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12374                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12375                 } else {
12376                         LOGE("failed to get clock of videosink after setting clock");
12377                         return MM_ERROR_PLAYER_INTERNAL;
12378                 }
12379         } else
12380                 LOGW("failed to get clock, maybe it is the time before first playing");
12381
12382         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12383                 /* change state of videobin to PAUSED */
12384                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12385                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12386                 if (ret != GST_STATE_CHANGE_FAILURE) {
12387                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12388                 } else {
12389                         LOGE("failed to change state of videobin to PLAYING");
12390                         return MM_ERROR_PLAYER_INTERNAL;
12391                 }
12392
12393                 /* release blocked and unref src pad of video decoder */
12394                 #if 0
12395                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12396                         LOGE("failed to set pad blocked FALSE(video)");
12397                         return MM_ERROR_PLAYER_INTERNAL;
12398                 }
12399                 #endif
12400                 LOGW("pad is unblocked(video)");
12401         } else {
12402                 if (player->doing_seek)
12403                         LOGW("not completed seek(%d)", player->doing_seek);
12404                 /* change state of videobin to PAUSED */
12405                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12406                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12407                 if (ret != GST_STATE_CHANGE_FAILURE) {
12408                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12409                 } else {
12410                         LOGE("failed to change state of videobin to PLAYING");
12411                         return MM_ERROR_PLAYER_INTERNAL;
12412                 }
12413
12414                 /* already skipped pad block */
12415                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12416         }
12417
12418         /* do get/set position for new videosink plugin */
12419         {
12420                 unsigned long position = 0;
12421                 gint64 pos_msec = 0;
12422
12423                 LOGD("do get/set position for new videosink plugin");
12424                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12425                         LOGE("failed to get position");
12426                         return MM_ERROR_PLAYER_INTERNAL;
12427                 }
12428 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12429                 /* accurate seek */
12430                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12431                         LOGE("failed to set position");
12432                         return MM_ERROR_PLAYER_INTERNAL;
12433                 }
12434 #else
12435                 /* key unit seek */
12436                 pos_msec = position * G_GINT64_CONSTANT(1000000);
12437                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12438                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12439                                                         GST_SEEK_TYPE_SET, pos_msec,
12440                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12441                 if (!ret) {
12442                         LOGE("failed to set position");
12443                         return MM_ERROR_PLAYER_INTERNAL;
12444                 }
12445 #endif
12446         }
12447
12448         if (src_pad_dec)
12449                 gst_object_unref(src_pad_dec);
12450         LOGD("success to change sink");
12451
12452         MMPLAYER_FLEAVE();
12453
12454         return MM_ERROR_NONE;
12455 }
12456
12457
12458 /* Note : if silent is true, then subtitle would not be displayed. :*/
12459 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12460 {
12461         mm_player_t* player = (mm_player_t*) hplayer;
12462
12463         MMPLAYER_FENTER();
12464
12465         /* check player handle */
12466         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12467
12468         player->set_mode.subtitle_off = silent;
12469
12470         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12471
12472         MMPLAYER_FLEAVE();
12473
12474         return MM_ERROR_NONE;
12475 }
12476
12477 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12478 {
12479         MMPlayerGstElement* mainbin = NULL;
12480         MMPlayerGstElement* textbin = NULL;
12481         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12482         GstState current_state = GST_STATE_VOID_PENDING;
12483         GstState element_state = GST_STATE_VOID_PENDING;
12484         GstState element_pending_state = GST_STATE_VOID_PENDING;
12485         gint64 time = 0;
12486         GstEvent *event = NULL;
12487         int result = MM_ERROR_NONE;
12488
12489         GstClock *curr_clock = NULL;
12490         GstClockTime base_time, start_time, curr_time;
12491
12492
12493         MMPLAYER_FENTER();
12494
12495         /* check player handle */
12496         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12497                                                                 player->pipeline &&
12498                                                                 player->pipeline->mainbin &&
12499                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12500
12501         mainbin = player->pipeline->mainbin;
12502         textbin = player->pipeline->textbin;
12503
12504         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12505
12506         // sync clock with current pipeline
12507         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12508         curr_time = gst_clock_get_time(curr_clock);
12509
12510         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12511         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12512
12513         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12514                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12515
12516         if (current_state > GST_STATE_READY) {
12517                 // sync state with current pipeline
12518                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12519                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12520                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12521
12522                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12523                 if (GST_STATE_CHANGE_FAILURE == ret) {
12524                         LOGE("fail to state change.\n");
12525                         result = MM_ERROR_PLAYER_INTERNAL;
12526                         goto ERROR;
12527                 }
12528         }
12529
12530         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12531         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12532
12533         if (curr_clock) {
12534                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12535                 gst_object_unref(curr_clock);
12536         }
12537
12538         // seek to current position
12539         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12540                 result = MM_ERROR_PLAYER_INVALID_STATE;
12541                 LOGE("gst_element_query_position failed, invalid state\n");
12542                 goto ERROR;
12543         }
12544
12545         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12546         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);
12547         if (event) {
12548                 __gst_send_event_to_sink(player, event);
12549         } else {
12550                 result = MM_ERROR_PLAYER_INTERNAL;
12551                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12552                 goto ERROR;
12553         }
12554
12555         /* sync state with current pipeline */
12556         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12557         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12558         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12559
12560         return MM_ERROR_NONE;
12561
12562 ERROR:
12563         /* release text pipeline resource */
12564         player->textsink_linked = 0;
12565
12566         /* release signal */
12567         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12568
12569         /* release textbin with it's childs */
12570         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12571         MMPLAYER_FREEIF(player->pipeline->textbin);
12572         player->pipeline->textbin = NULL;
12573
12574         /* release subtitle elem */
12575         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12576         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12577
12578         return result;
12579 }
12580
12581 static int
12582 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12583 {
12584         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12585         GstState current_state = GST_STATE_VOID_PENDING;
12586
12587         MMHandleType attrs = 0;
12588         MMPlayerGstElement* mainbin = NULL;
12589         MMPlayerGstElement* textbin = NULL;
12590
12591         gchar* subtitle_uri = NULL;
12592         int result = MM_ERROR_NONE;
12593         const gchar *charset = NULL;
12594
12595         MMPLAYER_FENTER();
12596
12597         /* check player handle */
12598         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12599                                                                 player->pipeline &&
12600                                                                 player->pipeline->mainbin &&
12601                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12602         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12603
12604         mainbin = player->pipeline->mainbin;
12605         textbin = player->pipeline->textbin;
12606
12607         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12608         if (current_state < GST_STATE_READY) {
12609                 result = MM_ERROR_PLAYER_INVALID_STATE;
12610                 LOGE("Pipeline is not in proper state\n");
12611                 goto EXIT;
12612         }
12613
12614         attrs = MMPLAYER_GET_ATTRS(player);
12615         if (!attrs) {
12616                 LOGE("cannot get content attribute\n");
12617                 result = MM_ERROR_PLAYER_INTERNAL;
12618                 goto EXIT;
12619         }
12620
12621         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12622         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12623                 LOGE("subtitle uri is not proper filepath\n");
12624                 result = MM_ERROR_PLAYER_INVALID_URI;
12625                 goto EXIT;
12626         }
12627
12628         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12629                 LOGE("failed to get storage info of subtitle path");
12630                 result = MM_ERROR_PLAYER_INVALID_URI;
12631                 goto EXIT;
12632         }
12633
12634         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12635         LOGD("new subtitle file path is [%s]\n", filepath);
12636
12637         if (!strcmp(filepath, subtitle_uri)) {
12638                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12639                 goto EXIT;
12640         } else {
12641                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12642                 if (mmf_attrs_commit(player->attrs)) {
12643                         LOGE("failed to commit.\n");
12644                         goto EXIT;
12645                 }
12646         }
12647
12648         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12649         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12650         player->subtitle_language_list = NULL;
12651         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12652
12653         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12654         if (ret != GST_STATE_CHANGE_SUCCESS) {
12655                 LOGE("failed to change state of textbin to READY");
12656                 result = MM_ERROR_PLAYER_INTERNAL;
12657                 goto EXIT;
12658         }
12659
12660         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12661         if (ret != GST_STATE_CHANGE_SUCCESS) {
12662                 LOGE("failed to change state of subparse to READY");
12663                 result = MM_ERROR_PLAYER_INTERNAL;
12664                 goto EXIT;
12665         }
12666
12667         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12668         if (ret != GST_STATE_CHANGE_SUCCESS) {
12669                 LOGE("failed to change state of filesrc to READY");
12670                 result = MM_ERROR_PLAYER_INTERNAL;
12671                 goto EXIT;
12672         }
12673
12674         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12675
12676         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12677
12678         charset = util_get_charset(filepath);
12679         if (charset) {
12680                 LOGD("detected charset is %s\n", charset);
12681                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12682         }
12683
12684         result = _mmplayer_sync_subtitle_pipeline(player);
12685
12686 EXIT:
12687         MMPLAYER_FLEAVE();
12688         return result;
12689 }
12690
12691 /* API to switch between external subtitles */
12692 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12693 {
12694         int result = MM_ERROR_NONE;
12695         mm_player_t* player = (mm_player_t*)hplayer;
12696         char *path = NULL;
12697
12698         MMPLAYER_FENTER();
12699
12700         /* check player handle */
12701         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12702
12703         /* filepath can be null in idle state */
12704         if (filepath) {
12705                 /* check file path */
12706                 if ((path = strstr(filepath, "file://")))
12707                         result = util_exist_file_path(path + 7);
12708                 else
12709                         result = util_exist_file_path(filepath);
12710
12711                 if (result != MM_ERROR_NONE) {
12712                         LOGE("invalid subtitle path 0x%X", result);
12713                         return result; /* file not found or permission denied */
12714                 }
12715         }
12716
12717         if (!player->pipeline) {
12718                 /* IDLE state */
12719                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12720                 if (mmf_attrs_commit(player->attrs)) {
12721                         LOGE("failed to commit");       /* subtitle path will not be created */
12722                         return MM_ERROR_PLAYER_INTERNAL;
12723                 }
12724         } else {
12725                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12726                 /* check filepath */
12727                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12728
12729                 if (!__mmplayer_check_subtitle(player)) {
12730                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12731                         if (mmf_attrs_commit(player->attrs)) {
12732                                 LOGE("failed to commit");
12733                                 return MM_ERROR_PLAYER_INTERNAL;
12734                         }
12735
12736                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12737                                 LOGE("fail to create text pipeline");
12738                                 return MM_ERROR_PLAYER_INTERNAL;
12739                         }
12740
12741                         result = _mmplayer_sync_subtitle_pipeline(player);
12742                 } else {
12743                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12744                 }
12745
12746                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12747                 player->is_external_subtitle_added_now = TRUE;
12748
12749                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12750                 if (!player->subtitle_language_list) {
12751                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12752                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12753                                 LOGW("subtitle language list is not updated yet");
12754                 }
12755                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12756         }
12757
12758         MMPLAYER_FLEAVE();
12759         return result;
12760 }
12761
12762 static int
12763 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12764 {
12765         int result = MM_ERROR_NONE;
12766         gchar* change_pad_name = NULL;
12767         GstPad* sinkpad = NULL;
12768         MMPlayerGstElement* mainbin = NULL;
12769         enum MainElementID elemId = MMPLAYER_M_NUM;
12770         GstCaps* caps = NULL;
12771         gint total_track_num = 0;
12772
12773         MMPLAYER_FENTER();
12774
12775         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12776                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12777
12778         LOGD("Change Track(%d) to %d\n", type, index);
12779
12780         mainbin = player->pipeline->mainbin;
12781
12782         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12783                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12784         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12785                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12786         } else {
12787                 /* Changing Video Track is not supported. */
12788                 LOGE("Track Type Error\n");
12789                 goto EXIT;
12790         }
12791
12792         if (mainbin[elemId].gst == NULL) {
12793                 result = MM_ERROR_PLAYER_NO_OP;
12794                 LOGD("Req track doesn't exist\n");
12795                 goto EXIT;
12796         }
12797
12798         total_track_num = player->selector[type].total_track_num;
12799         if (total_track_num <= 0) {
12800                 result = MM_ERROR_PLAYER_NO_OP;
12801                 LOGD("Language list is not available \n");
12802                 goto EXIT;
12803         }
12804
12805         if ((index < 0) || (index >= total_track_num)) {
12806                 result = MM_ERROR_INVALID_ARGUMENT;
12807                 LOGD("Not a proper index : %d \n", index);
12808                 goto EXIT;
12809         }
12810
12811         /*To get the new pad from the selector*/
12812         change_pad_name = g_strdup_printf("sink_%u", index);
12813         if (change_pad_name == NULL) {
12814                 result = MM_ERROR_PLAYER_INTERNAL;
12815                 LOGD("Pad does not exists\n");
12816                 goto EXIT;
12817         }
12818
12819         LOGD("new active pad name: %s\n", change_pad_name);
12820
12821         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12822         if (sinkpad == NULL) {
12823                 LOGD("sinkpad is NULL");
12824                 result = MM_ERROR_PLAYER_INTERNAL;
12825                 goto EXIT;
12826         }
12827
12828         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12829         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12830
12831         caps = gst_pad_get_current_caps(sinkpad);
12832         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12833
12834         if (sinkpad)
12835                 gst_object_unref(sinkpad);
12836
12837         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12838                 __mmplayer_set_audio_attrs(player, caps);
12839
12840 EXIT:
12841
12842         MMPLAYER_FREEIF(change_pad_name);
12843         return result;
12844 }
12845
12846 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12847 {
12848         int result = MM_ERROR_NONE;
12849         mm_player_t* player = NULL;
12850         MMPlayerGstElement* mainbin = NULL;
12851
12852         gint current_active_index = 0;
12853
12854         GstState current_state = GST_STATE_VOID_PENDING;
12855         GstEvent* event = NULL;
12856         gint64 time = 0;
12857
12858         MMPLAYER_FENTER();
12859
12860         player = (mm_player_t*)hplayer;
12861         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12862
12863         if (!player->pipeline) {
12864                 LOGE("Track %d pre setting -> %d\n", type, index);
12865
12866                 player->selector[type].active_pad_index = index;
12867                 goto EXIT;
12868         }
12869
12870         mainbin = player->pipeline->mainbin;
12871
12872         current_active_index = player->selector[type].active_pad_index;
12873
12874         /*If index is same as running index no need to change the pad*/
12875         if (current_active_index == index)
12876                 goto EXIT;
12877
12878         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12879                 result = MM_ERROR_PLAYER_INVALID_STATE;
12880                 goto EXIT;
12881         }
12882
12883         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12884         if (current_state < GST_STATE_PAUSED) {
12885                 result = MM_ERROR_PLAYER_INVALID_STATE;
12886                 LOGW("Pipeline not in porper state\n");
12887                 goto EXIT;
12888         }
12889
12890         result = __mmplayer_change_selector_pad(player, type, index);
12891         if (result != MM_ERROR_NONE) {
12892                 LOGE("change selector pad error\n");
12893                 goto EXIT;
12894         }
12895
12896         player->selector[type].active_pad_index = index;
12897
12898         if (current_state == GST_STATE_PLAYING) {
12899                 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);
12900                 if (event) {
12901                         __gst_send_event_to_sink(player, event);
12902                 } else {
12903                         result = MM_ERROR_PLAYER_INTERNAL;
12904                         goto EXIT;
12905                 }
12906         }
12907
12908 EXIT:
12909         return result;
12910 }
12911
12912 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12913 {
12914         mm_player_t* player = (mm_player_t*) hplayer;
12915
12916         MMPLAYER_FENTER();
12917
12918         /* check player handle */
12919         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12920
12921         *silent = player->set_mode.subtitle_off;
12922
12923         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12924
12925         MMPLAYER_FLEAVE();
12926
12927         return MM_ERROR_NONE;
12928 }
12929
12930 gboolean
12931 __is_ms_buff_src(mm_player_t* player)
12932 {
12933         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12934
12935         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12936 }
12937
12938 gboolean
12939 __has_suffix(mm_player_t* player, const gchar* suffix)
12940 {
12941         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12942         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12943
12944         gboolean ret = FALSE;
12945         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12946         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12947
12948         if (g_str_has_suffix(player->profile.uri, suffix))
12949                 ret = TRUE;
12950
12951         MMPLAYER_FREEIF(t_url);
12952         MMPLAYER_FREEIF(t_suffix);
12953
12954         return ret;
12955 }
12956
12957 int
12958 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12959 {
12960         mm_player_t* player = (mm_player_t*) hplayer;
12961
12962         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12963
12964         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12965                 MMPLAYER_PRINT_STATE(player);
12966                 LOGE("wrong-state : can't set the download mode to parse");
12967                 return MM_ERROR_PLAYER_INVALID_STATE;
12968         }
12969
12970         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12971         player->video_hub_download_mode = mode;
12972
12973         return MM_ERROR_NONE;
12974 }
12975
12976 int
12977 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12978 {
12979         mm_player_t* player = (mm_player_t*) hplayer;
12980
12981         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12982
12983         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12984         player->sync_handler = enable;
12985
12986         return MM_ERROR_NONE;
12987 }
12988
12989 int
12990 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12991                                         long long clock,
12992                                         long long clock_delta,
12993                                         long long video_time,
12994                                         long long media_clock,
12995                                         long long audio_time)
12996 {
12997         mm_player_t* player = (mm_player_t*) hplayer;
12998         MMPlayerGstElement* mainbin = NULL;
12999         GstClockTime start_time_audio = 0, start_time_video = 0;
13000         GstClockTimeDiff base_time = 0, new_base_time = 0;
13001         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13002         gint64 api_delta = 0;
13003         gint64 position = 0, position_delta = 0;
13004         gint64 adj_base_time = 0;
13005         GstClock *curr_clock = NULL;
13006         GstClockTime curr_time = 0;
13007         gboolean query_ret = TRUE;
13008         int result = MM_ERROR_NONE;
13009
13010         MMPLAYER_FENTER();
13011
13012         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13013         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13014         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13015
13016         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13017
13018         if ((video_time < 0) || (player->doing_seek)) {
13019                 LOGD("skip setting master clock.  %lld", video_time);
13020                 goto EXIT;
13021         }
13022
13023         mainbin = player->pipeline->mainbin;
13024
13025         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13026         curr_time = gst_clock_get_time(curr_clock);
13027
13028         current_state = MMPLAYER_CURRENT_STATE(player);
13029
13030         if (current_state == MM_PLAYER_STATE_PLAYING)
13031                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13032
13033         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13034                 (!query_ret)) {
13035                 position = player->last_position;
13036                 LOGD("query fail. %lld", position);
13037         }
13038
13039         clock *= GST_USECOND;
13040         clock_delta *= GST_USECOND;
13041
13042         api_delta = clock - curr_time;
13043         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13044                 player->video_share_api_delta = api_delta;
13045         else
13046                 clock_delta += (api_delta - player->video_share_api_delta);
13047
13048         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13049                 player->video_share_clock_delta = (gint64)clock_delta;
13050
13051                 position_delta = (position/GST_USECOND) - video_time;
13052                 position_delta *= GST_USECOND;
13053
13054                 adj_base_time = position_delta;
13055                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13056
13057         } else {
13058                 gint64 new_play_time = 0;
13059                 gint64 network_delay = 0;
13060
13061                 video_time *= GST_USECOND;
13062
13063                 network_delay = clock_delta - player->video_share_clock_delta;
13064                 new_play_time = video_time + network_delay;
13065
13066                 adj_base_time = position - new_play_time;
13067
13068                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13069                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13070         }
13071
13072         /* Adjust Current Stream Time with base_time of sink
13073          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13074          * 2. Set new base time
13075          *    if adj_base_time is positive value, the stream time will be decreased.
13076          * 3. If seek event is occurred, the start time will be reset. */
13077         if ((player->pipeline->audiobin) &&
13078                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13079                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13080
13081                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13082                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13083                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13084                 }
13085
13086                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13087         }
13088
13089         if ((player->pipeline->videobin) &&
13090                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13091                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13092
13093                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13094                         LOGD("video sink : gst_element_set_start_time -> NONE");
13095                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13096                 }
13097
13098                 // if videobin exist, get base_time from videobin.
13099                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13100         }
13101
13102         new_base_time = base_time + adj_base_time;
13103
13104         if ((player->pipeline->audiobin) &&
13105                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13106                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13107
13108         if ((player->pipeline->videobin) &&
13109                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13110                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13111
13112 EXIT:
13113         MMPLAYER_FLEAVE();
13114
13115         return result;
13116 }
13117
13118 int
13119 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13120                                         long long *video_time,
13121                                         long long *media_clock,
13122                                         long long *audio_time)
13123 {
13124         mm_player_t* player = (mm_player_t*) hplayer;
13125         MMPlayerGstElement* mainbin = NULL;
13126         GstClock *curr_clock = NULL;
13127         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13128         gint64 position = 0;
13129         gboolean query_ret = TRUE;
13130
13131         MMPLAYER_FENTER();
13132
13133         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13134         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13135         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13136
13137         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13138         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13139         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13140
13141         mainbin = player->pipeline->mainbin;
13142
13143         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13144
13145         current_state = MMPLAYER_CURRENT_STATE(player);
13146
13147         if (current_state != MM_PLAYER_STATE_PAUSED)
13148                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13149
13150         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13151                 (!query_ret))
13152                 position = player->last_position;
13153
13154         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13155
13156         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13157
13158         if (curr_clock)
13159                 gst_object_unref(curr_clock);
13160
13161         MMPLAYER_FLEAVE();
13162
13163         return MM_ERROR_NONE;
13164 }
13165
13166 static gboolean
13167 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13168 {
13169         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13170         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13171
13172         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13173         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13174
13175         int idx = 0;
13176
13177         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13178                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13179                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13180                         mm_player_dump_t *dump_s;
13181                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13182
13183                         if (dump_s == NULL) {
13184                                 LOGE("malloc fail");
13185                                 return FALSE;
13186                         }
13187
13188                         dump_s->dump_element_file = NULL;
13189                         dump_s->dump_pad = NULL;
13190                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13191
13192                         if (dump_s->dump_pad) {
13193                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13194                                 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]);
13195                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13196                                 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);
13197                                 /* add list for removed buffer probe and close FILE */
13198                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13199                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13200                                 return TRUE;
13201                         } else {
13202                                 g_free(dump_s);
13203                                 dump_s = NULL;
13204                                 LOGE("failed to get %s sink pad added", factory_name);
13205                         }
13206
13207
13208                 }
13209         }
13210         return FALSE;
13211 }
13212
13213 static GstPadProbeReturn
13214 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13215 {
13216         FILE *dump_data = (FILE *) u_data;
13217 //      int written = 0;
13218         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13219         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13220
13221         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13222
13223         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13224
13225 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13226
13227         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13228
13229         return GST_PAD_PROBE_OK;
13230 }
13231
13232 static void
13233 __mmplayer_release_dump_list(GList *dump_list)
13234 {
13235         if (dump_list) {
13236                 GList *d_list = dump_list;
13237                 for (; d_list; d_list = g_list_next(d_list)) {
13238                         mm_player_dump_t *dump_s = d_list->data;
13239                         if (dump_s->dump_pad) {
13240                                 if (dump_s->probe_handle_id)
13241                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13242                         }
13243                         if (dump_s->dump_element_file) {
13244                                 fclose(dump_s->dump_element_file);
13245                                 dump_s->dump_element_file = NULL;
13246                         }
13247                         MMPLAYER_FREEIF(dump_s);
13248                 }
13249                 g_list_free(dump_list);
13250                 dump_list = NULL;
13251         }
13252 }
13253
13254 int
13255 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13256 {
13257         mm_player_t* player = (mm_player_t*) hplayer;
13258
13259         MMPLAYER_FENTER();
13260
13261         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13262         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13263
13264         *exist = player->has_closed_caption;
13265
13266         MMPLAYER_FLEAVE();
13267
13268         return MM_ERROR_NONE;
13269 }
13270
13271 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13272 {
13273         MMPLAYER_FENTER();
13274         if (buffer) {
13275                 // LOGD("unref internal gst buffer %p", buffer);
13276                 gst_buffer_unref((GstBuffer *)buffer);
13277                 buffer = NULL;
13278         }
13279         MMPLAYER_FLEAVE();
13280 }
13281
13282 void
13283 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13284 {
13285         mm_player_t *player  = (mm_player_t*)user_data;
13286         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13287         guint64 current_level_bytes = 0;
13288
13289         MMPLAYER_RETURN_IF_FAIL(player);
13290
13291         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13292
13293         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
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_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13298         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13299
13300 }
13301
13302 void
13303 __gst_appsrc_feed_video_data(GstElement *element, guint size, 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         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13312
13313         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
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_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13318         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13319 }
13320
13321 void
13322 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13323 {
13324         mm_player_t *player  = (mm_player_t*)user_data;
13325         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13326         guint64 current_level_bytes = 0;
13327
13328         MMPLAYER_RETURN_IF_FAIL(player);
13329
13330         LOGI("app-src: feed subtitle\n");
13331
13332         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13333
13334         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13335         if (player->media_stream_buffer_status_cb[type])
13336                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13337
13338         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13339 }
13340
13341 void
13342 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13343 {
13344         mm_player_t *player  = (mm_player_t*)user_data;
13345         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13346         guint64 current_level_bytes = 0;
13347
13348         MMPLAYER_RETURN_IF_FAIL(player);
13349
13350         LOGI("app-src: audio buffer is full.\n");
13351
13352         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13353
13354         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13355
13356         if (player->media_stream_buffer_status_cb[type])
13357                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13358
13359         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13360 }
13361
13362 void
13363 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13364 {
13365         mm_player_t *player  = (mm_player_t*)user_data;
13366         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13367         guint64 current_level_bytes = 0;
13368
13369         MMPLAYER_RETURN_IF_FAIL(player);
13370
13371         LOGI("app-src: video buffer is full.\n");
13372
13373         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13374
13375         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13376         if (player->media_stream_buffer_status_cb[type])
13377                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13378
13379         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13380 }
13381
13382 gboolean
13383 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13384 {
13385         mm_player_t *player  = (mm_player_t*)user_data;
13386         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13387
13388         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13389
13390         LOGD("app-src: seek audio data %llu\n", position);
13391         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13392
13393         if (player->media_stream_seek_data_cb[type])
13394                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13395         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13396
13397         return TRUE;
13398 }
13399
13400 gboolean
13401 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13402 {
13403         mm_player_t *player  = (mm_player_t*)user_data;
13404         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13405
13406         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13407
13408         LOGD("app-src: seek video data %llu\n", position);
13409         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13410         if (player->media_stream_seek_data_cb[type])
13411                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13412         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13413
13414         return TRUE;
13415 }
13416
13417 gboolean
13418 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13419 {
13420         mm_player_t *player  = (mm_player_t*)user_data;
13421         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13422
13423         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13424
13425         LOGD("app-src: seek subtitle data\n");
13426         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13427
13428         if (player->media_stream_seek_data_cb[type])
13429                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13430         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13431
13432         return TRUE;
13433 }
13434
13435 int
13436 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13437 {
13438         mm_player_t* player = (mm_player_t*) hplayer;
13439
13440         MMPLAYER_FENTER();
13441
13442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13443
13444         player->pcm_samplerate = samplerate;
13445         player->pcm_channel = channel;
13446
13447         MMPLAYER_FLEAVE();
13448         return MM_ERROR_NONE;
13449 }
13450
13451 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13452 {
13453         mm_player_t* player = (mm_player_t*) hplayer;
13454
13455         MMPLAYER_FENTER();
13456
13457         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13458         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13459
13460         if (MMPLAYER_IS_STREAMING(player))
13461                 *timeout = player->ini.live_state_change_timeout;
13462         else
13463                 *timeout = player->ini.localplayback_state_change_timeout;
13464
13465         LOGD("timeout = %d\n", *timeout);
13466
13467         MMPLAYER_FLEAVE();
13468         return MM_ERROR_NONE;
13469 }
13470
13471 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13472 {
13473         mm_player_t* player = (mm_player_t*) hplayer;
13474
13475         MMPLAYER_FENTER();
13476
13477         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13478         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13479
13480         *num = player->video_num_buffers;
13481         *extra_num = player->video_extra_num_buffers;
13482
13483         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13484
13485         MMPLAYER_FLEAVE();
13486         return MM_ERROR_NONE;
13487 }
13488
13489 static void
13490 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13491 {
13492         int i = 0;
13493         MMPLAYER_FENTER();
13494         MMPLAYER_RETURN_IF_FAIL(player);
13495
13496         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13497
13498                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13499                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13500                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13501                         player->storage_info[i].id = -1;
13502                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13503
13504                         if (path_type != MMPLAYER_PATH_MAX)
13505                                 break;
13506                 }
13507         }
13508
13509         MMPLAYER_FLEAVE();
13510 }
13511
13512 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13513 {
13514         int ret = MM_ERROR_NONE;
13515         mm_player_t* player = (mm_player_t*)hplayer;
13516         MMMessageParamType msg_param = {0, };
13517
13518         MMPLAYER_FENTER();
13519         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13520
13521         LOGW("state changed storage %d:%d", id, state);
13522
13523         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13524                 return MM_ERROR_NONE;
13525
13526         /* FIXME: text path should be handled seperately. */
13527         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13528                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13529                 LOGW("external storage is removed");
13530
13531                 if (player->msg_posted == FALSE) {
13532                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13533                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13534                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13535                         player->msg_posted = TRUE;
13536                 }
13537
13538                 /* unrealize the player */
13539                 ret = _mmplayer_unrealize(hplayer);
13540                 if (ret != MM_ERROR_NONE)
13541                         LOGE("failed to unrealize");
13542         }
13543
13544         MMPLAYER_FLEAVE();
13545         return ret;
13546 }
13547
13548 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13549 {
13550         int ret = MM_ERROR_NONE;
13551         mm_player_t* player = (mm_player_t*) hplayer;
13552         int idx = 0, total = 0;
13553         gchar *result = NULL, *tmp = NULL;
13554
13555         MMPLAYER_FENTER();
13556         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13557         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13558
13559         total = *num = g_list_length(player->adaptive_info.var_list);
13560         if (total <= 0) {
13561                 LOGW("There is no stream variant info.");
13562                 return ret;
13563         }
13564
13565         result = g_strdup("");
13566         for (idx = 0 ; idx < total ; idx++) {
13567                 VariantData *v_data = NULL;
13568                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13569
13570                 if (v_data) {
13571                         gchar data[64] = {0};
13572                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13573
13574                         tmp = g_strconcat(result, data, NULL);
13575                         g_free(result);
13576                         result = tmp;
13577                 } else {
13578                         LOGW("There is no variant data in %d", idx);
13579                         (*num)--;
13580                 }
13581         }
13582
13583         *var_info = (char *)result;
13584
13585         LOGD("variant info %d:%s", *num, *var_info);
13586         MMPLAYER_FLEAVE();
13587         return ret;
13588 }
13589
13590 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13591 {
13592         int ret = MM_ERROR_NONE;
13593         mm_player_t* player = (mm_player_t*) hplayer;
13594
13595         MMPLAYER_FENTER();
13596         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13597
13598         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13599
13600         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13601         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13602         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13603
13604         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13605                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13606                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13607                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13608
13609                 /* FIXME: seek to current position for applying new variant limitation */
13610         }
13611
13612         MMPLAYER_FLEAVE();
13613         return ret;
13614
13615 }
13616
13617 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13618 {
13619         int ret = MM_ERROR_NONE;
13620         mm_player_t* player = (mm_player_t*) hplayer;
13621
13622         MMPLAYER_FENTER();
13623         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13624         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13625
13626         *bandwidth = player->adaptive_info.limit.bandwidth;
13627         *width = player->adaptive_info.limit.width;
13628         *height = player->adaptive_info.limit.height;
13629
13630         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13631
13632         MMPLAYER_FLEAVE();
13633         return ret;
13634 }
13635
13636 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13637 {
13638         int ret = MM_ERROR_NONE;
13639         mm_player_t* player = (mm_player_t*) hplayer;
13640
13641         MMPLAYER_FENTER();
13642         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13643
13644         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13645                 LOGW("buffer_ms will not be applied.");
13646
13647
13648         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13649
13650         if (player->streamer == NULL) {
13651                 player->streamer = __mm_player_streaming_create();
13652                 __mm_player_streaming_initialize(player->streamer);
13653         }
13654
13655         if (buffer_ms >= 0)
13656                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13657
13658         if (rebuffer_ms >= 0)
13659                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13660
13661         MMPLAYER_FLEAVE();
13662         return ret;
13663
13664 }
13665
13666 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13667 {
13668         int ret = MM_ERROR_NONE;
13669         mm_player_t* player = (mm_player_t*) hplayer;
13670
13671         MMPLAYER_FENTER();
13672         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13673         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13674
13675         if (player->streamer == NULL) {
13676                 player->streamer = __mm_player_streaming_create();
13677                 __mm_player_streaming_initialize(player->streamer);
13678         }
13679
13680         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13681         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13682
13683         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13684
13685         MMPLAYER_FLEAVE();
13686         return ret;
13687 }
13688
13689 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13690 {
13691 #define IDX_FIRST_SW_CODEC 0
13692         mm_player_t* player = (mm_player_t*) hplayer;
13693         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13694         MMHandleType attrs = 0;
13695
13696         MMPLAYER_FENTER();
13697         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13698
13699         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13700                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13701                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13702
13703         switch (stream_type) {
13704         case MM_PLAYER_STREAM_TYPE_AUDIO:
13705                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13706                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13707                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13708                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13709                         LOGE("There is no a codec for codec_type %d", codec_type);
13710                         return MM_ERROR_PLAYER_NO_OP;
13711                 }
13712         break;
13713         case MM_PLAYER_STREAM_TYPE_VIDEO:
13714                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13715                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13716                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13717                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13718                         LOGE("There is no v codec for codec_type %d", codec_type);
13719                         return MM_ERROR_PLAYER_NO_OP;
13720                 }
13721
13722         break;
13723         default:
13724                 LOGE("Invalid stream type %d", stream_type);
13725                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13726         break;
13727         }
13728
13729         LOGD("update %s codec_type to %d", attr_name, codec_type);
13730
13731         attrs = MMPLAYER_GET_ATTRS(player);
13732         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13733
13734         if (mmf_attrs_commit(player->attrs)) {
13735                 LOGE("failed to commit codec_type attributes");
13736                 return MM_ERROR_PLAYER_INTERNAL;
13737         }
13738
13739         MMPLAYER_FLEAVE();
13740         return MM_ERROR_NONE;
13741 }
13742
13743 int
13744 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13745 {
13746         mm_player_t* player = (mm_player_t*) hplayer;
13747         GstElement* rg_vol_element = NULL;
13748
13749         MMPLAYER_FENTER();
13750
13751         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13752
13753         player->sound.rg_enable = enabled;
13754
13755         /* just hold rgvolume enable value if pipeline is not ready */
13756         if (!player->pipeline || !player->pipeline->audiobin) {
13757                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13758                 return MM_ERROR_NONE;
13759         }
13760
13761         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13762
13763         if (!rg_vol_element) {
13764                 LOGD("rgvolume element is not created");
13765                 return MM_ERROR_PLAYER_INTERNAL;
13766         }
13767
13768         if (enabled)
13769                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13770         else
13771                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13772
13773         MMPLAYER_FLEAVE();
13774
13775         return MM_ERROR_NONE;
13776 }
13777
13778 int
13779 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13780 {
13781         mm_player_t* player = (mm_player_t*) hplayer;
13782         GstElement* rg_vol_element = NULL;
13783         gboolean enable = FALSE;
13784
13785         MMPLAYER_FENTER();
13786
13787         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13788         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13789
13790         /* just hold enable_rg value if pipeline is not ready */
13791         if (!player->pipeline || !player->pipeline->audiobin) {
13792                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13793                 *enabled = player->sound.rg_enable;
13794                 return MM_ERROR_NONE;
13795         }
13796
13797         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13798
13799         if (!rg_vol_element) {
13800                 LOGD("rgvolume element is not created");
13801                 return MM_ERROR_PLAYER_INTERNAL;
13802         }
13803
13804         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13805         *enabled = enable;
13806
13807         MMPLAYER_FLEAVE();
13808
13809         return MM_ERROR_NONE;
13810 }