[0.6.123] add _abort_pause
[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_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
108
109 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
139
140 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
146 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157
158 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
159 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
175
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
189
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
193
194 static int              __gst_realize(mm_player_t* player);
195 static int              __gst_unrealize(mm_player_t* player);
196 static int              __gst_start(mm_player_t* player);
197 static int              __gst_stop(mm_player_t* player);
198 static int              __gst_pause(mm_player_t* player, gboolean async);
199 static int              __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202                                         gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
204
205 static int              __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int              __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
210
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
212
213 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
214
215 /* util */
216 static gboolean __is_ms_buff_src(mm_player_t* player);
217 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
218
219 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
220 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
221 static int __mmplayer_start_streaming_ext(mm_player_t *player);
222 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
223 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
224
225 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
226 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
227 static void __mmplayer_check_pipeline(mm_player_t* player);
228 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
229 static void __mmplayer_deactivate_old_path(mm_player_t *player);
230
231 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
232 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
233
234 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
235 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
236 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
237 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
238 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
239 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
240 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
241 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
242 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
245 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
246 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
247 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
248 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
249 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
250 static void             __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type);
251
252 /*===========================================================================================
253 |                                                                                                                                                                                       |
254 |  FUNCTION DEFINITIONS                                                                                                                                         |
255 |                                                                                                                                                                                       |
256 ========================================================================================== */
257
258 #if 0 //debug
259 static void
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
261 {
262         gint i, count;
263
264         count = gst_tag_list_get_tag_size(list, tag);
265
266         LOGD("count = %d", count);
267
268         for (i = 0; i < count; i++) {
269                 gchar *str;
270
271                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
273                                 g_assert_not_reached();
274                 } else
275                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
276
277                 if (i == 0)
278                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
279                 else
280                         g_print("                 : %s\n", str);
281
282                 g_free(str);
283         }
284 }
285 #endif
286
287 /* This function should be called after the pipeline goes PAUSED or higher
288 state. */
289 gboolean
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
291 {
292         static gboolean has_duration = FALSE;
293         static gboolean has_video_attrs = FALSE;
294         static gboolean has_audio_attrs = FALSE;
295         static gboolean has_bitrate = FALSE;
296         gboolean missing_only = FALSE;
297         gboolean all = FALSE;
298         gint64 dur_nsec = 0;
299         GstStructure* p = NULL;
300         MMHandleType attrs = 0;
301         gchar *path = NULL;
302         struct stat sb;
303
304         MMPLAYER_FENTER();
305
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
307
308         /* check player state here */
309         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311                 /* give warning now only */
312                 LOGW("be careful. content attributes may not available in this state ");
313         }
314
315         /* get content attribute first */
316         attrs = MMPLAYER_GET_ATTRS(player);
317         if (!attrs) {
318                 LOGE("cannot get content attribute");
319                 return FALSE;
320         }
321
322         /* get update flag */
323
324         if (flag & ATTR_MISSING_ONLY) {
325                 missing_only = TRUE;
326                 LOGD("updating missed attr only");
327         }
328
329         if (flag & ATTR_ALL) {
330                 all = TRUE;
331                 has_duration = FALSE;
332                 has_video_attrs = FALSE;
333                 has_audio_attrs = FALSE;
334                 has_bitrate = FALSE;
335
336                 LOGD("updating all attrs");
337         }
338
339         if (missing_only && all) {
340                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341                 missing_only = FALSE;
342         }
343
344         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345                 LOGD("try to update duration");
346                 has_duration = FALSE;
347
348                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349                         player->duration = dur_nsec;
350                         LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
351                         has_duration = TRUE;
352                 }
353
354                 if (player->duration < 0) {
355                         LOGW("duration is Non-Initialized !!!");
356                         player->duration = 0;
357                 }
358
359                 /* update streaming service type */
360                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
361
362                 /* check duration is OK */
363                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364                         /* FIXIT : find another way to get duration here. */
365                         LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
366                 }
367         }
368
369         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370                 /* update audio params
371                 NOTE : We need original audio params and it can be only obtained from src pad of audio
372                 decoder. Below code only valid when we are not using 'resampler' just before
373                 'audioconverter'. */
374
375                 LOGD("try to update audio attrs");
376                 has_audio_attrs = FALSE;
377
378                 if (player->pipeline->audiobin &&
379                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380                         GstCaps *caps_a = NULL;
381                         GstPad* pad = NULL;
382                         gint samplerate = 0, channels = 0;
383
384                         pad = gst_element_get_static_pad(
385                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
386
387                         if (pad) {
388                                 caps_a = gst_pad_get_current_caps(pad);
389
390                                 if (caps_a) {
391                                         p = gst_caps_get_structure(caps_a, 0);
392
393                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
394
395                                         gst_structure_get_int(p, "rate", &samplerate);
396                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
397
398                                         gst_structure_get_int(p, "channels", &channels);
399                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
400
401                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
402
403                                         gst_caps_unref(caps_a);
404                                         caps_a = NULL;
405
406                                         has_audio_attrs = TRUE;
407                                 } else
408                                         LOGW("not ready to get audio caps");
409
410                                 gst_object_unref(pad);
411                         } else
412                                 LOGW("failed to get pad from audiosink");
413                 }
414         }
415
416         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417                 LOGD("try to update video attrs");
418                 has_video_attrs = FALSE;
419
420                 if (player->pipeline->videobin &&
421                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422                         GstCaps *caps_v = NULL;
423                         GstPad* pad = NULL;
424                         gint tmpNu, tmpDe;
425                         gint width, height;
426
427                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
428                         if (pad) {
429                                 caps_v = gst_pad_get_current_caps(pad);
430
431                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432                                 if (!caps_v && player->v_stream_caps) {
433                                         caps_v = player->v_stream_caps;
434                                         gst_caps_ref(caps_v);
435                                 }
436
437                                 if (caps_v) {
438                                         p = gst_caps_get_structure(caps_v, 0);
439                                         gst_structure_get_int(p, "width", &width);
440                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
441
442                                         gst_structure_get_int(p, "height", &height);
443                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
444
445                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
446
447                                         SECURE_LOGD("width : %d     height : %d", width, height);
448
449                                         gst_caps_unref(caps_v);
450                                         caps_v = NULL;
451
452                                         if (tmpDe > 0) {
453                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
455                                         }
456
457                                         has_video_attrs = TRUE;
458                                 } else
459                                         LOGD("no negitiated caps from videosink");
460                                 gst_object_unref(pad);
461                                 pad = NULL;
462                         } else {
463                                 LOGD("no videosink sink pad");
464                         }
465                 }
466         }
467
468
469         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
470                 has_bitrate = FALSE;
471
472                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473                 if (player->duration) {
474                         guint64 data_size = 0;
475
476                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
478
479                                 if (stat(path, &sb) == 0)
480                                         data_size = (guint64)sb.st_size;
481                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482                                 data_size = player->http_content_size;
483                         }
484                         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
485
486                         if (data_size) {
487                                 guint64 bitrate = 0;
488                                 guint64 msec_dur = 0;
489
490                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
491                                 if (msec_dur > 0) {
492                                         bitrate = data_size * 8 * 1000 / msec_dur;
493                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
495
496                                         has_bitrate = TRUE;
497                                 } else {
498                                         LOGD("player duration is less than 0");
499                                 }
500                         }
501
502                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503                                 if (player->total_bitrate) {
504                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
505                                         has_bitrate = TRUE;
506                                 }
507                         }
508                 }
509         }
510
511         /* validate all */
512         if (mmf_attrs_commit(attrs)) {
513                 LOGE("failed to update attributes\n");
514                 return FALSE;
515         }
516
517         MMPLAYER_FLEAVE();
518
519         return TRUE;
520 }
521
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
523 {
524         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
525
526         MMPLAYER_FENTER();
527
528         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
529                         player->pipeline &&
530                         player->pipeline->mainbin &&
531                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532                         STREAMING_SERVICE_NONE);
533
534         /* streaming service type if streaming */
535         if (!MMPLAYER_IS_STREAMING(player))
536                 return STREAMING_SERVICE_NONE;
537
538         if (MMPLAYER_IS_HTTP_STREAMING(player))
539                 streaming_type = (player->duration == 0) ?
540                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
541
542         switch (streaming_type) {
543         case STREAMING_SERVICE_LIVE:
544                 LOGD("it's live streaming");
545                 break;
546         case STREAMING_SERVICE_VOD:
547                 LOGD("it's vod streaming");
548                 break;
549         default:
550                 LOGE("should not get here");
551                 break;
552         }
553
554         MMPLAYER_FLEAVE();
555
556         return streaming_type;
557 }
558
559
560 /* this function sets the player state and also report
561  * it to applicaton by calling callback function
562  */
563 void
564 __mmplayer_set_state(mm_player_t* player, int state)
565 {
566         MMMessageParamType msg = {0, };
567         gboolean post_bos = FALSE;
568
569         MMPLAYER_RETURN_IF_FAIL(player);
570
571         if (MMPLAYER_CURRENT_STATE(player) == state) {
572                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
574                 return;
575         }
576
577         /* update player states */
578         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579         MMPLAYER_CURRENT_STATE(player) = state;
580
581         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
583
584         /* print state */
585         MMPLAYER_PRINT_STATE(player);
586
587         switch (MMPLAYER_CURRENT_STATE(player)) {
588         case MM_PLAYER_STATE_NULL:
589         case MM_PLAYER_STATE_READY:
590                 break;
591
592         case MM_PLAYER_STATE_PAUSED:
593                 {
594                         if (!player->sent_bos) {
595                                 /* rtsp case, get content attrs by GstMessage */
596                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597                                         /* it's first time to update all content attrs. */
598                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
599                                 }
600                         }
601
602                         /* add audio callback probe if condition is satisfied */
603                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604                                 __mmplayer_configure_audio_callback(player);
605
606                         /* FIXIT : handle return value */
607                 }
608                 break;
609
610         case MM_PLAYER_STATE_PLAYING:
611                 {
612                         /* try to get content metadata */
613                         if (!player->sent_bos) {
614                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
616                                  * legacy mmfw-player api */
617                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
618                         }
619
620                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621                                 if (!player->sent_bos)
622                                         __mmplayer_handle_missed_plugin(player);
623                         }
624
625                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626                                 /* initialize because auto resume is done well. */
627                                 player->resumed_by_rewind = FALSE;
628                                 player->playback_rate = 1.0;
629                         }
630
631                         if (!player->sent_bos) {
632                                 /* check audio codec field is set or not
633                                  * we can get it from typefinder or codec's caps.
634                                  */
635                                 gchar *audio_codec = NULL;
636                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
637
638                                 /* The codec format can't be sent for audio only case like amr, mid etc.
639                                  * Because, parser don't make related TAG.
640                                  * So, if it's not set yet, fill it with found data.
641                                  */
642                                 if (!audio_codec) {
643                                         if (g_strrstr(player->type, "audio/midi"))
644                                                 audio_codec = g_strdup("MIDI");
645                                         else if (g_strrstr(player->type, "audio/x-amr"))
646                                                 audio_codec = g_strdup("AMR");
647                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648                                                 audio_codec = g_strdup("AAC");
649                                         else
650                                                 audio_codec = g_strdup("unknown");
651                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
652
653                                         MMPLAYER_FREEIF(audio_codec);
654                                         if (mmf_attrs_commit(player->attrs))
655                                                 LOGE("failed to update attributes\n");
656
657                                         LOGD("set audio codec type with caps\n");
658                                 }
659
660                                 post_bos = TRUE;
661                         }
662                 }
663                 break;
664
665         case MM_PLAYER_STATE_NONE:
666         default:
667                 LOGW("invalid target state, there is nothing to do.\n");
668                 break;
669         }
670
671
672         /* post message to application */
673         if (MMPLAYER_TARGET_STATE(player) == state) {
674                 /* fill the message with state of player */
675                 msg.union_type = MM_MSG_UNION_STATE;
676                 msg.state.previous = MMPLAYER_PREV_STATE(player);
677                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
678
679                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
680
681                 /* state changed by resource callback */
682                 if (player->interrupted_by_resource) {
683                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
684                 } else { /* state changed by usecase */
685                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
686                 }
687         } else {
688                 LOGD("intermediate state, do nothing.\n");
689                 MMPLAYER_PRINT_STATE(player);
690                 return;
691         }
692
693         if (post_bos) {
694                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
695                 player->sent_bos = TRUE;
696         }
697
698         return;
699 }
700
701 static gpointer __mmplayer_next_play_thread(gpointer data)
702 {
703         mm_player_t* player = (mm_player_t*) data;
704         MMPlayerGstElement *mainbin = NULL;
705
706         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
707
708         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
709         while (!player->next_play_thread_exit) {
710                 LOGD("next play thread started. waiting for signal.\n");
711                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
712
713                 LOGD("reconfigure pipeline for gapless play.\n");
714
715                 if (player->next_play_thread_exit) {
716                         if (player->gapless.reconfigure) {
717                                 player->gapless.reconfigure = false;
718                                 MMPLAYER_PLAYBACK_UNLOCK(player);
719                         }
720                         LOGD("exiting gapless play thread\n");
721                         break;
722                 }
723
724                 mainbin = player->pipeline->mainbin;
725
726                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
731
732                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
733         }
734         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
735
736         return NULL;
737 }
738
739 static void
740 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
741 {
742         MMHandleType attrs = 0;
743         guint64 data_size = 0;
744         gchar* path = NULL;
745         gint64 pos_nsec = 0;
746         struct stat sb;
747
748         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
749
750         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec);       /* to update player->last_position */
751
752         attrs = MMPLAYER_GET_ATTRS(player);
753         if (!attrs) {
754                 LOGE("fail to get attributes.\n");
755                 return;
756         }
757
758         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
759                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
760
761                 if (stat(path, &sb) == 0)
762                         data_size = (guint64)sb.st_size;
763         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
764                 data_size = player->http_content_size;
765
766         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
767         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
768
769         return;
770 }
771
772 static int
773 __mmplayer_handle_buffering_message(mm_player_t* player)
774 {
775         int ret = MM_ERROR_NONE;
776         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
777         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
778         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
779         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
780
781         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
782                 LOGW("do nothing for buffering msg\n");
783                 ret = MM_ERROR_PLAYER_INVALID_STATE;
784                 goto exit;
785         }
786
787         prev_state = MMPLAYER_PREV_STATE(player);
788         current_state = MMPLAYER_CURRENT_STATE(player);
789         target_state = MMPLAYER_TARGET_STATE(player);
790         pending_state = MMPLAYER_PENDING_STATE(player);
791
792         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
793                 MMPLAYER_STATE_GET_NAME(prev_state),
794                 MMPLAYER_STATE_GET_NAME(current_state),
795                 MMPLAYER_STATE_GET_NAME(pending_state),
796                 MMPLAYER_STATE_GET_NAME(target_state),
797                 player->streamer->buffering_state);
798
799         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
800                 /* NOTE : if buffering has done, player has to go to target state. */
801                 switch (target_state) {
802                 case MM_PLAYER_STATE_PAUSED:
803                         {
804                                 switch (pending_state) {
805                                 case MM_PLAYER_STATE_PLAYING:
806                                         __gst_pause(player, TRUE);
807                                         break;
808
809                                 case MM_PLAYER_STATE_PAUSED:
810                                         LOGD("player is already going to paused state, there is nothing to do.\n");
811                                         break;
812
813                                 case MM_PLAYER_STATE_NONE:
814                                 case MM_PLAYER_STATE_NULL:
815                                 case MM_PLAYER_STATE_READY:
816                                 default:
817                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
818                                         break;
819                                 }
820                         }
821                         break;
822
823                 case MM_PLAYER_STATE_PLAYING:
824                         {
825                                 switch (pending_state) {
826                                 case MM_PLAYER_STATE_NONE:
827                                         {
828                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
829                                                         __gst_resume(player, TRUE);
830                                         }
831                                         break;
832
833                                 case MM_PLAYER_STATE_PAUSED:
834                                         /* NOTE: It should be worked as asynchronously.
835                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
836                                          */
837                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
838                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
839                                                  * The current state should be changed to paused purposely to prevent state conflict.
840                                                  */
841                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
842                                         }
843                                         __gst_resume(player, TRUE);
844                                         break;
845
846                                 case MM_PLAYER_STATE_PLAYING:
847                                         LOGD("player is already going to playing state, there is nothing to do.\n");
848                                         break;
849
850                                 case MM_PLAYER_STATE_NULL:
851                                 case MM_PLAYER_STATE_READY:
852                                 default:
853                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
854                                         break;
855                                 }
856                         }
857                         break;
858
859                 case MM_PLAYER_STATE_NULL:
860                 case MM_PLAYER_STATE_READY:
861                 case MM_PLAYER_STATE_NONE:
862                 default:
863                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
864                         break;
865                 }
866         } else {
867                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
868                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
869                  */
870                 switch (pending_state) {
871                 case MM_PLAYER_STATE_NONE:
872                         {
873                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
874                                         /* rtsp streaming pause makes rtsp server stop sending data. */
875                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
876                                                 LOGD("set pause state during buffering\n");
877                                                 __gst_pause(player, TRUE);
878                                         }
879                                 }
880                         }
881                         break;
882
883                 case MM_PLAYER_STATE_PLAYING:
884                         /* rtsp streaming pause makes rtsp server stop sending data. */
885                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
886                                 __gst_pause(player, TRUE);
887                         break;
888
889                 case MM_PLAYER_STATE_PAUSED:
890                         break;
891
892                 case MM_PLAYER_STATE_NULL:
893                 case MM_PLAYER_STATE_READY:
894                 default:
895                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
896                         break;
897                 }
898         }
899
900 exit:
901         return ret;
902 }
903
904 static void
905 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
906 {
907         MMPlayerGstElement *textbin;
908         MMPLAYER_FENTER();
909
910         MMPLAYER_RETURN_IF_FAIL(player &&
911                                         player->pipeline &&
912                                         player->pipeline->textbin);
913
914         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
915
916         textbin = player->pipeline->textbin;
917
918         if (is_drop) {
919                 LOGD("Drop subtitle text after getting EOS\n");
920
921                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
922                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
923
924                 player->is_subtitle_force_drop = TRUE;
925         } else {
926                 if (player->is_subtitle_force_drop == TRUE) {
927                         LOGD("Enable subtitle data path without drop\n");
928
929                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
930                         __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
931
932                         LOGD("non-connected with external display");
933
934                         player->is_subtitle_force_drop = FALSE;
935                 }
936         }
937 }
938
939 static VariantData *
940 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
941 {
942         VariantData *var_info = NULL;
943         g_return_val_if_fail(self != NULL, NULL);
944
945         var_info = g_new0(VariantData, 1);
946         if (!var_info) return NULL;
947         var_info->bandwidth = self->bandwidth;
948         var_info->width = self->width;
949         var_info->height = self->height;
950         return var_info;
951 }
952
953 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
954 {
955         mm_player_t* player = (mm_player_t*)hplayer;
956         GstMessage *msg = NULL;
957         GQueue *queue = NULL;
958
959         MMPLAYER_FENTER();
960         MMPLAYER_RETURN_IF_FAIL(player);
961
962         /* disconnecting bus watch */
963         if (player->bus_watcher)
964                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
965         player->bus_watcher = 0;
966
967         /* destroy the gst bus msg thread */
968         if (player->bus_msg_thread) {
969                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
970                 player->bus_msg_thread_exit = TRUE;
971                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
972                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
973
974                 LOGD("gst bus msg thread exit.");
975                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
976                 player->bus_msg_thread = NULL;
977
978                 g_mutex_clear(&player->bus_msg_thread_mutex);
979                 g_cond_clear(&player->bus_msg_thread_cond);
980         }
981
982         g_mutex_lock(&player->bus_msg_q_lock);
983         queue = player->bus_msg_q;
984         while (!g_queue_is_empty(queue)) {
985                 msg = (GstMessage *)g_queue_pop_head(queue);
986                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
987                 gst_message_unref(msg);
988         }
989         g_mutex_unlock(&player->bus_msg_q_lock);
990
991         MMPLAYER_FLEAVE();
992 }
993
994 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
995 {
996         mm_player_t *player = (mm_player_t *) data;
997
998         g_return_val_if_fail(player, FALSE);
999         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1000
1001         gst_message_ref(msg);
1002
1003         g_mutex_lock(&player->bus_msg_q_lock);
1004         g_queue_push_tail(player->bus_msg_q, msg);
1005         g_mutex_unlock(&player->bus_msg_q_lock);
1006
1007         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1008         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1009         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1010         return TRUE;
1011 }
1012
1013 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1014 {
1015         mm_player_t *player = (mm_player_t*)(data);
1016         GstMessage *msg = NULL;
1017         GstBus *bus = NULL;
1018
1019         MMPLAYER_FENTER();
1020         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1021                                                 player->pipeline &&
1022                                                 player->pipeline->mainbin &&
1023                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1024                                                 NULL);
1025
1026         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1027         if (!bus) {
1028                 LOGE("cannot get BUS from the pipeline");
1029                 return NULL;
1030         }
1031
1032         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1033
1034         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1035         while (!player->bus_msg_thread_exit) {
1036                 g_mutex_lock(&player->bus_msg_q_lock);
1037                 msg = g_queue_pop_head(player->bus_msg_q);
1038                 g_mutex_unlock(&player->bus_msg_q_lock);
1039                 if (msg == NULL) {
1040                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1041                         continue;
1042                 }
1043                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1044                 /* handle the gst msg */
1045                 __mmplayer_gst_callback(msg, player);
1046                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1047                 gst_message_unref(msg);
1048         }
1049
1050         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1051         gst_object_unref(GST_OBJECT(bus));
1052
1053         MMPLAYER_FLEAVE();
1054         return NULL;
1055 }
1056
1057 static void
1058 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1059 {
1060         mm_player_t* player = (mm_player_t*)(data);
1061
1062         MMPLAYER_RETURN_IF_FAIL(player);
1063         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1064
1065         switch (GST_MESSAGE_TYPE(msg)) {
1066         case GST_MESSAGE_UNKNOWN:
1067                 LOGD("unknown message received\n");
1068                 break;
1069
1070         case GST_MESSAGE_EOS:
1071                 {
1072                         MMHandleType attrs = 0;
1073                         gint count = 0;
1074
1075                         LOGD("GST_MESSAGE_EOS received\n");
1076
1077                         /* NOTE : EOS event is comming multiple time. watch out it */
1078                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1079                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1080                                 LOGD("EOS received on non-playing state. ignoring it\n");
1081                                 break;
1082                         }
1083
1084                         if (player->pipeline) {
1085                                 if (player->pipeline->textbin)
1086                                         __mmplayer_drop_subtitle(player, TRUE);
1087
1088                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1089                                         GstPad *pad = NULL;
1090
1091                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1092
1093                                         LOGD("release audio callback\n");
1094
1095                                         /* release audio callback */
1096                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1097                                         player->audio_cb_probe_id = 0;
1098                                         /* audio callback should be free because it can be called even though probe remove.*/
1099                                         player->audio_stream_cb = NULL;
1100                                         player->audio_stream_cb_user_param = NULL;
1101
1102                                 }
1103                         }
1104                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1105                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1106
1107                         /* rewind if repeat count is greater then zero */
1108                         /* get play count */
1109                         attrs = MMPLAYER_GET_ATTRS(player);
1110
1111                         if (attrs) {
1112                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1113
1114                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1115
1116                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1117                                         if (player->playback_rate < 0.0) {
1118                                                 player->resumed_by_rewind = TRUE;
1119                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1120                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1121                                         }
1122
1123                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1124
1125                                         /* initialize */
1126                                         player->sent_bos = FALSE;
1127
1128                                         /* not posting eos when repeating */
1129                                         break;
1130                                 }
1131                         }
1132
1133                         if (player->pipeline)
1134                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1135
1136                         /* post eos message to application */
1137                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1138
1139                         /* reset last position */
1140                         player->last_position = 0;
1141                 }
1142                 break;
1143
1144         case GST_MESSAGE_ERROR:
1145                 {
1146                         GError *error = NULL;
1147                         gchar* debug = NULL;
1148
1149                         /* generating debug info before returning error */
1150                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1151
1152                         /* get error code */
1153                         gst_message_parse_error(msg, &error, &debug);
1154
1155                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1156                                 /* Note : the streaming error from the streaming source is handled
1157                                  *   using __mmplayer_handle_streaming_error.
1158                                  */
1159                                 __mmplayer_handle_streaming_error(player, msg);
1160
1161                                 /* dump state of all element */
1162                                 __mmplayer_dump_pipeline_state(player);
1163                         } else {
1164                                 /* traslate gst error code to msl error code. then post it
1165                                  * to application if needed
1166                                  */
1167                                 __mmplayer_handle_gst_error(player, msg, error);
1168
1169                                 if (debug)
1170                                         LOGE("error debug : %s", debug);
1171                         }
1172
1173                         if (MMPLAYER_IS_HTTP_PD(player))
1174                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1175
1176                         MMPLAYER_FREEIF(debug);
1177                         g_error_free(error);
1178                 }
1179                 break;
1180
1181         case GST_MESSAGE_WARNING:
1182                 {
1183                         char* debug = NULL;
1184                         GError* error = NULL;
1185
1186                         gst_message_parse_warning(msg, &error, &debug);
1187
1188                         LOGD("warning : %s\n", error->message);
1189                         LOGD("debug : %s\n", debug);
1190
1191                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1192
1193                         MMPLAYER_FREEIF(debug);
1194                         g_error_free(error);
1195                 }
1196                 break;
1197
1198         case GST_MESSAGE_TAG:
1199                 {
1200                         LOGD("GST_MESSAGE_TAG\n");
1201                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1202                                 LOGW("failed to extract tags from gstmessage\n");
1203                 }
1204                 break;
1205
1206         case GST_MESSAGE_BUFFERING:
1207                 {
1208                         MMMessageParamType msg_param = {0, };
1209                         int bRet = MM_ERROR_NONE;
1210
1211                         if (!(player->pipeline && player->pipeline->mainbin)) {
1212                                 LOGE("Pipeline is not initialized");
1213                                 break;
1214                         }
1215
1216                         if (!MMPLAYER_IS_STREAMING(player))
1217                                 break;
1218
1219                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1220                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1221                                         /* skip the playback control by buffering msg while user request is handled. */
1222                                         gint per = 0;
1223
1224                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1225
1226                                         gst_message_parse_buffering(msg, &per);
1227                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1228
1229                                         msg_param.connection.buffering = per;
1230                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1231                                         break;
1232                                 }
1233                         } else {
1234                                 MMPLAYER_CMD_LOCK(player);
1235                         }
1236
1237                         if (!player->streamer) {
1238                                 LOGW("Pipeline is shutting down");
1239                                 MMPLAYER_CMD_UNLOCK(player);
1240                                 break;
1241                         }
1242
1243                         /* ignore the remained buffering message till getting 100% msg */
1244                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1245                                 gint buffer_percent = 0;
1246
1247                                 gst_message_parse_buffering(msg, &buffer_percent);
1248
1249                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1250                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1251                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1252                                 }
1253                                 MMPLAYER_CMD_UNLOCK(player);
1254                                 break;
1255                         }
1256
1257                         /* ignore the remained buffering message */
1258                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1259                                 gint buffer_percent = 0;
1260
1261                                 gst_message_parse_buffering(msg, &buffer_percent);
1262
1263                                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1264                                                         player->streamer->buffering_percent, buffer_percent);
1265
1266                                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1267                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1268                                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1269
1270                                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1271                                 } else {
1272                                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1273                                         MMPLAYER_CMD_UNLOCK(player);
1274                                         break;
1275                                 }
1276                         }
1277
1278                         __mmplayer_update_buffer_setting(player, msg);
1279
1280                         bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1281
1282                         if (bRet == MM_ERROR_NONE) {
1283                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1284                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1285
1286                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1287                                         player->pending_resume &&
1288                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1289
1290                                         player->is_external_subtitle_added_now = FALSE;
1291                                         player->pending_resume = FALSE;
1292                                         _mmplayer_resume((MMHandleType)player);
1293                                 }
1294
1295                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1296                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1297
1298                                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1299                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1300                                                         player->seek_state = MMPLAYER_SEEK_NONE;
1301                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1302                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1303                                                         /* Considering the async state trasition in case of RTSP.
1304                                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1305                                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1306                                                 }
1307                                         }
1308                                 }
1309                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310                                 if (!player->streamer) {
1311                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312                                         MMPLAYER_CMD_UNLOCK(player);
1313                                         break;
1314                                 }
1315
1316                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1317
1318                                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1320
1321                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1323                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1324                                         } else {
1325                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1326                                         }
1327                                 } else {
1328                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1329                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1330                                 }
1331                         }
1332                         MMPLAYER_CMD_UNLOCK(player);
1333                 }
1334                 break;
1335
1336         case GST_MESSAGE_STATE_CHANGED:
1337                 {
1338                         MMPlayerGstElement *mainbin;
1339                         const GValue *voldstate, *vnewstate, *vpending;
1340                         GstState oldstate = GST_STATE_NULL;
1341                         GstState newstate = GST_STATE_NULL;
1342                         GstState pending = GST_STATE_NULL;
1343
1344                         if (!(player->pipeline && player->pipeline->mainbin)) {
1345                                 LOGE("player pipeline handle is null");
1346                                 break;
1347                         }
1348
1349                         mainbin = player->pipeline->mainbin;
1350
1351                         /* we only handle messages from pipeline */
1352                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1353                                 break;
1354
1355                         /* get state info from msg */
1356                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1359
1360                         if (!voldstate || !vnewstate) {
1361                                 LOGE("received msg has wrong format.");
1362                                 break;
1363                         }
1364
1365                         oldstate = (GstState)voldstate->data[0].v_int;
1366                         newstate = (GstState)vnewstate->data[0].v_int;
1367                         if (vpending)
1368                                 pending = (GstState)vpending->data[0].v_int;
1369
1370                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1371                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372                                 gst_element_state_get_name((GstState)oldstate),
1373                                 gst_element_state_get_name((GstState)newstate),
1374                                 gst_element_state_get_name((GstState)pending));
1375
1376                         if (newstate == GST_STATE_PLAYING) {
1377                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1378
1379                                         int retVal = MM_ERROR_NONE;
1380                                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1381
1382                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1383
1384                                         if (MM_ERROR_NONE != retVal)
1385                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1386
1387                                         player->pending_seek.is_pending = FALSE;
1388                                 }
1389                         }
1390
1391                         if (oldstate == newstate) {
1392                                 LOGD("pipeline reports state transition to old state");
1393                                 break;
1394                         }
1395
1396                         switch (newstate) {
1397                         case GST_STATE_VOID_PENDING:
1398                                 break;
1399
1400                         case GST_STATE_NULL:
1401                                 break;
1402
1403                         case GST_STATE_READY:
1404                                 break;
1405
1406                         case GST_STATE_PAUSED:
1407                                 {
1408                                         gboolean prepare_async = FALSE;
1409
1410                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411                                                 __mmplayer_configure_audio_callback(player);
1412
1413                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414                                                 // managed prepare async case
1415                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1417                                         }
1418
1419                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1421
1422                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1424                                                                 player->total_maximum_bitrate, player->total_bitrate);
1425
1426                                                 if (player->pending_seek.is_pending) {
1427                                                         LOGW("trying to do pending seek");
1428                                                         MMPLAYER_CMD_LOCK(player);
1429                                                         __gst_pending_seek(player);
1430                                                         MMPLAYER_CMD_UNLOCK(player);
1431                                                 }
1432                                         }
1433                                 }
1434                                 break;
1435
1436                         case GST_STATE_PLAYING:
1437                                 {
1438                                         if (MMPLAYER_IS_STREAMING(player)) {
1439                                                 // managed prepare async case when buffering is completed
1440                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1444
1445                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1446
1447                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448                                                         if (player->streamer->buffering_percent < 100) {
1449
1450                                                                 MMMessageParamType msg_param = {0, };
1451                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1452
1453                                                                 msg_param.connection.buffering = 100;
1454                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1455                                                         }
1456                                                 }
1457                                         }
1458
1459                                         if (player->gapless.stream_changed) {
1460                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461                                                 player->gapless.stream_changed = FALSE;
1462                                         }
1463
1464                                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1465                                                 player->seek_state = MMPLAYER_SEEK_NONE;
1466                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1467                                         }
1468                                 }
1469                                 break;
1470
1471                         default:
1472                                 break;
1473                         }
1474                 }
1475                 break;
1476
1477         case GST_MESSAGE_CLOCK_LOST:
1478                         {
1479                                 GstClock *clock = NULL;
1480                                 gboolean need_new_clock = FALSE;
1481
1482                                 gst_message_parse_clock_lost(msg, &clock);
1483                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1484
1485                                 if (!player->videodec_linked)
1486                                         need_new_clock = TRUE;
1487                                 else if (!player->ini.use_system_clock)
1488                                         need_new_clock = TRUE;
1489
1490                                 if (need_new_clock) {
1491                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1492                                         __gst_pause(player, FALSE);
1493                                         __gst_resume(player, FALSE);
1494                                 }
1495                         }
1496                         break;
1497
1498         case GST_MESSAGE_NEW_CLOCK:
1499                         {
1500                                 GstClock *clock = NULL;
1501                                 gst_message_parse_new_clock(msg, &clock);
1502                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1503                         }
1504                         break;
1505
1506         case GST_MESSAGE_ELEMENT:
1507                         {
1508                                 const gchar *structure_name;
1509                                 gint count = 0, idx = 0;
1510                                 MMHandleType attrs = 0;
1511
1512                                 attrs = MMPLAYER_GET_ATTRS(player);
1513                                 if (!attrs) {
1514                                         LOGE("cannot get content attribute");
1515                                         break;
1516                                 }
1517
1518                                 if (gst_message_get_structure(msg) == NULL)
1519                                         break;
1520
1521                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1522                                 if (!structure_name)
1523                                         break;
1524
1525                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1526
1527                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1528                                         const GValue *var_info = NULL;
1529
1530                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1531                                         if (var_info != NULL) {
1532                                                 if (player->adaptive_info.var_list)
1533                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1534
1535                                                 /* share addr or copy the list */
1536                                                 player->adaptive_info.var_list =
1537                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1538
1539                                                 count = g_list_length(player->adaptive_info.var_list);
1540                                                 if (count > 0) {
1541                                                         VariantData *temp = NULL;
1542
1543                                                         /* print out for debug */
1544                                                         LOGD("num of variant_info %d", count);
1545                                                         for (idx = 0; idx < count; idx++) {
1546                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1547                                                                 if (temp)
1548                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1549                                                         }
1550                                                 }
1551                                         }
1552                                 }
1553
1554                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1555                                         gint num_buffers = 0;
1556                                         gint extra_num_buffers = 0;
1557
1558                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1559                                                 player->video_num_buffers = num_buffers;
1560                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1561                                         }
1562
1563                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1564                                                 player->video_extra_num_buffers = extra_num_buffers;
1565                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1566                                         }
1567                                         break;
1568                                 }
1569
1570                                 if (!strcmp(structure_name, "Language_list")) {
1571                                         const GValue *lang_list = NULL;
1572                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1573                                         if (lang_list != NULL) {
1574                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1575                                                 if (count > 1)
1576                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1577                                         }
1578                                 }
1579
1580                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1581                                         const GValue *lang_list = NULL;
1582                                         MMPlayerLangStruct *temp = NULL;
1583
1584                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1585                                         if (lang_list != NULL) {
1586                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1587                                                 if (count) {
1588                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1589                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1590                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1591                                                         if (mmf_attrs_commit(attrs))
1592                                                                 LOGE("failed to commit.\n");
1593                                                         LOGD("Total subtitle tracks = %d \n", count);
1594
1595                                                         while (count) {
1596                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1597                                                                 if (temp)
1598                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1599                                                                                                 temp->language_key, temp->language_code);
1600                                                                 count--;
1601                                                         }
1602                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1603                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1604                                                 }
1605                                         }
1606                                 }
1607
1608                                 /* custom message */
1609                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1610                                         MMMessageParamType msg_param = {0,};
1611                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1612                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1613                                 }
1614
1615                                 /* custom message for RTSP attribute :
1616                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1617                                     sdp which has contents info is received when rtsp connection is opened.
1618                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1619                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1620
1621                                         gchar *audio_codec = NULL;
1622                                         gchar *video_codec = NULL;
1623                                         gchar *video_frame_size = NULL;
1624
1625                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1626                                         LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1627                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1628
1629                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1630                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1631                                         if (audio_codec)
1632                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1633
1634                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1635                                         LOGD("rtsp_video_codec : %s", video_codec);
1636                                         if (video_codec)
1637                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1638
1639                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1640                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1641                                         if (video_frame_size) {
1642
1643                                                 char *seperator = strchr(video_frame_size, '-');
1644                                                 if (seperator) {
1645
1646                                                         char video_width[10] = {0,};
1647                                                         int frame_size_len = strlen(video_frame_size);
1648                                                         int separtor_len = strlen(seperator);
1649
1650                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1651                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1652
1653                                                         seperator++;
1654                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1655                                                 }
1656                                         }
1657
1658                                         if (mmf_attrs_commit(attrs))
1659                                                 LOGE("failed to commit.\n");
1660                                 }
1661                         }
1662                         break;
1663
1664         case GST_MESSAGE_DURATION_CHANGED:
1665                 {
1666                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1667                         if (!__mmplayer_gst_handle_duration(player, msg))
1668                                 LOGW("failed to update duration");
1669                 }
1670
1671                 break;
1672
1673         case GST_MESSAGE_ASYNC_START:
1674                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1675                 break;
1676
1677         case GST_MESSAGE_ASYNC_DONE:
1678                 {
1679                         MMPlayerGstElement *mainbin;
1680
1681                         if (!(player->pipeline && player->pipeline->mainbin)) {
1682                                 LOGE("player pipeline handle is null");
1683                                 break;
1684                         }
1685
1686                         mainbin = player->pipeline->mainbin;
1687
1688                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1689
1690                         /* we only handle messages from pipeline */
1691                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1692                                 break;
1693
1694                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1695                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1696                                         player->seek_state = MMPLAYER_SEEK_NONE;
1697                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1698                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1699                                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1700                                                 LOGD("sync %s state(%s) with parent state(%s)",
1701                                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1702                                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1703                                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1704
1705                                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1706                                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1707                                                    Because the buffering state is controlled according to the state transition for force resume,
1708                                                    the decodebin state should be paused as player state. */
1709                                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1710                                         }
1711
1712                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1713                                                 (player->streamer) &&
1714                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1715                                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1716                                                 GstQuery *query = NULL;
1717                                                 gboolean busy = FALSE;
1718                                                 gint percent = 0;
1719
1720                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1721                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1722                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1723                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1724                                                         gst_query_unref(query);
1725
1726                                                         LOGD("buffered percent(%s): %d\n",
1727                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1728                                                 }
1729
1730                                                 if (percent >= 100)
1731                                                         __mmplayer_handle_buffering_message(player);
1732                                         }
1733
1734                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1735                                 }
1736                         }
1737                 }
1738                 break;
1739
1740         #if 0 /* delete unnecessary logs */
1741         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1742         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1743         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1744         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1745         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1746         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1747         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1748         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1749         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1750         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1751         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1752         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1753         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1754         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1755         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1756         #endif
1757
1758         default:
1759                 break;
1760         }
1761
1762         /* should not call 'gst_message_unref(msg)' */
1763         return;
1764 }
1765
1766 static gboolean
1767 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1768 {
1769         gint64 bytes = 0;
1770
1771         MMPLAYER_FENTER();
1772
1773         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1774         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1775
1776         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1777                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1778                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1779
1780                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1781                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1782                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1783                 }
1784         } else {
1785                 /* handling audio clip which has vbr. means duration is keep changing */
1786                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1787         }
1788
1789         MMPLAYER_FLEAVE();
1790
1791         return TRUE;
1792 }
1793
1794 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1795                 mm_player_spherical_metadata_t *metadata) {
1796         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1797         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1798         gst_tag_list_get_string(tags, "stitching_software",
1799                         &metadata->stitching_software);
1800         gst_tag_list_get_string(tags, "projection_type",
1801                         &metadata->projection_type_string);
1802         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1803         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1804         gst_tag_list_get_int(tags, "init_view_heading",
1805                         &metadata->init_view_heading);
1806         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1807         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1808         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1809         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1810                         &metadata->full_pano_width_pixels);
1811         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1812                         &metadata->full_pano_height_pixels);
1813         gst_tag_list_get_int(tags, "cropped_area_image_width",
1814                         &metadata->cropped_area_image_width);
1815         gst_tag_list_get_int(tags, "cropped_area_image_height",
1816                         &metadata->cropped_area_image_height);
1817         gst_tag_list_get_int(tags, "cropped_area_left",
1818                         &metadata->cropped_area_left);
1819         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1820         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1821         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1822         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1823 }
1824
1825 static gboolean
1826 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1827 {
1828
1829 /* macro for better code readability */
1830 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1832         if (string != NULL) { \
1833                 SECURE_LOGD("update tag string : %s\n", string); \
1834                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1835                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1836                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1837                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1838                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1839                         g_free(new_string); \
1840                         new_string = NULL; \
1841                 } else { \
1842                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1843                 } \
1844                 g_free(string); \
1845                 string = NULL; \
1846         } \
1847 }
1848
1849 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1850 do {    \
1851         GstSample *sample = NULL;\
1852         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1853                 GstMapInfo info = GST_MAP_INFO_INIT;\
1854                 buffer = gst_sample_get_buffer(sample);\
1855                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1856                         LOGD("failed to get image data from tag");\
1857                         gst_sample_unref(sample);\
1858                         return FALSE;\
1859                 } \
1860                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1861                 MMPLAYER_FREEIF(player->album_art);\
1862                 player->album_art = (gchar *)g_malloc(info.size);\
1863                 if (player->album_art) {\
1864                         memcpy(player->album_art, info.data, info.size);\
1865                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1866                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1867                                 msg_param.data = (void *)player->album_art;\
1868                                 msg_param.size = info.size;\
1869                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1870                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1871                         } \
1872                 } \
1873                 gst_buffer_unmap(buffer, &info);\
1874                 gst_sample_unref(sample);\
1875         }       \
1876 } while (0)
1877
1878 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1879 do {    \
1880         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1881                 if (v_uint) { \
1882                         int i = 0; \
1883                         gchar *tag_list_str = NULL; \
1884                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1885                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1886                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1887                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1888                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1889                         else \
1890                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1891                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1892                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1893                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1894                                 player->bitrate[track_type] = v_uint; \
1895                                 player->total_bitrate = 0; \
1896                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1897                                         player->total_bitrate += player->bitrate[i]; \
1898                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1899                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1900                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1901                                 player->maximum_bitrate[track_type] = v_uint; \
1902                                 player->total_maximum_bitrate = 0; \
1903                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1904                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1905                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1906                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1907                         } else { \
1908                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1909                         } \
1910                         v_uint = 0;\
1911                         g_free(tag_list_str); \
1912                 } \
1913         } \
1914 } while (0)
1915
1916 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1917 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1918         if (date != NULL) {\
1919                 string = g_strdup_printf("%d", g_date_get_year(date));\
1920                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1921                 SECURE_LOGD("metainfo year : %s\n", string);\
1922                 MMPLAYER_FREEIF(string);\
1923                 g_date_free(date);\
1924         } \
1925 }
1926
1927 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1928 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1929         if (datetime != NULL) {\
1930                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1931                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1932                 SECURE_LOGD("metainfo year : %s\n", string);\
1933                 MMPLAYER_FREEIF(string);\
1934                 gst_date_time_unref(datetime);\
1935         } \
1936 }
1937
1938 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1939 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1940         if (v_uint64) {\
1941                 /* FIXIT : don't know how to store date */\
1942                 g_assert(1);\
1943                 v_uint64 = 0;\
1944         } \
1945 }
1946
1947 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1948 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1949         if (v_double) {\
1950                 /* FIXIT : don't know how to store date */\
1951                 g_assert(1);\
1952                 v_double = 0;\
1953         } \
1954 }
1955
1956         /* function start */
1957         GstTagList* tag_list = NULL;
1958
1959         MMHandleType attrs = 0;
1960
1961         char *string = NULL;
1962         guint v_uint = 0;
1963         GDate *date = NULL;
1964         GstDateTime *datetime = NULL;
1965         /* album cover */
1966         GstBuffer *buffer = NULL;
1967         gint index = 0;
1968         MMMessageParamType msg_param = {0, };
1969
1970         /* currently not used. but those are needed for above macro */
1971         //guint64 v_uint64 = 0;
1972         //gdouble v_double = 0;
1973
1974         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1975
1976         attrs = MMPLAYER_GET_ATTRS(player);
1977
1978         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1979
1980         /* get tag list from gst message */
1981         gst_message_parse_tag(msg, &tag_list);
1982
1983         /* store tags to player attributes */
1984         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1985         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1986         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1987         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1988         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1989         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1990         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1991         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1992         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1993         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1994         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1995         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1996         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1997         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1998         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1999         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2000         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2001         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2002         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2003         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2004         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2005         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2006         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2007         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2008         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2009         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2010         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2011         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2012         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2013         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2014         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2015         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2016         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2017         MMPLAYER_UPDATE_TAG_LOCK(player);
2018         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2019         MMPLAYER_UPDATE_TAG_UNLOCK(player);
2020         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2021         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2022         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2023         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2024         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2025         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2026         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2027         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2028         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2029         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2030         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2031         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2032         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2033
2034         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2035                 if (player->video360_metadata.is_spherical == -1) {
2036                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2037                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2038                                         player->video360_metadata.is_spherical);
2039                         if (player->video360_metadata.is_spherical == 1) {
2040                                 LOGD("This is spherical content for 360 playback.");
2041                                 player->is_content_spherical = TRUE;
2042                         } else {
2043                                 LOGD("This is not spherical content");
2044                                 player->is_content_spherical = FALSE;
2045                         }
2046
2047                         if (player->video360_metadata.projection_type_string) {
2048                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2049                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2050                                 } else {
2051                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2052                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2053                                 }
2054                         }
2055
2056                         if (player->video360_metadata.stereo_mode_string) {
2057                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2058                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2059                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2060                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2061                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2062                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2063                                 } else {
2064                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2065                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2066                                 }
2067                         }
2068                 }
2069         }
2070
2071         if (mmf_attrs_commit(attrs))
2072                 LOGE("failed to commit.\n");
2073
2074         gst_tag_list_free(tag_list);
2075
2076         return TRUE;
2077 }
2078
2079 static void
2080 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2081 {
2082         mm_player_t* player = (mm_player_t*) data;
2083
2084         MMPLAYER_FENTER();
2085
2086         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2087           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2088           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2089           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2090
2091           * [1] audio and video will be dumped with filesink.
2092           * [2] autoplugging is done by just using pad caps.
2093           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2094           * and the video will be dumped via filesink.
2095           */
2096         if (player->num_dynamic_pad == 0) {
2097                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2098
2099                 if (!__mmplayer_gst_remove_fakesink(player,
2100                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2101                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2102                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2103                          * source element are not same. To overcome this situation, this function will called
2104                          * several places and several times. Therefore, this is not an error case.
2105                          */
2106                         return;
2107         }
2108
2109         /* create dot before error-return. for debugging */
2110         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2111
2112         player->no_more_pad = TRUE;
2113
2114         MMPLAYER_FLEAVE();
2115 }
2116
2117 static gboolean
2118 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2119 {
2120         GstElement* parent = NULL;
2121
2122         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2123
2124         /* if we have no fakesink. this meas we are using decodebin which doesn'
2125         t need to add extra fakesink */
2126         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2127
2128         /* lock */
2129         MMPLAYER_FSINK_LOCK(player);
2130
2131         if (!fakesink->gst)
2132                 goto ERROR;
2133
2134         /* get parent of fakesink */
2135         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2136         if (!parent) {
2137                 LOGD("fakesink already removed\n");
2138                 goto ERROR;
2139         }
2140
2141         gst_element_set_locked_state(fakesink->gst, TRUE);
2142
2143         /* setting the state to NULL never returns async
2144          * so no need to wait for completion of state transiton
2145          */
2146         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2147                 LOGE("fakesink state change failure!\n");
2148                 /* FIXIT : should I return here? or try to proceed to next? */
2149                 /* return FALSE; */
2150
2151         /* remove fakesink from it's parent */
2152         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2153                 LOGE("failed to remove fakesink\n");
2154
2155                 gst_object_unref(parent);
2156
2157                 goto ERROR;
2158         }
2159
2160         gst_object_unref(parent);
2161
2162         LOGD("state-holder removed\n");
2163
2164         gst_element_set_locked_state(fakesink->gst, FALSE);
2165
2166         MMPLAYER_FSINK_UNLOCK(player);
2167         return TRUE;
2168
2169 ERROR:
2170         if (fakesink->gst)
2171                 gst_element_set_locked_state(fakesink->gst, FALSE);
2172
2173         MMPLAYER_FSINK_UNLOCK(player);
2174         return FALSE;
2175 }
2176
2177
2178 static void
2179 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2180 {
2181         GstPad *sinkpad = NULL;
2182         GstCaps* caps = NULL;
2183         GstElement* new_element = NULL;
2184         GstStructure* str = NULL;
2185         const gchar* name = NULL;
2186
2187         mm_player_t* player = (mm_player_t*) data;
2188
2189         MMPLAYER_FENTER();
2190
2191         MMPLAYER_RETURN_IF_FAIL(element && pad);
2192         MMPLAYER_RETURN_IF_FAIL(player &&
2193                                         player->pipeline &&
2194                                         player->pipeline->mainbin);
2195
2196
2197         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2198          * num_dynamic_pad will decreased after creating a sinkbin.
2199          */
2200         player->num_dynamic_pad++;
2201         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2202
2203         caps = gst_pad_query_caps(pad, NULL);
2204
2205         MMPLAYER_CHECK_NULL(caps);
2206
2207         /* clear  previous result*/
2208         player->have_dynamic_pad = FALSE;
2209
2210         str = gst_caps_get_structure(caps, 0);
2211
2212         if (!str) {
2213                 LOGE("cannot get structure from caps.\n");
2214                 goto ERROR;
2215         }
2216
2217         name = gst_structure_get_name(str);
2218         if (!name) {
2219                 LOGE("cannot get mimetype from structure.\n");
2220                 goto ERROR;
2221         }
2222
2223         if (strstr(name, "video")) {
2224                 gint stype = 0;
2225                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2226
2227                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2228                         if (player->v_stream_caps) {
2229                                 gst_caps_unref(player->v_stream_caps);
2230                                 player->v_stream_caps = NULL;
2231                         }
2232
2233                         new_element = gst_element_factory_make("fakesink", NULL);
2234                         player->num_dynamic_pad--;
2235                         goto NEW_ELEMENT;
2236                 }
2237         }
2238
2239         /* clear  previous result*/
2240         player->have_dynamic_pad = FALSE;
2241
2242         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2243                 LOGE("failed to autoplug for caps");
2244                 goto ERROR;
2245         }
2246
2247         /* check if there's dynamic pad*/
2248         if (player->have_dynamic_pad) {
2249                 LOGE("using pad caps assums there's no dynamic pad !\n");
2250                 goto ERROR;
2251         }
2252
2253         gst_caps_unref(caps);
2254         caps = NULL;
2255
2256 NEW_ELEMENT:
2257
2258         /* excute new_element if created*/
2259         if (new_element) {
2260                 LOGD("adding new element to pipeline\n");
2261
2262                 /* set state to READY before add to bin */
2263                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2264
2265                 /* add new element to the pipeline */
2266                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2267                         LOGE("failed to add autoplug element to bin\n");
2268                         goto ERROR;
2269                 }
2270
2271                 /* get pad from element */
2272                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2273                 if (!sinkpad) {
2274                         LOGE("failed to get sinkpad from autoplug element\n");
2275                         goto ERROR;
2276                 }
2277
2278                 /* link it */
2279                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2280                         LOGE("failed to link autoplug element\n");
2281                         goto ERROR;
2282                 }
2283
2284                 gst_object_unref(sinkpad);
2285                 sinkpad = NULL;
2286
2287                 /* run. setting PLAYING here since streamming source is live source */
2288                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2289         }
2290
2291         if (caps)
2292                 gst_caps_unref(caps);
2293
2294         MMPLAYER_FLEAVE();
2295
2296         return;
2297
2298 STATE_CHANGE_FAILED:
2299 ERROR:
2300         /* FIXIT : take care if new_element has already added to pipeline */
2301         if (new_element)
2302                 gst_object_unref(GST_OBJECT(new_element));
2303
2304         if (sinkpad)
2305                 gst_object_unref(GST_OBJECT(sinkpad));
2306
2307         if (caps)
2308                 gst_caps_unref(caps);
2309
2310         /* FIXIT : how to inform this error to MSL ????? */
2311         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2312          * then post an error to application
2313          */
2314 }
2315
2316 static GstPadProbeReturn
2317 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2318 {
2319         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2320         return GST_PAD_PROBE_OK;
2321 }
2322
2323 static GstPadProbeReturn
2324 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2325 {
2326         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2327         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2328         mm_player_t* player = (mm_player_t*)data;
2329         GstCaps* caps = NULL;
2330         GstStructure* str = NULL;
2331         const gchar* name = NULL;
2332         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2333
2334
2335         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2336                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2337                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2338                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2339                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2340                         return ret;
2341         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2342                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2343                         return ret;
2344         }
2345
2346         caps = gst_pad_query_caps(pad, NULL);
2347         if (!caps) {
2348                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2349                 return ret;
2350         }
2351
2352         str = gst_caps_get_structure(caps, 0);
2353         if (!str) {
2354                 LOGE("failed to get structure from caps");
2355                 goto ERROR;
2356         }
2357
2358         name = gst_structure_get_name(str);
2359         if (!name) {
2360                 LOGE("failed to get name from str");
2361                 goto ERROR;
2362         }
2363
2364         if (strstr(name, "audio")) {
2365                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2366         } else if (strstr(name, "video")) {
2367                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2368         } else {
2369                 /* text track is not supportable */
2370                 LOGE("invalid name %s", name);
2371                 goto ERROR;
2372         }
2373
2374         switch (GST_EVENT_TYPE(event)) {
2375         case GST_EVENT_EOS:
2376                 {
2377                         /* in case of gapless, drop eos event not to send it to sink */
2378                         if (player->gapless.reconfigure && !player->msg_posted) {
2379                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2380                                 ret = GST_PAD_PROBE_DROP;
2381                         }
2382                         break;
2383                 }
2384         case GST_EVENT_STREAM_START:
2385                 {
2386                         gint64 stop_running_time = 0;
2387                         gint64 position_running_time = 0;
2388                         gint64 position = 0;
2389                         gint idx = 0;
2390
2391                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2392                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2393                                         !(player->selector[idx].event_probe_id)) {
2394                                         /* LOGW("[%d] skip", idx); */
2395                                         continue;
2396                                 }
2397
2398                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2399                                         stop_running_time =
2400                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2401                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2402                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2403                                         stop_running_time =
2404                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2405                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2406                                 } else {
2407                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2408                                         stop_running_time =
2409                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2410                                                                 GST_FORMAT_TIME, player->duration);
2411                                 }
2412
2413                                 position_running_time =
2414                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2415                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2416
2417                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2418                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2419                                         idx,
2420                                         GST_TIME_ARGS(stop_running_time),
2421                                         GST_TIME_ARGS(position_running_time),
2422                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2423                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2424
2425                                 position_running_time = MAX(position_running_time, stop_running_time);
2426                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2427                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2428                                 position_running_time = MAX(0, position_running_time);
2429                                 position = MAX(position, position_running_time);
2430                         }
2431
2432                         if (position != 0) {
2433                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2434                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2435                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2436
2437                                 player->gapless.start_time[stream_type] += position;
2438                         }
2439                         break;
2440                 }
2441         case GST_EVENT_FLUSH_STOP:
2442                 {
2443                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2444                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2445                         player->gapless.start_time[stream_type] = 0;
2446                         break;
2447                 }
2448         case GST_EVENT_SEGMENT:
2449                 {
2450                         GstSegment segment;
2451                         GstEvent *tmpev;
2452
2453                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2454                         gst_event_copy_segment(event, &segment);
2455
2456                         if (segment.format == GST_FORMAT_TIME) {
2457                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2458                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2459                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2460                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2461                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2462                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2463
2464                                 /* keep the all the segment ev to cover the seeking */
2465                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2466                                 player->gapless.update_segment[stream_type] = TRUE;
2467
2468                                 if (!player->gapless.running)
2469                                         break;
2470
2471                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2472
2473                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2474
2475                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2476                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2477                                 gst_event_unref(event);
2478                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2479                         }
2480                         break;
2481                 }
2482         case GST_EVENT_QOS:
2483                 {
2484                         gdouble proportion = 0.0;
2485                         GstClockTimeDiff diff = 0;
2486                         GstClockTime timestamp = 0;
2487                         gint64 running_time_diff = -1;
2488                         GstQOSType type = 0;
2489                         GstEvent *tmpev = NULL;
2490
2491                         running_time_diff = player->gapless.segment[stream_type].base;
2492
2493                         if (running_time_diff <= 0) /* don't need to adjust */
2494                                 break;
2495
2496                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2497                         gst_event_unref(event);
2498
2499                         if (timestamp < running_time_diff) {
2500                                 LOGW("QOS event from previous group");
2501                                 ret = GST_PAD_PROBE_DROP;
2502                                 break;
2503                         }
2504
2505                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2506                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2507                                                 stream_type, GST_TIME_ARGS(timestamp),
2508                                                 GST_TIME_ARGS(running_time_diff),
2509                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2510
2511                         timestamp -= running_time_diff;
2512
2513                         /* That case is invalid for QoS events */
2514                         if (diff < 0 && -diff > timestamp) {
2515                                 LOGW("QOS event from previous group");
2516                                 ret = GST_PAD_PROBE_DROP;
2517                                 break;
2518                         }
2519
2520                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2521                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2522
2523                         break;
2524                 }
2525         default:
2526                 break;
2527         }
2528
2529 ERROR:
2530         if (caps)
2531                 gst_caps_unref(caps);
2532         return ret;
2533 }
2534
2535 static void
2536 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2537 {
2538         mm_player_t* player = NULL;
2539         GstElement* pipeline = NULL;
2540         GstElement* selector = NULL;
2541         GstElement* fakesink = NULL;
2542         GstCaps* caps = NULL;
2543         GstStructure* str = NULL;
2544         const gchar* name = NULL;
2545         GstPad* sinkpad = NULL;
2546         GstPad* srcpad = NULL;
2547         gboolean first_track = FALSE;
2548
2549         enum MainElementID elemId = MMPLAYER_M_NUM;
2550         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2551
2552         /* check handles */
2553         player = (mm_player_t*)data;
2554
2555         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2556         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2557
2558         //LOGD("pad-added signal handling\n");
2559
2560         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2561
2562         /* get mimetype from caps */
2563         caps = gst_pad_query_caps(pad, NULL);
2564         if (!caps) {
2565                 LOGE("cannot get caps from pad.\n");
2566                 goto ERROR;
2567         }
2568
2569         str = gst_caps_get_structure(caps, 0);
2570         if (!str) {
2571                 LOGE("cannot get structure from caps.\n");
2572                 goto ERROR;
2573         }
2574
2575         name = gst_structure_get_name(str);
2576         if (!name) {
2577                 LOGE("cannot get mimetype from structure.\n");
2578                 goto ERROR;
2579         }
2580
2581         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2582         //LOGD("detected mimetype : %s\n", name);
2583
2584         if (strstr(name, "video")) {
2585                 gint stype = 0;
2586
2587                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2588                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2589
2590                 /* don't make video because of not required, and not support multiple track */
2591                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2592                         LOGD("no video sink by null surface");
2593
2594                         gchar *caps_str = gst_caps_to_string(caps);
2595                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2596                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2597                                 player->set_mode.video_zc = TRUE;
2598
2599                         MMPLAYER_FREEIF(caps_str);
2600
2601                         if (player->v_stream_caps) {
2602                                 gst_caps_unref(player->v_stream_caps);
2603                                 player->v_stream_caps = NULL;
2604                         }
2605
2606                         LOGD("create fakesink instead of videobin");
2607
2608                         /* fake sink */
2609                         fakesink = gst_element_factory_make("fakesink", NULL);
2610                         if (fakesink == NULL) {
2611                                 LOGE("ERROR : fakesink create error\n");
2612                                 goto ERROR;
2613                         }
2614
2615                         if (player->ini.set_dump_element_flag)
2616                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2617
2618                         player->video_fakesink = fakesink;
2619
2620                         /* store it as it's sink element */
2621                         __mmplayer_add_sink(player, player->video_fakesink);
2622
2623                         gst_bin_add(GST_BIN(pipeline), fakesink);
2624
2625                         // link
2626                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2627
2628                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2629                                 LOGW("failed to link fakesink\n");
2630                                 gst_object_unref(GST_OBJECT(fakesink));
2631                                 goto ERROR;
2632                         }
2633
2634                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2635                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2636                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2637                         }
2638
2639                         if (player->set_mode.media_packet_video_stream) {
2640                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2641
2642                                 MMPLAYER_SIGNAL_CONNECT(player,
2643                                                                                 G_OBJECT(fakesink),
2644                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2645                                                                                 "handoff",
2646                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2647                                                                                 (gpointer)player);
2648
2649                                 MMPLAYER_SIGNAL_CONNECT(player,
2650                                                                                 G_OBJECT(fakesink),
2651                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2652                                                                                 "preroll-handoff",
2653                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2654                                                                                 (gpointer)player);
2655                         }
2656
2657                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2658                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2659                         goto DONE;
2660                 }
2661
2662                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2663                         __mmplayer_gst_decode_callback(elem, pad, player);
2664                         goto DONE;
2665                 }
2666
2667                 LOGD("video selector \n");
2668                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2669                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2670         } else {
2671                 if (strstr(name, "audio")) {
2672                         gint samplerate = 0;
2673                         gint channels = 0;
2674
2675                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2676                                 __mmplayer_gst_decode_callback(elem, pad, player);
2677                                 goto DONE;
2678                         }
2679
2680                         LOGD("audio selector \n");
2681                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2682                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2683
2684                         gst_structure_get_int(str, "rate", &samplerate);
2685                         gst_structure_get_int(str, "channels", &channels);
2686
2687                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2688                                 /* fake sink */
2689                                 fakesink = gst_element_factory_make("fakesink", NULL);
2690                                 if (fakesink == NULL) {
2691                                         LOGE("ERROR : fakesink create error\n");
2692                                         goto ERROR;
2693                                 }
2694
2695                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2696
2697                                 /* link */
2698                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2699
2700                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2701                                         LOGW("failed to link fakesink\n");
2702                                         gst_object_unref(GST_OBJECT(fakesink));
2703                                         goto ERROR;
2704                                 }
2705
2706                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2707                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2708
2709                                 goto DONE;
2710                         }
2711                 } else if (strstr(name, "text")) {
2712                         LOGD("text selector \n");
2713                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2714                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2715                 } else {
2716                         LOGE("wrong elem id \n");
2717                         goto ERROR;
2718                 }
2719         }
2720
2721         selector = player->pipeline->mainbin[elemId].gst;
2722         if (selector == NULL) {
2723                 selector = gst_element_factory_make("input-selector", NULL);
2724                 LOGD("Creating input-selector\n");
2725                 if (selector == NULL) {
2726                         LOGE("ERROR : input-selector create error\n");
2727                         goto ERROR;
2728                 }
2729                 g_object_set(selector, "sync-streams", TRUE, NULL);
2730
2731                 player->pipeline->mainbin[elemId].id = elemId;
2732                 player->pipeline->mainbin[elemId].gst = selector;
2733
2734                 first_track = TRUE;
2735                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2736
2737                 srcpad = gst_element_get_static_pad(selector, "src");
2738
2739                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2740                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2741                         __mmplayer_gst_selector_blocked, NULL, NULL);
2742                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2743                         __mmplayer_gst_selector_event_probe, player, NULL);
2744
2745                 gst_element_set_state(selector, GST_STATE_PAUSED);
2746                 gst_bin_add(GST_BIN(pipeline), selector);
2747         } else
2748                 LOGD("input-selector is already created.\n");
2749
2750         // link
2751         LOGD("Calling request pad with selector %p \n", selector);
2752         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2753
2754         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2755
2756         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2757                 LOGW("failed to link selector\n");
2758                 gst_object_unref(GST_OBJECT(selector));
2759                 goto ERROR;
2760         }
2761
2762         if (first_track) {
2763                 LOGD("this is first track --> active track \n");
2764                 g_object_set(selector, "active-pad", sinkpad, NULL);
2765         }
2766
2767         _mmplayer_track_update_info(player, stream_type, sinkpad);
2768
2769
2770 DONE:
2771 ERROR:
2772
2773         if (caps)
2774                 gst_caps_unref(caps);
2775
2776         if (sinkpad) {
2777                 gst_object_unref(GST_OBJECT(sinkpad));
2778                 sinkpad = NULL;
2779         }
2780
2781         if (srcpad) {
2782                 gst_object_unref(GST_OBJECT(srcpad));
2783                 srcpad = NULL;
2784         }
2785
2786         return;
2787 }
2788
2789 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2790 {
2791         GstPad* srcpad = NULL;
2792         MMHandleType attrs = 0;
2793         gint active_index = 0;
2794
2795         // [link] input-selector :: textbin
2796         srcpad = gst_element_get_static_pad(text_selector, "src");
2797         if (!srcpad) {
2798                 LOGE("failed to get srcpad from selector\n");
2799                 return;
2800         }
2801
2802         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2803
2804         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2805         if ((active_index != DEFAULT_TRACK) &&
2806                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2807                 LOGW("failed to change text track\n");
2808                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2809         }
2810
2811         player->no_more_pad = TRUE;
2812         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2813
2814         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2815         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2816                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2817                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2818         }
2819
2820         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2821
2822         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2823                 player->has_closed_caption = TRUE;
2824
2825         attrs = MMPLAYER_GET_ATTRS(player);
2826         if (attrs) {
2827                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2828                 if (mmf_attrs_commit(attrs))
2829                         LOGE("failed to commit.\n");
2830         } else
2831                 LOGE("cannot get content attribute");
2832
2833         if (srcpad) {
2834                 gst_object_unref(GST_OBJECT(srcpad));
2835                 srcpad = NULL;
2836         }
2837 }
2838
2839 static void
2840 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2841 {
2842         mm_player_t* player = (mm_player_t*)data;
2843         GstElement* selector = NULL;
2844         GstElement* queue = NULL;
2845
2846         GstPad* srcpad = NULL;
2847         GstPad* sinkpad = NULL;
2848         GstCaps* caps = NULL;
2849         gchar* caps_str = NULL;
2850
2851         MMPLAYER_FENTER();
2852         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2853
2854         caps = gst_pad_get_current_caps(pad);
2855         caps_str = gst_caps_to_string(caps);
2856         LOGD("deinterleave new caps : %s\n", caps_str);
2857         MMPLAYER_FREEIF(caps_str);
2858         gst_caps_unref(caps);
2859
2860         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2861                 LOGE("ERROR : queue create error\n");
2862                 goto ERROR;
2863         }
2864
2865         g_object_set(G_OBJECT(queue),
2866                                 "max-size-buffers", 10,
2867                                 "max-size-bytes", 0,
2868                                 "max-size-time", (guint64)0,
2869                                 NULL);
2870
2871         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2872
2873         if (!selector) {
2874                 LOGE("there is no audio channel selector.\n");
2875                 goto ERROR;
2876         }
2877
2878         srcpad = gst_element_get_static_pad(queue, "src");
2879         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2880
2881         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2882
2883         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2884                 LOGW("failed to link deinterleave - selector\n");
2885                 goto ERROR;
2886         }
2887
2888         gst_element_set_state(queue, GST_STATE_PAUSED);
2889         player->audio_mode.total_track_num++;
2890
2891 ERROR:
2892
2893         if (srcpad) {
2894                 gst_object_unref(GST_OBJECT(srcpad));
2895                 srcpad = NULL;
2896         }
2897
2898         if (sinkpad) {
2899                 gst_object_unref(GST_OBJECT(sinkpad));
2900                 sinkpad = NULL;
2901         }
2902
2903         MMPLAYER_FLEAVE();
2904         return;
2905 }
2906
2907 static void
2908 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2909 {
2910         mm_player_t* player = NULL;
2911         GstElement* selector = NULL;
2912         GstPad* sinkpad = NULL;
2913         gint active_index = 0;
2914         gchar* change_pad_name = NULL;
2915         GstCaps* caps = NULL;   // no need to unref
2916         gint default_audio_ch = 0;
2917
2918         MMPLAYER_FENTER();
2919         player = (mm_player_t*) data;
2920
2921         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2922
2923         if (!selector) {
2924                 LOGE("there is no audio channel selector.\n");
2925                 goto ERROR;
2926         }
2927
2928         active_index = player->audio_mode.active_pad_index;
2929
2930         if (active_index != default_audio_ch) {
2931                 gint audio_ch = default_audio_ch;
2932
2933                 /*To get the new pad from the selector*/
2934                 change_pad_name = g_strdup_printf("sink%d", active_index);
2935                 if (change_pad_name != NULL) {
2936                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2937                         if (sinkpad != NULL) {
2938                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2939                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2940
2941                                 audio_ch = active_index;
2942
2943                                 caps = gst_pad_get_current_caps(sinkpad);
2944                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2945
2946                                 __mmplayer_set_audio_attrs(player, caps);
2947                                 gst_caps_unref(caps);
2948                         }
2949                         MMPLAYER_FREEIF(change_pad_name);
2950                 }
2951
2952                 player->audio_mode.active_pad_index = audio_ch;
2953                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2954         }
2955
2956 ERROR:
2957
2958         if (sinkpad)
2959                 gst_object_unref(sinkpad);
2960
2961         MMPLAYER_FLEAVE();
2962         return;
2963 }
2964
2965 static void
2966 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2967 {
2968         mm_player_t* player = NULL;
2969         MMPlayerGstElement *mainbin = NULL;
2970
2971         GstElement* tee = NULL;
2972         GstElement* stereo_queue = NULL;
2973         GstElement* mono_queue = NULL;
2974         GstElement* conv = NULL;
2975         GstElement* filter = NULL;
2976         GstElement* deinterleave = NULL;
2977         GstElement* selector = NULL;
2978
2979         GstPad* srcpad = NULL;
2980         GstPad* selector_srcpad = NULL;
2981         GstPad* sinkpad = NULL;
2982         GstCaps* caps = NULL;
2983         gulong block_id = 0;
2984
2985         MMPLAYER_FENTER();
2986
2987         /* check handles */
2988         player = (mm_player_t*) data;
2989
2990         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2991         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2992
2993         mainbin = player->pipeline->mainbin;
2994
2995         /* tee */
2996         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2997                 LOGE("ERROR : tee create error\n");
2998                 goto ERROR;
2999         }
3000
3001         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3002         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3003
3004         gst_element_set_state(tee, GST_STATE_PAUSED);
3005
3006         /* queue */
3007         srcpad = gst_element_get_request_pad(tee, "src_%u");
3008         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3009                 LOGE("ERROR : stereo queue create error\n");
3010                 goto ERROR;
3011         }
3012
3013         g_object_set(G_OBJECT(stereo_queue),
3014                                 "max-size-buffers", 10,
3015                                 "max-size-bytes", 0,
3016                                 "max-size-time", (guint64)0,
3017                                 NULL);
3018
3019         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3020         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3021
3022         if (srcpad) {
3023                 gst_object_unref(GST_OBJECT(srcpad));
3024                 srcpad = NULL;
3025         }
3026
3027         srcpad = gst_element_get_request_pad(tee, "src_%u");
3028
3029         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3030                 LOGE("ERROR : mono queue create error\n");
3031                 goto ERROR;
3032         }
3033
3034         g_object_set(G_OBJECT(mono_queue),
3035                                 "max-size-buffers", 10,
3036                                 "max-size-bytes", 0,
3037                                 "max-size-time", (guint64)0,
3038                                 NULL);
3039
3040         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3041         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3042
3043         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3044         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3045
3046         /* audioconvert */
3047         srcpad = gst_element_get_static_pad(mono_queue, "src");
3048         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3049                 LOGE("ERROR : audioconvert create error\n");
3050                 goto ERROR;
3051         }
3052
3053         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3054         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3055
3056         /* caps filter */
3057         if (srcpad) {
3058                 gst_object_unref(GST_OBJECT(srcpad));
3059                 srcpad = NULL;
3060         }
3061         srcpad = gst_element_get_static_pad(conv, "src");
3062
3063         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3064                 LOGE("ERROR : capsfilter create error\n");
3065                 goto ERROR;
3066         }
3067
3068         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3069         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3070
3071         caps = gst_caps_from_string("audio/x-raw-int, "
3072                                 "width = (int) 16, "
3073                                 "depth = (int) 16, "
3074                                 "channels = (int) 2");
3075
3076         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3077         gst_caps_unref(caps);
3078
3079         gst_element_set_state(conv, GST_STATE_PAUSED);
3080         gst_element_set_state(filter, GST_STATE_PAUSED);
3081
3082         /* deinterleave */
3083         if (srcpad) {
3084                 gst_object_unref(GST_OBJECT(srcpad));
3085                 srcpad = NULL;
3086         }
3087         srcpad = gst_element_get_static_pad(filter, "src");
3088
3089         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3090                 LOGE("ERROR : deinterleave create error\n");
3091                 goto ERROR;
3092         }
3093
3094         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3095
3096         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3097                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3098
3099         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3100                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3101
3102         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3103         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3104
3105         /* selector */
3106         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3107         if (selector == NULL) {
3108                 LOGE("ERROR : audio-selector create error\n");
3109                 goto ERROR;
3110         }
3111
3112         g_object_set(selector, "sync-streams", TRUE, NULL);
3113         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3114
3115         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3116         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3117
3118         selector_srcpad = gst_element_get_static_pad(selector, "src");
3119
3120         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3121         block_id =
3122                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3123                         __mmplayer_gst_selector_blocked, NULL, NULL);
3124
3125         if (srcpad) {
3126                 gst_object_unref(GST_OBJECT(srcpad));
3127                 srcpad = NULL;
3128         }
3129
3130         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3131         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3132
3133         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3134                 LOGW("failed to link queue_stereo - selector\n");
3135                 goto ERROR;
3136         }
3137
3138         player->audio_mode.total_track_num++;
3139
3140         g_object_set(selector, "active-pad", sinkpad, NULL);
3141         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3142         gst_element_set_state(selector, GST_STATE_PAUSED);
3143
3144         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3145
3146 ERROR:
3147
3148         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3149         if (block_id != 0) {
3150                 gst_pad_remove_probe(selector_srcpad, block_id);
3151                 block_id = 0;
3152         }
3153
3154         if (sinkpad) {
3155                 gst_object_unref(GST_OBJECT(sinkpad));
3156                 sinkpad = NULL;
3157         }
3158
3159         if (srcpad) {
3160                 gst_object_unref(GST_OBJECT(srcpad));
3161                 srcpad = NULL;
3162         }
3163
3164         if (selector_srcpad) {
3165                 gst_object_unref(GST_OBJECT(selector_srcpad));
3166                 selector_srcpad = NULL;
3167         }
3168
3169         MMPLAYER_FLEAVE();
3170         return;
3171 }
3172
3173 static void
3174 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3175 {
3176         mm_player_t* player = NULL;
3177         GstPad* srcpad = NULL;
3178         GstElement* video_selector = NULL;
3179         GstElement* audio_selector = NULL;
3180         GstElement* text_selector = NULL;
3181         MMHandleType attrs = 0;
3182         gint active_index = 0;
3183         gint64 dur_bytes = 0L;
3184
3185         player = (mm_player_t*) data;
3186
3187         LOGD("no-more-pad signal handling\n");
3188
3189         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3190                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3191                 LOGW("no need to go more");
3192
3193                 if (player->gapless.reconfigure) {
3194                         player->gapless.reconfigure = FALSE;
3195                         MMPLAYER_PLAYBACK_UNLOCK(player);
3196                 }
3197
3198                 return;
3199         }
3200
3201         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3202                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3203                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3204                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3205                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3206
3207                 if (NULL == player->streamer) {
3208                         LOGW("invalid state for buffering");
3209                         goto ERROR;
3210                 }
3211
3212                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3213                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3214
3215                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3216                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3217
3218                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3219
3220                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3221                         LOGE("fail to get duration.\n");
3222
3223                 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3224                  * use file information was already set on Q2 when it was created. */
3225                 __mm_player_streaming_set_queue2(player->streamer,
3226                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3227                                                 TRUE,                               /* use_buffering */
3228                                                 buffer_bytes,
3229                                                 init_buffering_time,
3230                                                 1.0,                                /* low percent */
3231                                                 player->ini.http_buffering_limit,   /* high percent */
3232                                                 MUXED_BUFFER_TYPE_MAX,              /* use previous buffer type setting */
3233                                                 NULL,
3234                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3235         }
3236
3237         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3238         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3239         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3240         if (video_selector) {
3241                 // [link] input-selector :: videobin
3242                 srcpad = gst_element_get_static_pad(video_selector, "src");
3243                 if (!srcpad) {
3244                         LOGE("failed to get srcpad from video selector\n");
3245                         goto ERROR;
3246                 }
3247
3248                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3249                 if (!text_selector && !audio_selector)
3250                         player->no_more_pad = TRUE;
3251
3252                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3253
3254                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3256                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3257                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3258                 }
3259         }
3260
3261         if (audio_selector) {
3262                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3263                 if ((active_index != DEFAULT_TRACK) &&
3264                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3265                         LOGW("failed to change audio track\n");
3266                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3267                 }
3268
3269                 // [link] input-selector :: audiobin
3270                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3271                 if (!srcpad) {
3272                         LOGE("failed to get srcpad from selector\n");
3273                         goto ERROR;
3274                 }
3275
3276                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3277                 if (!text_selector)
3278                         player->no_more_pad = TRUE;
3279
3280                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3281                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3282                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3283                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3284                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3285                         }
3286
3287                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3288                 } else {
3289                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3290
3291                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3292                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3293                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3294                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3295                         }
3296                 }
3297
3298                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3299
3300                 attrs = MMPLAYER_GET_ATTRS(player);
3301                 if (attrs) {
3302                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3303                         if (mmf_attrs_commit(attrs))
3304                                 LOGE("failed to commit.\n");
3305                 } else
3306                         LOGE("cannot get content attribute");
3307         } else {
3308                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3309                         LOGD("There is no audio track : remove audiobin");
3310
3311                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3312                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3313
3314                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3315                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3316                 }
3317
3318                 if (player->num_dynamic_pad == 0)
3319                         __mmplayer_pipeline_complete(NULL, player);
3320         }
3321
3322         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3323                 if (text_selector)
3324                         __mmplayer_handle_text_decode_path(player, text_selector);
3325         }
3326
3327         MMPLAYER_FLEAVE();
3328
3329 ERROR:
3330         if (srcpad) {
3331                 gst_object_unref(GST_OBJECT(srcpad));
3332                 srcpad = NULL;
3333         }
3334
3335         if (player->gapless.reconfigure) {
3336                 player->gapless.reconfigure = FALSE;
3337                 MMPLAYER_PLAYBACK_UNLOCK(player);
3338         }
3339 }
3340
3341 static void
3342 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3343 {
3344         mm_player_t* player = NULL;
3345         MMHandleType attrs = 0;
3346         GstElement* pipeline = NULL;
3347         GstCaps* caps = NULL;
3348         gchar* caps_str = NULL;
3349         GstStructure* str = NULL;
3350         const gchar* name = NULL;
3351         GstPad* sinkpad = NULL;
3352         GstElement* sinkbin = NULL;
3353         gboolean reusing = FALSE;
3354         GstElement *text_selector = NULL;
3355
3356         /* check handles */
3357         player = (mm_player_t*) data;
3358
3359         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3360         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3361
3362         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3363
3364         attrs = MMPLAYER_GET_ATTRS(player);
3365         if (!attrs) {
3366                 LOGE("cannot get content attribute\n");
3367                 goto ERROR;
3368         }
3369
3370         /* get mimetype from caps */
3371         caps = gst_pad_query_caps(pad, NULL);
3372         if (!caps) {
3373                 LOGE("cannot get caps from pad.\n");
3374                 goto ERROR;
3375         }
3376         caps_str = gst_caps_to_string(caps);
3377
3378         str = gst_caps_get_structure(caps, 0);
3379         if (!str) {
3380                 LOGE("cannot get structure from caps.\n");
3381                 goto ERROR;
3382         }
3383
3384         name = gst_structure_get_name(str);
3385         if (!name) {
3386                 LOGE("cannot get mimetype from structure.\n");
3387                 goto ERROR;
3388         }
3389
3390         //LOGD("detected mimetype : %s\n", name);
3391
3392         if (strstr(name, "audio")) {
3393                 if (player->pipeline->audiobin == NULL) {
3394                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3395                                 LOGE("failed to create audiobin. continuing without audio\n");
3396                                 goto ERROR;
3397                         }
3398
3399                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3400                         LOGD("creating audiosink bin success\n");
3401                 } else {
3402                         reusing = TRUE;
3403                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3404                         LOGD("reusing audiobin\n");
3405                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3406                 }
3407
3408                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3409                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3410
3411                 player->audiosink_linked  = 1;
3412
3413                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3414                 if (!sinkpad) {
3415                         LOGE("failed to get pad from sinkbin\n");
3416                         goto ERROR;
3417                 }
3418         } else if (strstr(name, "video")) {
3419                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3420                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3421                         player->set_mode.video_zc = TRUE;
3422
3423                 if (player->pipeline->videobin == NULL) {
3424                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3425                         /* get video surface type */
3426                         int surface_type = 0;
3427                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3428                         LOGD("display_surface_type(%d)\n", surface_type);
3429
3430                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3431                                 LOGD("not make videobin because it dose not want\n");
3432                                 goto ERROR;
3433                         }
3434
3435                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3436                                 /* mark video overlay for acquire */
3437                                 if (player->video_overlay_resource == NULL) {
3438                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3439                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3440                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3441                                                         &player->video_overlay_resource)
3442                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3443                                                 LOGE("could not mark video_overlay resource for acquire\n");
3444                                                 goto ERROR;
3445                                         }
3446                                 }
3447                         }
3448
3449                         player->interrupted_by_resource = FALSE;
3450                         /* acquire resources for video overlay */
3451                         if (mm_resource_manager_commit(player->resource_manager) !=
3452                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3453                                 LOGE("could not acquire resources for video playing\n");
3454                                 goto ERROR;
3455                         }
3456
3457                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3458                                 LOGE("failed to create videobin. continuing without video\n");
3459                                 goto ERROR;
3460                         }
3461
3462                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3463                         LOGD("creating videosink bin success\n");
3464                 } else {
3465                         reusing = TRUE;
3466                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3467                         LOGD("re-using videobin\n");
3468                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3469                 }
3470
3471                 player->videosink_linked  = 1;
3472
3473                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3474                 if (!sinkpad) {
3475                         LOGE("failed to get pad from sinkbin\n");
3476                         goto ERROR;
3477                 }
3478         } else if (strstr(name, "text")) {
3479                 if (player->pipeline->textbin == NULL) {
3480                         MMPlayerGstElement* mainbin = NULL;
3481
3482                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3483                                 LOGE("failed to create text sink bin. continuing without text\n");
3484                                 goto ERROR;
3485                         }
3486
3487                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3488                         LOGD("creating textsink bin success\n");
3489
3490                         /* FIXIT : track number shouldn't be hardcoded */
3491                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3492
3493                         player->textsink_linked  = 1;
3494                         LOGI("player->textsink_linked set to 1\n");
3495
3496                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3497                         if (!sinkpad) {
3498                                 LOGE("failed to get pad from sinkbin\n");
3499                                 goto ERROR;
3500                         }
3501
3502                         mainbin = player->pipeline->mainbin;
3503
3504                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3505                                 /* input selector */
3506                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3507                                 if (!text_selector) {
3508                                         LOGE("failed to create subtitle input selector element\n");
3509                                         goto ERROR;
3510                                 }
3511                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3512
3513                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3514                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3515
3516                                 /* warm up */
3517                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3518                                         LOGE("failed to set state(READY) to sinkbin\n");
3519                                         goto ERROR;
3520                                 }
3521
3522                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3523                                         LOGW("failed to add subtitle input selector\n");
3524                                         goto ERROR;
3525                                 }
3526
3527                                 LOGD("created element input-selector");
3528
3529                         } else {
3530                                 LOGD("already having subtitle input selector");
3531                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3532                         }
3533                 } else {
3534                         if (!player->textsink_linked) {
3535                                 LOGD("re-using textbin\n");
3536
3537                                 reusing = TRUE;
3538                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3539
3540                                 player->textsink_linked  = 1;
3541                                 LOGI("player->textsink_linked set to 1\n");
3542                         } else
3543                                 LOGD("ignoring internal subtutle since external subtitle is available");
3544                 }
3545         } else {
3546                 LOGW("unknown type of elementary stream!ignoring it...\n");
3547                 goto ERROR;
3548         }
3549
3550         if (sinkbin) {
3551                 if (!reusing) {
3552                         /* warm up */
3553                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3554                                 LOGE("failed to set state(READY) to sinkbin\n");
3555                                 goto ERROR;
3556                         }
3557
3558                         /* Added for multi audio support to avoid adding audio bin again*/
3559                         /* add */
3560                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3561                                 LOGE("failed to add sinkbin to pipeline\n");
3562                                 goto ERROR;
3563                         }
3564                 }
3565
3566                 /* link */
3567                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3568                         LOGE("failed to get pad from sinkbin\n");
3569                         goto ERROR;
3570                 }
3571
3572                 if (!reusing) {
3573                         /* run */
3574                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3575                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3576                                 goto ERROR;
3577                         }
3578
3579                         if (text_selector) {
3580                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3581                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3582                                         goto ERROR;
3583                                 }
3584                         }
3585                 }
3586
3587                 gst_object_unref(sinkpad);
3588                 sinkpad = NULL;
3589         }
3590
3591         LOGD("[handle: %p] linking sink bin success", player);
3592
3593         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3594          * streaming task. if the task blocked, then buffer will not flow to the next element
3595          *(autoplugging element). so this is special hack for streaming. please try to remove it
3596          */
3597         /* dec stream count. we can remove fakesink if it's zero */
3598         if (player->num_dynamic_pad)
3599                 player->num_dynamic_pad--;
3600
3601         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3602
3603         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3604                 __mmplayer_pipeline_complete(NULL, player);
3605
3606 ERROR:
3607
3608         MMPLAYER_FREEIF(caps_str);
3609
3610         if (caps)
3611                 gst_caps_unref(caps);
3612
3613         if (sinkpad)
3614                 gst_object_unref(GST_OBJECT(sinkpad));
3615
3616         /* flusing out new attributes */
3617         if (mmf_attrs_commit(attrs))
3618                 LOGE("failed to comit attributes\n");
3619
3620         return;
3621 }
3622
3623 static gboolean
3624 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3625 {
3626         int pro_value = 0; // in the case of expection, default will be returned.
3627         int dest_angle = rotation_angle;
3628         int rotation_type = -1;
3629
3630         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3631         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3632         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3633
3634         if (rotation_angle >= 360)
3635                 dest_angle = rotation_angle - 360;
3636
3637         /* chech if supported or not */
3638         if (dest_angle % 90) {
3639                 LOGD("not supported rotation angle = %d", rotation_angle);
3640                 return FALSE;
3641         }
3642
3643         /*
3644           * tizenwlsink (A)
3645           * custom_convert - none (B)
3646           * videoflip - none (C)
3647           */
3648         if (player->set_mode.video_zc) {
3649                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3650                         rotation_type = ROTATION_USING_CUSTOM;
3651                 else // A
3652                         rotation_type = ROTATION_USING_SINK;
3653         } else {
3654                 int surface_type = 0;
3655                 rotation_type = ROTATION_USING_FLIP;
3656
3657                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3658                 LOGD("check display surface type attribute: %d", surface_type);
3659
3660                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3661                         rotation_type = ROTATION_USING_SINK;
3662                 else
3663                         rotation_type = ROTATION_USING_FLIP; //C
3664
3665                 LOGD("using %d type for rotation", rotation_type);
3666         }
3667
3668         /* get property value for setting */
3669         switch (rotation_type) {
3670         case ROTATION_USING_SINK: // tizenwlsink
3671                 {
3672                         switch (dest_angle) {
3673                         case 0:
3674                                 break;
3675                         case 90:
3676                                 pro_value = 3; // clockwise 90
3677                                 break;
3678                         case 180:
3679                                 pro_value = 2;
3680                                 break;
3681                         case 270:
3682                                 pro_value = 1; // counter-clockwise 90
3683                                 break;
3684                         }
3685                 }
3686                 break;
3687         case ROTATION_USING_CUSTOM:
3688                 {
3689                         gchar *ename = NULL;
3690                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3691
3692                         if (g_strrstr(ename, "fimcconvert")) {
3693                                 switch (dest_angle) {
3694                                 case 0:
3695                                         break;
3696                                 case 90:
3697                                         pro_value = 90; // clockwise 90
3698                                         break;
3699                                 case 180:
3700                                         pro_value = 180;
3701                                         break;
3702                                 case 270:
3703                                         pro_value = 270; // counter-clockwise 90
3704                                         break;
3705                                 }
3706                         }
3707                 }
3708                 break;
3709         case ROTATION_USING_FLIP: // videoflip
3710                 {
3711                                 switch (dest_angle) {
3712                                 case 0:
3713                                         break;
3714                                 case 90:
3715                                         pro_value = 1; // clockwise 90
3716                                         break;
3717                                 case 180:
3718                                         pro_value = 2;
3719                                         break;
3720                                 case 270:
3721                                         pro_value = 3; // counter-clockwise 90
3722                                         break;
3723                                 }
3724                 }
3725                 break;
3726         }
3727
3728         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3729
3730         *value = pro_value;
3731
3732         return TRUE;
3733 }
3734
3735 int
3736 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3737 {
3738         /* check video sinkbin is created */
3739         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3740                 player->pipeline &&
3741                 player->pipeline->videobin &&
3742                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3743                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3744                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3745
3746         return MM_ERROR_NONE;
3747 }
3748
3749 void
3750 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3751 {
3752         int rotation_value = 0;
3753         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3754         int user_angle = 0;
3755         MMPLAYER_FENTER();
3756
3757         /* check video sinkbin is created */
3758         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3759                 return;
3760
3761         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3762
3763         /* get rotation value to set */
3764         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3765         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3766         LOGD("set video param : rotate %d", rotation_value);
3767 }
3768
3769 void
3770 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3771 {
3772         MMHandleType attrs = 0;
3773         int visible = 0;
3774         MMPLAYER_FENTER();
3775
3776         /* check video sinkbin is created */
3777         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3778                 return;
3779
3780         attrs = MMPLAYER_GET_ATTRS(player);
3781         MMPLAYER_RETURN_IF_FAIL(attrs);
3782
3783         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3784         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3785         LOGD("set video param : visible %d", visible);
3786 }
3787
3788 void
3789 __mmplayer_video_param_set_display_method(mm_player_t* player)
3790 {
3791         MMHandleType attrs = 0;
3792         int display_method = 0;
3793         MMPLAYER_FENTER();
3794
3795         /* check video sinkbin is created */
3796         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3797                 return;
3798
3799         attrs = MMPLAYER_GET_ATTRS(player);
3800         MMPLAYER_RETURN_IF_FAIL(attrs);
3801
3802         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3803         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3804         LOGD("set video param : method %d", display_method);
3805 }
3806
3807 void
3808 __mmplayer_video_param_set_roi_area(mm_player_t* player)
3809 {
3810         MMHandleType attrs = 0;
3811         void *handle = NULL;
3812         /*set wl_display*/
3813         int win_roi_x = 0;
3814         int win_roi_y = 0;
3815         int win_roi_width = 0;
3816         int win_roi_height = 0;
3817         MMPLAYER_FENTER();
3818
3819         /* check video sinkbin is created */
3820         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3821                 return;
3822
3823         attrs = MMPLAYER_GET_ATTRS(player);
3824         MMPLAYER_RETURN_IF_FAIL(attrs);
3825
3826         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3827
3828         if (handle) {
3829                 /* It should be set after setting window */
3830                 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
3831                 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
3832                 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
3833                 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
3834
3835                 /* After setting window handle, set display roi area */
3836                 gst_video_overlay_set_display_roi_area(
3837                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3838                          win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3839                 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
3840                         win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3841
3842         }
3843 }
3844 void
3845 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3846 {
3847         MMHandleType attrs = 0;
3848         void *handle = NULL;
3849
3850         /* check video sinkbin is created */
3851         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3852                 return;
3853
3854         attrs = MMPLAYER_GET_ATTRS(player);
3855         MMPLAYER_RETURN_IF_FAIL(attrs);
3856
3857         /* common case if using overlay surface */
3858         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3859
3860         if (handle) {
3861                 /* default is using wl_surface_id */
3862                 unsigned int wl_surface_id      = 0;
3863                 wl_surface_id = *(int*)handle;
3864                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3865                 gst_video_overlay_set_wl_window_wl_surface_id(
3866                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3867                                 *(int*)handle);
3868         } else
3869                 /* FIXIT : is it error case? */
3870                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3871 }
3872
3873
3874 int
3875 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3876 {
3877         bool update_all_param = FALSE;
3878         MMPLAYER_FENTER();
3879
3880         /* check video sinkbin is created */
3881         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3882                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3883
3884         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3885                 LOGE("can not find tizenwlsink");
3886                 return MM_ERROR_PLAYER_INTERNAL;
3887         }
3888
3889         LOGD("param_name : %s", param_name);
3890         if (!g_strcmp0(param_name, "update_all_param"))
3891                 update_all_param = TRUE;
3892
3893         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3894                 __mmplayer_video_param_set_display_overlay(player);
3895         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3896                 __mmplayer_video_param_set_display_method(player);
3897         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3898                 __mmplayer_video_param_set_display_visible(player);
3899         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3900                 __mmplayer_video_param_set_display_rotation(player);
3901         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
3902                 __mmplayer_video_param_set_roi_area(player);
3903
3904         return MM_ERROR_NONE;
3905 }
3906
3907 int
3908 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3909 {
3910         MMHandleType attrs = 0;
3911         int surface_type = 0;
3912         int ret = MM_ERROR_NONE;
3913
3914         MMPLAYER_FENTER();
3915
3916         /* check video sinkbin is created */
3917         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3918                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3919
3920         attrs = MMPLAYER_GET_ATTRS(player);
3921         if (!attrs) {
3922                 LOGE("cannot get content attribute");
3923                 return MM_ERROR_PLAYER_INTERNAL;
3924         }
3925         LOGD("param_name : %s", param_name);
3926
3927         /* update display surface */
3928         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3929         LOGD("check display surface type attribute: %d", surface_type);
3930
3931         /* configuring display */
3932         switch (surface_type) {
3933         case MM_DISPLAY_SURFACE_OVERLAY:
3934                 {
3935                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3936                         if (ret != MM_ERROR_NONE)
3937                                 return ret;
3938                 }
3939                 break;
3940         }
3941
3942         MMPLAYER_FLEAVE();
3943
3944         return MM_ERROR_NONE;
3945 }
3946
3947 int
3948 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3949 {
3950         gboolean disable_overlay = FALSE;
3951         mm_player_t* player = (mm_player_t*) hplayer;
3952         int ret = MM_ERROR_NONE;
3953
3954         MMPLAYER_FENTER();
3955         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3956         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3957                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3958                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3959
3960         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3961                 LOGW("Display control is not supported");
3962                 return MM_ERROR_PLAYER_INTERNAL;
3963         }
3964
3965         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3966
3967         if (audio_only == (bool)disable_overlay) {
3968                 LOGE("It's the same with current setting: (%d)", audio_only);
3969                 return MM_ERROR_NONE;
3970         }
3971
3972         if (audio_only) {
3973                 LOGE("disable overlay");
3974                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3975
3976                 /* release overlay resource */
3977                 if (player->video_overlay_resource != NULL) {
3978                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3979                                         player->video_overlay_resource);
3980                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3981                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3982                                 goto ERROR;
3983                         }
3984                         player->video_overlay_resource = NULL;
3985                 }
3986
3987                 ret = mm_resource_manager_commit(player->resource_manager);
3988                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3990                         goto ERROR;
3991                 }
3992         } else {
3993                 /* mark video overlay for acquire */
3994                 if (player->video_overlay_resource == NULL) {
3995                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3996                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3997                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3998                                         &player->video_overlay_resource);
3999                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4000                                 LOGE("could not prepare for video_overlay resource\n");
4001                                 goto ERROR;
4002                         }
4003                 }
4004
4005                 player->interrupted_by_resource = FALSE;
4006                 /* acquire resources for video overlay */
4007                 ret = mm_resource_manager_commit(player->resource_manager);
4008                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4009                         LOGE("could not acquire resources for video playing\n");
4010                         goto ERROR;
4011                 }
4012
4013                 LOGD("enable overlay");
4014                 __mmplayer_video_param_set_display_overlay(player);
4015                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4016         }
4017
4018 ERROR:
4019         MMPLAYER_FLEAVE();
4020         return MM_ERROR_NONE;
4021 }
4022
4023 int
4024 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4025 {
4026         mm_player_t* player = (mm_player_t*) hplayer;
4027         gboolean disable_overlay = FALSE;
4028
4029         MMPLAYER_FENTER();
4030
4031         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4032         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4033         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4034                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4035                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4036
4037         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4038                 LOGW("Display control is not supported");
4039                 return MM_ERROR_PLAYER_INTERNAL;
4040         }
4041
4042         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4043
4044         *paudio_only = (bool)(disable_overlay);
4045
4046         LOGD("audio_only : %d", *paudio_only);
4047
4048         MMPLAYER_FLEAVE();
4049
4050         return MM_ERROR_NONE;
4051 }
4052
4053 static int
4054 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4055 {
4056         GList* bucket = element_bucket;
4057         MMPlayerGstElement* element = NULL;
4058         MMPlayerGstElement* prv_element = NULL;
4059         gint successful_link_count = 0;
4060
4061         MMPLAYER_FENTER();
4062
4063         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4064
4065         prv_element = (MMPlayerGstElement*)bucket->data;
4066         bucket = bucket->next;
4067
4068         for (; bucket; bucket = bucket->next) {
4069                 element = (MMPlayerGstElement*)bucket->data;
4070
4071                 if (element && element->gst) {
4072                         /* If next element is audio appsrc then make a separate audio pipeline */
4073                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4074                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4075                                 prv_element = element;
4076                                 continue;
4077                         }
4078
4079                         if (prv_element && prv_element->gst) {
4080                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4081                                         LOGD("linking [%s] to [%s] success\n",
4082                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4083                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4084                                         successful_link_count++;
4085                                 } else {
4086                                         LOGD("linking [%s] to [%s] failed\n",
4087                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4088                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4089                                         return -1;
4090                                 }
4091                         }
4092                 }
4093
4094                 prv_element = element;
4095         }
4096
4097         MMPLAYER_FLEAVE();
4098
4099         return successful_link_count;
4100 }
4101
4102 static int
4103 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4104 {
4105         GList* bucket = element_bucket;
4106         MMPlayerGstElement* element = NULL;
4107         int successful_add_count = 0;
4108
4109         MMPLAYER_FENTER();
4110
4111         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4112         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4113
4114         for (; bucket; bucket = bucket->next) {
4115                 element = (MMPlayerGstElement*)bucket->data;
4116
4117                 if (element && element->gst) {
4118                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4119                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4120                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4121                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4122                                 return 0;
4123                         }
4124                         successful_add_count++;
4125                 }
4126         }
4127
4128         MMPLAYER_FLEAVE();
4129
4130         return successful_add_count;
4131 }
4132
4133 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4134 {
4135         mm_player_t* player = (mm_player_t*) data;
4136         GstCaps *caps = NULL;
4137         GstStructure *str = NULL;
4138         const char *name;
4139
4140         MMPLAYER_FENTER();
4141
4142         MMPLAYER_RETURN_IF_FAIL(pad)
4143         MMPLAYER_RETURN_IF_FAIL(unused)
4144         MMPLAYER_RETURN_IF_FAIL(data)
4145
4146         caps = gst_pad_get_current_caps(pad);
4147         if (!caps)
4148                 return;
4149
4150         str = gst_caps_get_structure(caps, 0);
4151         if (!str)
4152                 goto ERROR;
4153
4154         name = gst_structure_get_name(str);
4155         if (!name)
4156                 goto ERROR;
4157
4158         LOGD("name = %s\n", name);
4159
4160         if (strstr(name, "audio")) {
4161                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4162
4163                 if (player->audio_stream_changed_cb) {
4164                         LOGE("call the audio stream changed cb\n");
4165                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4166                 }
4167         } else if (strstr(name, "video")) {
4168                 if ((name = gst_structure_get_string(str, "format")))
4169                         player->set_mode.video_zc = name[0] == 'S';
4170
4171                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4172
4173                 if (player->video_stream_changed_cb) {
4174                         LOGE("call the video stream changed cb\n");
4175                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4176                 }
4177         } else
4178                 goto ERROR;
4179
4180 ERROR:
4181
4182         gst_caps_unref(caps);
4183
4184         MMPLAYER_FLEAVE();
4185
4186         return;
4187 }
4188
4189
4190
4191 /**
4192  * This function is to create audio pipeline for playing.
4193  *
4194  * @param       player          [in]    handle of player
4195  *
4196  * @return      This function returns zero on success.
4197  * @remark
4198  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4199  */
4200 /* macro for code readability. just for sinkbin-creation functions */
4201 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4202 do {\
4203         x_bin[x_id].id = x_id;\
4204         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4205         if (!x_bin[x_id].gst) {\
4206                 LOGE("failed to create %s \n", x_factory);\
4207                 goto ERROR;\
4208         } else {\
4209                 if (x_player->ini.set_dump_element_flag)\
4210                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4211         } \
4212         if (x_add_bucket)\
4213                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4214 } while (0);
4215
4216 static void
4217 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4218 {
4219         GList *l = NULL;
4220
4221         MMPLAYER_FENTER();
4222         MMPLAYER_RETURN_IF_FAIL(player);
4223
4224         if (player->audio_stream_buff_list) {
4225                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4226                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4227                         if (tmp) {
4228                                 if (send_all) {
4229                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4230                                         __mmplayer_audio_stream_send_data(player, tmp);
4231                                 }
4232                                 if (tmp->pcm_data)
4233                                         g_free(tmp->pcm_data);
4234                                 g_free(tmp);
4235                         }
4236                 }
4237                 g_list_free(player->audio_stream_buff_list);
4238                 player->audio_stream_buff_list = NULL;
4239         }
4240
4241         MMPLAYER_FLEAVE();
4242 }
4243
4244 static void
4245 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4246 {
4247         MMPlayerAudioStreamDataType audio_stream = { 0, };
4248
4249         MMPLAYER_FENTER();
4250         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4251
4252         audio_stream.bitrate = a_buffer->bitrate;
4253         audio_stream.channel = a_buffer->channel;
4254         audio_stream.depth = a_buffer->depth;
4255         audio_stream.is_little_endian = a_buffer->is_little_endian;
4256         audio_stream.channel_mask = a_buffer->channel_mask;
4257         audio_stream.data_size = a_buffer->data_size;
4258         audio_stream.data = a_buffer->pcm_data;
4259
4260         /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4261         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4262
4263         MMPLAYER_FLEAVE();
4264 }
4265
4266 static void
4267 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4268 {
4269         mm_player_t* player = (mm_player_t*) data;
4270
4271         gint channel = 0;
4272         gint rate = 0;
4273         gint depth = 0;
4274         gint endianness = 0;
4275         guint64 channel_mask = 0;
4276         void *a_data = NULL;
4277         gint a_size = 0;
4278         mm_player_audio_stream_buff_t *a_buffer = NULL;
4279         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4280         GList *l = NULL;
4281
4282         MMPLAYER_FENTER();
4283         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4284
4285         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4286         a_data = mapinfo.data;
4287         a_size = mapinfo.size;
4288
4289         GstCaps *caps = gst_pad_get_current_caps(pad);
4290         GstStructure *structure = gst_caps_get_structure(caps, 0);
4291
4292         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4293         gst_structure_get_int(structure, "rate", &rate);
4294         gst_structure_get_int(structure, "channels", &channel);
4295         gst_structure_get_int(structure, "depth", &depth);
4296         gst_structure_get_int(structure, "endianness", &endianness);
4297         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4298         gst_caps_unref(GST_CAPS(caps));
4299
4300         /* In case of the sync is false, use buffer list.              *
4301          * The num of buffer list depends on the num of audio channels */
4302         if (player->audio_stream_buff_list) {
4303                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4304                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4305                         if (tmp) {
4306                                 if (channel_mask == tmp->channel_mask) {
4307                                         /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4308                                         if (tmp->data_size + a_size < tmp->buff_size) {
4309                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4310                                                 tmp->data_size += a_size;
4311                                         } else {
4312                                                 /* send data to client */
4313                                                 __mmplayer_audio_stream_send_data(player, tmp);
4314
4315                                                 if (a_size > tmp->buff_size) {
4316                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4317                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4318                                                         if (tmp->pcm_data == NULL) {
4319                                                                 LOGE("failed to realloc data.");
4320                                                                 goto DONE;
4321                                                         }
4322                                                         tmp->buff_size = a_size;
4323                                                 }
4324                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4325                                                 memcpy(tmp->pcm_data, a_data, a_size);
4326                                                 tmp->data_size = a_size;
4327                                         }
4328                                         goto DONE;
4329                                 }
4330                         } else {
4331                                 LOGE("data is empty in list.");
4332                                 goto DONE;
4333                         }
4334                 }
4335         }
4336
4337         /* create new audio stream data */
4338         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4339         if (a_buffer == NULL) {
4340                 LOGE("failed to alloc data.");
4341                 goto DONE;
4342         }
4343         a_buffer->bitrate = rate;
4344         a_buffer->channel = channel;
4345         a_buffer->depth = depth;
4346         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4347         a_buffer->channel_mask = channel_mask;
4348         a_buffer->data_size = a_size;
4349
4350         if (!player->audio_stream_sink_sync) {
4351                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4352                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4353                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4354                 if (a_buffer->pcm_data == NULL) {
4355                         LOGE("failed to alloc data.");
4356                         g_free(a_buffer);
4357                         goto DONE;
4358                 }
4359                 memcpy(a_buffer->pcm_data, a_data, a_size);
4360                 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4361                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4362         } else {
4363                 /* If sync is TRUE, send data directly. */
4364                 a_buffer->pcm_data = a_data;
4365                 __mmplayer_audio_stream_send_data(player, a_buffer);
4366                 g_free(a_buffer);
4367         }
4368
4369 DONE:
4370         gst_buffer_unmap(buffer, &mapinfo);
4371         MMPLAYER_FLEAVE();
4372 }
4373
4374 static void
4375 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4376 {
4377         mm_player_t* player = (mm_player_t*)data;
4378         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4379         GstPad* sinkpad = NULL;
4380         GstElement *queue = NULL, *sink = NULL;
4381
4382         MMPLAYER_FENTER();
4383         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4384
4385         queue = gst_element_factory_make("queue", NULL);
4386         if (queue == NULL) {
4387                 LOGD("fail make queue\n");
4388                 goto ERROR;
4389         }
4390
4391         sink = gst_element_factory_make("fakesink", NULL);
4392         if (sink == NULL) {
4393                 LOGD("fail make fakesink\n");
4394                 goto ERROR;
4395         }
4396
4397         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4398
4399         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4400                 LOGW("failed to link queue & sink\n");
4401                 goto ERROR;
4402         }
4403
4404         sinkpad = gst_element_get_static_pad(queue, "sink");
4405
4406         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4407                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4408                 goto ERROR;
4409         }
4410
4411         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4412
4413         gst_object_unref(sinkpad);
4414         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4415         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4416
4417         gst_element_set_state(sink, GST_STATE_PAUSED);
4418         gst_element_set_state(queue, GST_STATE_PAUSED);
4419
4420         MMPLAYER_SIGNAL_CONNECT(player,
4421                 G_OBJECT(sink),
4422                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4423                 "handoff",
4424                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4425                 (gpointer)player);
4426
4427         MMPLAYER_FLEAVE();
4428         return;
4429
4430 ERROR:
4431         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4432         if (queue) {
4433                 gst_object_unref(GST_OBJECT(queue));
4434                 queue = NULL;
4435         }
4436         if (sink) {
4437                 gst_object_unref(GST_OBJECT(sink));
4438                 sink = NULL;
4439         }
4440         if (sinkpad) {
4441                 gst_object_unref(GST_OBJECT(sinkpad));
4442                 sinkpad = NULL;
4443         }
4444
4445         return;
4446 }
4447
4448 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4449 {
4450         #define MAX_PROPS_LEN 128
4451         gint latency_mode = 0;
4452         gchar *stream_type = NULL;
4453         gchar *latency = NULL;
4454         gint stream_id = 0;
4455         gchar stream_props[MAX_PROPS_LEN] = {0,};
4456         GstStructure *props = NULL;
4457
4458         /* set volume table
4459          * It should be set after player creation through attribute.
4460          * But, it can not be changed during playing.
4461          */
4462         MMPLAYER_FENTER();
4463         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4464         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4465
4466         if (!stream_type) {
4467                 LOGE("stream_type is null.\n");
4468         } else {
4469                 if (player->sound.focus_id)
4470                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4471                                         stream_type, stream_id, player->sound.focus_id);
4472                 else
4473                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4474                                         stream_type, stream_id);
4475                 props = gst_structure_from_string(stream_props, NULL);
4476                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4477                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4478                         stream_type, stream_id, player->sound.focus_id, stream_props);
4479                 gst_structure_free(props);
4480         }
4481
4482         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4483
4484         switch (latency_mode) {
4485         case AUDIO_LATENCY_MODE_LOW:
4486                 latency = g_strndup("low", 3);
4487                 break;
4488         case AUDIO_LATENCY_MODE_MID:
4489                 latency = g_strndup("mid", 3);
4490                 break;
4491         case AUDIO_LATENCY_MODE_HIGH:
4492                 latency = g_strndup("high", 4);
4493                 break;
4494         };
4495
4496         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4497                         "latency", latency,
4498                         NULL);
4499
4500         LOGD("audiosink property - latency=%s \n", latency);
4501
4502         g_free(latency);
4503
4504         MMPLAYER_FLEAVE();
4505 }
4506
4507 static int
4508 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4509 {
4510         MMPlayerGstElement* first_element = NULL;
4511         MMPlayerGstElement* audiobin = NULL;
4512         MMHandleType attrs = 0;
4513         GstPad *pad = NULL;
4514         GstPad *ghostpad = NULL;
4515         GList* element_bucket = NULL;
4516         gboolean link_audio_sink_now = TRUE;
4517         int i = 0;
4518         GstCaps *acaps;
4519
4520         MMPLAYER_FENTER();
4521
4522         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4523
4524         /* alloc handles */
4525         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4526         if (!audiobin) {
4527                 LOGE("failed to allocate memory for audiobin\n");
4528                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4529         }
4530
4531         attrs = MMPLAYER_GET_ATTRS(player);
4532
4533         /* create bin */
4534         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4535         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4536         if (!audiobin[MMPLAYER_A_BIN].gst) {
4537                 LOGE("failed to create audiobin\n");
4538                 goto ERROR;
4539         }
4540
4541         /* take it */
4542         player->pipeline->audiobin = audiobin;
4543
4544         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4545
4546         /* Adding audiotp plugin for reverse trickplay feature */
4547 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4548
4549         /* converter */
4550         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4551
4552         /* replaygain volume */
4553         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4554         if (player->sound.rg_enable)
4555                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4556         else
4557                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4558
4559         /* resampler */
4560         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4561
4562         if (player->set_mode.pcm_extraction) {
4563                 // pcm extraction only and no sound output
4564                 if (player->audio_stream_render_cb_ex) {
4565                         char *caps_str = NULL;
4566                         GstCaps* caps = NULL;
4567                         gchar *format = NULL;
4568
4569                         /* capsfilter */
4570                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4571
4572                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4573
4574                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4575
4576                         caps = gst_caps_new_simple("audio/x-raw",
4577                                         "format", G_TYPE_STRING, format,
4578                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4579                                         "channels", G_TYPE_INT, player->pcm_channel,
4580                                         NULL);
4581                         caps_str = gst_caps_to_string(caps);
4582                         LOGD("new caps : %s\n", caps_str);
4583
4584                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4585
4586                         /* clean */
4587                         gst_caps_unref(caps);
4588                         MMPLAYER_FREEIF(caps_str);
4589
4590                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4591
4592                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4593                         /* raw pad handling signal */
4594                         MMPLAYER_SIGNAL_CONNECT(player,
4595                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4596                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4597                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4598                 } else {
4599                         int dst_samplerate = 0;
4600                         int dst_channels = 0;
4601                         int dst_depth = 0;
4602                         char *caps_str = NULL;
4603                         GstCaps* caps = NULL;
4604
4605                         /* get conf. values */
4606                         mm_attrs_multiple_get(player->attrs,
4607                                                 NULL,
4608                                                 "pcm_extraction_samplerate", &dst_samplerate,
4609                                                 "pcm_extraction_channels", &dst_channels,
4610                                                 "pcm_extraction_depth", &dst_depth,
4611                                                 NULL);
4612
4613                         /* capsfilter */
4614                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4615                         caps = gst_caps_new_simple("audio/x-raw",
4616                                         "rate", G_TYPE_INT, dst_samplerate,
4617                                         "channels", G_TYPE_INT, dst_channels,
4618                                         "depth", G_TYPE_INT, dst_depth,
4619                                         NULL);
4620                         caps_str = gst_caps_to_string(caps);
4621                         LOGD("new caps : %s\n", caps_str);
4622
4623                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4624
4625                         /* clean */
4626                         gst_caps_unref(caps);
4627                         MMPLAYER_FREEIF(caps_str);
4628
4629                         /* fake sink */
4630                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4631
4632                         /* set sync */
4633                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4634                 }
4635         } else {
4636                 // normal playback
4637                 //GstCaps* caps = NULL;
4638                 gint channels = 0;
4639
4640                 /* for logical volume control */
4641                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4642                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4643
4644                 if (player->sound.mute) {
4645                         LOGD("mute enabled\n");
4646                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4647                 }
4648
4649 #if 0
4650                 /*capsfilter */
4651                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4652                 caps = gst_caps_from_string("audio/x-raw-int, "
4653                                         "endianness = (int) LITTLE_ENDIAN, "
4654                                         "signed = (boolean) true, "
4655                                         "width = (int) 16, "
4656                                         "depth = (int) 16");
4657                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4658                 gst_caps_unref(caps);
4659 #endif
4660
4661                 /* check if multi-channels */
4662                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4663                         GstPad *srcpad = NULL;
4664                         GstCaps *caps = NULL;
4665
4666                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4667                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4668                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4669                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4670                                         if (str)
4671                                                 gst_structure_get_int(str, "channels", &channels);
4672                                         gst_caps_unref(caps);
4673                                 }
4674                                 gst_object_unref(srcpad);
4675                         }
4676                 }
4677
4678                 /* audio effect element. if audio effect is enabled */
4679                 if ((strcmp(player->ini.audioeffect_element, ""))
4680                         && (channels <= 2)
4681                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4682                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4683
4684                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4685
4686                         if ((!player->bypass_audio_effect)
4687                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4688                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4689                                         if (!_mmplayer_audio_effect_custom_apply(player))
4690                                                 LOGI("apply audio effect(custom) setting success\n");
4691                                 }
4692                         }
4693
4694                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4695                                 && (player->set_mode.rich_audio))
4696                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4697                 }
4698
4699                 /* create audio sink */
4700                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4701                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4702                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4703
4704                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4705                 if (player->is_360_feature_enabled &&
4706                         player->is_content_spherical &&
4707                         channels == 4 &&
4708                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4709                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4710                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4711
4712                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4713
4714                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4715
4716                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4717                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4718                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4719                         gst_caps_unref(acaps);
4720
4721                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4722                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4723                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4724                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4725
4726                         player->is_openal_plugin_used = TRUE;
4727
4728                         if (player->video360_yaw_radians <= M_PI &&
4729                                         player->video360_yaw_radians >= -M_PI &&
4730                                         player->video360_pitch_radians <= M_PI_2 &&
4731                                         player->video360_pitch_radians >= -M_PI_2) {
4732                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4733                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4734                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4735                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4736                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4737                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4738                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4739                         }
4740                 } else {
4741                         if (player->is_360_feature_enabled && player->is_content_spherical)
4742                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4743                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4744                 }
4745
4746                 /* qos on */
4747                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4748                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4749
4750
4751                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4752                         (player->videodec_linked && player->ini.use_system_clock)) {
4753                         LOGD("system clock will be used.\n");
4754                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4755                 }
4756
4757                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4758                         __mmplayer_gst_set_audiosink_property(player, attrs);
4759         }
4760
4761         if (audiobin[MMPLAYER_A_SINK].gst) {
4762                 GstPad *sink_pad = NULL;
4763                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4764                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4765                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4766                 gst_object_unref(GST_OBJECT(sink_pad));
4767         }
4768
4769         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4770
4771         /* adding created elements to bin */
4772         LOGD("adding created elements to bin\n");
4773         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4774                 LOGE("failed to add elements\n");
4775                 goto ERROR;
4776         }
4777
4778         /* linking elements in the bucket by added order. */
4779         LOGD("Linking elements in the bucket by added order.\n");
4780         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4781                 LOGE("failed to link elements\n");
4782                 goto ERROR;
4783         }
4784
4785         /* get first element's sinkpad for creating ghostpad */
4786         first_element = (MMPlayerGstElement *)element_bucket->data;
4787         if (!first_element) {
4788                 LOGE("failed to get first elem\n");
4789                 goto ERROR;
4790         }
4791
4792         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4793         if (!pad) {
4794                 LOGE("failed to get pad from first element of audiobin\n");
4795                 goto ERROR;
4796         }
4797
4798         ghostpad = gst_ghost_pad_new("sink", pad);
4799         if (!ghostpad) {
4800                 LOGE("failed to create ghostpad\n");
4801                 goto ERROR;
4802         }
4803
4804         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4805                 LOGE("failed to add ghostpad to audiobin\n");
4806                 goto ERROR;
4807         }
4808
4809         gst_object_unref(pad);
4810
4811         g_list_free(element_bucket);
4812         MMPLAYER_FLEAVE();
4813
4814         return MM_ERROR_NONE;
4815
4816 ERROR:
4817
4818         LOGD("ERROR : releasing audiobin\n");
4819
4820         if (pad)
4821                 gst_object_unref(GST_OBJECT(pad));
4822
4823         if (ghostpad)
4824                 gst_object_unref(GST_OBJECT(ghostpad));
4825
4826         if (element_bucket)
4827                 g_list_free(element_bucket);
4828
4829         /* release element which are not added to bin */
4830         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4831                 /* NOTE : skip bin */
4832                 if (audiobin[i].gst) {
4833                         GstObject* parent = NULL;
4834                         parent = gst_element_get_parent(audiobin[i].gst);
4835
4836                         if (!parent) {
4837                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4838                                 audiobin[i].gst = NULL;
4839                         } else
4840                                 gst_object_unref(GST_OBJECT(parent));
4841                 }
4842         }
4843
4844         /* release audiobin with it's childs */
4845         if (audiobin[MMPLAYER_A_BIN].gst)
4846                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4847
4848         MMPLAYER_FREEIF(audiobin);
4849
4850         player->pipeline->audiobin = NULL;
4851
4852         return MM_ERROR_PLAYER_INTERNAL;
4853 }
4854
4855 static GstPadProbeReturn
4856 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4857 {
4858         mm_player_t* player = (mm_player_t*) u_data;
4859         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4860         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4861
4862         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4863
4864         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4865                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4866
4867         return GST_PAD_PROBE_OK;
4868 }
4869
4870 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4871 {
4872         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4873 }
4874
4875 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4876 {
4877         int ret = MM_ERROR_NONE;
4878         GList *l = NULL;
4879         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4881
4882         MMPLAYER_VIDEO_BO_LOCK(player);
4883
4884         if (player->video_bo_list) {
4885                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4886                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887                         if (tmp && tmp->bo == bo) {
4888                                 tmp->using = FALSE;
4889                                 LOGD("release bo %p", bo);
4890                                 tbm_bo_unref(tmp->bo);
4891                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4892                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4893                                 return ret;
4894                         }
4895                 }
4896         } else {
4897                 /* hw codec is running or the list was reset for DRC. */
4898                 LOGW("there is no bo list.");
4899         }
4900         MMPLAYER_VIDEO_BO_UNLOCK(player);
4901
4902         LOGW("failed to find bo %p", bo);
4903         return ret;
4904 }
4905
4906 static void
4907 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4908 {
4909         GList *l = NULL;
4910
4911         MMPLAYER_FENTER();
4912         MMPLAYER_RETURN_IF_FAIL(player);
4913
4914         MMPLAYER_VIDEO_BO_LOCK(player);
4915         if (player->video_bo_list) {
4916                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4917                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4918                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4919                         if (tmp) {
4920                                 if (tmp->bo)
4921                                         tbm_bo_unref(tmp->bo);
4922                                 g_free(tmp);
4923                         }
4924                 }
4925                 g_list_free(player->video_bo_list);
4926                 player->video_bo_list = NULL;
4927         }
4928         player->video_bo_size = 0;
4929         MMPLAYER_VIDEO_BO_UNLOCK(player);
4930
4931         MMPLAYER_FLEAVE();
4932         return;
4933 }
4934
4935 static void*
4936 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4937 {
4938         GList *l = NULL;
4939         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4940         gboolean ret = TRUE;
4941
4942         /* check DRC, if it is, destroy the prev bo list to create again */
4943         if (player->video_bo_size != size) {
4944                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4945                 __mmplayer_video_stream_destroy_bo_list(player);
4946                 player->video_bo_size = size;
4947         }
4948
4949         MMPLAYER_VIDEO_BO_LOCK(player);
4950
4951         if ((!player->video_bo_list) ||
4952                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4953
4954                 /* create bo list */
4955                 int idx = 0;
4956                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4957
4958                 if (player->video_bo_list) {
4959                         /* if bo list did not created all, try it again. */
4960                         idx = g_list_length(player->video_bo_list);
4961                         LOGD("bo list exist(len: %d)", idx);
4962                 }
4963
4964                 for (; idx < player->ini.num_of_video_bo; idx++) {
4965                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4966                         if (!bo_info) {
4967                                 LOGE("Fail to alloc bo_info.");
4968                                 break;
4969                         }
4970                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4971                         if (!bo_info->bo) {
4972                                 LOGE("Fail to tbm_bo_alloc.");
4973                                 g_free(bo_info);
4974                                 break;
4975                         }
4976                         bo_info->using = FALSE;
4977                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4978                 }
4979
4980                 /* update video num buffers */
4981                 player->video_num_buffers = idx;
4982                 if (idx == player->ini.num_of_video_bo)
4983                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4984
4985                 if (idx == 0) {
4986                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4987                         return NULL;
4988                 }
4989
4990                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4991         }
4992
4993         while (TRUE) {
4994                 /* get bo from list*/
4995                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4996                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4997                         if (tmp && (tmp->using == FALSE)) {
4998                                 LOGD("found bo %p to use", tmp->bo);
4999                                 tmp->using = TRUE;
5000                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5001                                 return tbm_bo_ref(tmp->bo);
5002                         }
5003                 }
5004                 if (!ret) {
5005                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5006                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5007                         return NULL;
5008                 }
5009
5010                 if (player->ini.video_bo_timeout <= 0) {
5011                         MMPLAYER_VIDEO_BO_WAIT(player);
5012                 } else {
5013                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5014                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5015                 }
5016                 continue;
5017         }
5018 }
5019
5020 static void
5021 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5022 {
5023         mm_player_t* player = (mm_player_t*)data;
5024         MMPLAYER_FENTER();
5025         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5026
5027         /* send prerolled pkt */
5028         player->video_stream_prerolled = FALSE;
5029
5030         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5031
5032         /* not to send prerolled pkt again */
5033         player->video_stream_prerolled = TRUE;
5034 }
5035
5036 static void
5037 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5038 {
5039         mm_player_t* player = (mm_player_t*)data;
5040         GstCaps *caps = NULL;
5041         MMPlayerVideoStreamDataType *stream = NULL;
5042         MMVideoBuffer *video_buffer = NULL;
5043         GstMemory *dataBlock = NULL;
5044         GstMemory *metaBlock = NULL;
5045         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5046         GstStructure *structure = NULL;
5047         const gchar *string_format = NULL;
5048         unsigned int fourcc = 0;
5049
5050         MMPLAYER_FENTER();
5051         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5052
5053         if (player->video_stream_prerolled) {
5054                 player->video_stream_prerolled = FALSE;
5055                 LOGD("skip the prerolled pkt not to send it again");
5056                 return;
5057         }
5058
5059         caps = gst_pad_get_current_caps(pad);
5060         if (caps == NULL) {
5061                 LOGE("Caps is NULL.");
5062                 return;
5063         }
5064
5065         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5066
5067         /* clear stream data structure */
5068         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5069         if (!stream) {
5070                 LOGE("failed to alloc mem for video data");
5071                 return;
5072         }
5073
5074         structure = gst_caps_get_structure(caps, 0);
5075         gst_structure_get_int(structure, "width", &(stream->width));
5076         gst_structure_get_int(structure, "height", &(stream->height));
5077         string_format = gst_structure_get_string(structure, "format");
5078         if (string_format)
5079                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5080         stream->format = util_get_pixtype(fourcc);
5081         gst_caps_unref(caps);
5082         caps = NULL;
5083
5084         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5085
5086     /*
5087         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5088                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5089     */
5090
5091         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5092                 LOGE("Wrong condition!!");
5093                 goto ERROR;
5094         }
5095
5096         /* set size and timestamp */
5097         dataBlock = gst_buffer_peek_memory(buffer, 0);
5098         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5099         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5100
5101         /* check zero-copy */
5102         if (player->set_mode.video_zc &&
5103                 player->set_mode.media_packet_video_stream &&
5104                 gst_buffer_n_memory(buffer) > 1) {
5105                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5106                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5107                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5108         }
5109
5110         if (video_buffer) { /* hw codec */
5111                 /* set tbm bo */
5112                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5113                         int i = 0;
5114
5115                         /* copy pointer of tbm bo, stride, elevation */
5116                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5117                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5118                                 i++;
5119                         }
5120                 } else {
5121                         LOGE("Not support video buffer format");
5122                         goto ERROR;
5123                 }
5124                 memcpy(stream->stride, video_buffer->stride_width,
5125                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5126                 memcpy(stream->elevation, video_buffer->stride_height,
5127                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5128
5129                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5130                 stream->internal_buffer = gst_buffer_ref(buffer);
5131         } else { /* sw codec */
5132                 int i = 0;
5133                 int j = 0;
5134                 int k = 0;
5135                 int ret = TBM_SURFACE_ERROR_NONE;
5136                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5137                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5138                 int size = 0;
5139                 unsigned char *src = NULL;
5140                 unsigned char *dest = NULL;
5141                 tbm_bo_handle thandle;
5142                 tbm_surface_h surface;
5143                 tbm_surface_info_s info;
5144                 gboolean gst_ret;
5145
5146                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5147                 if (!gst_ret) {
5148                         LOGE("fail to gst_memory_map");
5149                         goto ERROR;
5150                 }
5151
5152
5153                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5154                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5155
5156                         ret = tbm_surface_get_info(surface, &info);
5157
5158                         if (ret != TBM_SURFACE_ERROR_NONE) {
5159                                 tbm_surface_destroy(surface);
5160                                 goto ERROR;
5161                         }
5162                         tbm_surface_destroy(surface);
5163
5164                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5165                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5166                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5167                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5168                         stream->stride[0] = info.planes[0].stride;
5169                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5170                         stream->stride[1] = info.planes[1].stride;
5171                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5172                         stream->stride[2] = info.planes[2].stride;
5173                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5174                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5175                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5176                         stream->stride[0] = stream->width * 4;
5177                         stream->elevation[0] = stream->height;
5178                         size = stream->stride[0] * stream->height;
5179                 } else {
5180                         LOGE("Not support format %d", stream->format);
5181                         goto ERROR;
5182                 }
5183
5184                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5185                 if (!stream->bo[0]) {
5186                         LOGE("Fail to tbm_bo_alloc!!");
5187                         goto ERROR;
5188                 }
5189
5190                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5191                 if (thandle.ptr && mapinfo.data) {
5192                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5193                                 for (i = 0; i < 3; i++) {
5194                                         src = mapinfo.data + src_offset[i];
5195                                         dest = thandle.ptr + info.planes[i].offset;
5196
5197                                         if (i > 0) k = 1;
5198                                         for (j = 0; j < stream->height>>k; j++) {
5199                                                 memcpy(dest, src, stream->width>>k);
5200                                                 src += src_stride[i];
5201                                                 dest += stream->stride[i];
5202                                         }
5203                                 }
5204                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5205                                 memcpy(thandle.ptr, mapinfo.data, size);
5206                         } else {
5207                                 LOGE("Not support format %d", stream->format);
5208                                 goto ERROR;
5209                         }
5210                 } else {
5211                         LOGE("data pointer is wrong. dest : %p, src : %p",
5212                                         thandle.ptr, mapinfo.data);
5213                         goto ERROR;
5214                 }
5215                 tbm_bo_unmap(stream->bo[0]);
5216         }
5217
5218         if (player->video_stream_cb) { /* This has been already checked at the entry */
5219                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5220                         LOGE("failed to send video stream data.");
5221                         goto ERROR;
5222                 }
5223         }
5224
5225         if (metaBlock)
5226                 gst_memory_unmap(metaBlock, &mapinfo);
5227         else
5228                 gst_memory_unmap(dataBlock, &mapinfo);
5229
5230         return;
5231
5232 ERROR:
5233         LOGE("release video stream resource.");
5234         if (metaBlock) {
5235                 int i = 0;
5236                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5237                         if (stream->bo[i])
5238                                 tbm_bo_unref(stream->bo[i]);
5239                 }
5240                 gst_memory_unmap(metaBlock, &mapinfo);
5241
5242                 /* unref gst buffer */
5243                 if (stream->internal_buffer)
5244                         gst_buffer_unref(stream->internal_buffer);
5245         } else if (dataBlock) {
5246                 if (stream->bo[0])
5247                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5248                 gst_memory_unmap(dataBlock, &mapinfo);
5249         }
5250
5251         g_free(stream);
5252         return;
5253 }
5254
5255 static int
5256 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5257 {
5258         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5259         GList* element_bucket = NULL;
5260
5261         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5262
5263         MMPLAYER_FENTER();
5264
5265         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5266                 LOGD("do not need to add video filters.");
5267                 return MM_ERROR_NONE;
5268         }
5269
5270         /* in case of sw codec except 360 playback,
5271          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5272         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5273         LOGD("using video converter: %s", video_csc);
5274
5275         /* set video rotator */
5276         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5277
5278         *bucket = element_bucket;
5279         MMPLAYER_FLEAVE();
5280         return MM_ERROR_NONE;
5281
5282 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5283         g_list_free(element_bucket);
5284
5285         *bucket = NULL;
5286         MMPLAYER_FLEAVE();
5287         return MM_ERROR_PLAYER_INTERNAL;
5288 }
5289
5290 /**
5291  * This function is to create video pipeline.
5292  *
5293  * @param       player          [in]    handle of player
5294  *              caps            [in]    src caps of decoder
5295  *              surface_type    [in]    surface type for video rendering
5296  *
5297  * @return      This function returns zero on success.
5298  * @remark
5299  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5300  */
5301 /**
5302   * VIDEO PIPELINE
5303   * - video overlay surface(arm/x86) : tizenwlsink
5304   */
5305 static int
5306 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5307 {
5308         GstPad *pad = NULL;
5309         MMHandleType attrs;
5310         GList*element_bucket = NULL;
5311         MMPlayerGstElement* first_element = NULL;
5312         MMPlayerGstElement* videobin = NULL;
5313         gchar *videosink_element = NULL;
5314
5315         MMPLAYER_FENTER();
5316
5317         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5318
5319         /* alloc handles */
5320         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5321         if (!videobin)
5322                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5323
5324         player->pipeline->videobin = videobin;
5325
5326         attrs = MMPLAYER_GET_ATTRS(player);
5327         if (!attrs) {
5328                 LOGE("cannot get content attribute");
5329                 return MM_ERROR_PLAYER_INTERNAL;
5330         }
5331
5332         /* create bin */
5333         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5334         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5335         if (!videobin[MMPLAYER_V_BIN].gst) {
5336                 LOGE("failed to create videobin");
5337                 goto ERROR;
5338         }
5339
5340         int enable_video_decoded_cb = 0;
5341         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5342
5343         if (player->is_360_feature_enabled && player->is_content_spherical) {
5344                 LOGD("video360 elem will be added.");
5345
5346                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5347                                 "video-360", TRUE, player);
5348
5349                 /* Set spatial media metadata and/or user settings to the element.
5350                  * */
5351                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352                                 "projection-type", player->video360_metadata.projection_type, NULL);
5353
5354                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5356
5357                 if (player->video360_metadata.full_pano_width_pixels &&
5358                                 player->video360_metadata.full_pano_height_pixels &&
5359                                 player->video360_metadata.cropped_area_image_width &&
5360                                 player->video360_metadata.cropped_area_image_height) {
5361                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5362                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5363                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5364                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5365                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5366                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5367                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5368                                         NULL);
5369                 }
5370
5371                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5372                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5373                                         "horizontal-fov", player->video360_horizontal_fov,
5374                                         "vertical-fov", player->video360_vertical_fov, NULL);
5375                 }
5376
5377                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5378                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5379                                         "zoom", 1.0f / player->video360_zoom, NULL);
5380                 }
5381
5382                 if (player->video360_yaw_radians <= M_PI &&
5383                                 player->video360_yaw_radians >= -M_PI &&
5384                                 player->video360_pitch_radians <= M_PI_2 &&
5385                                 player->video360_pitch_radians >= -M_PI_2) {
5386                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5387                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5388                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5389                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5390                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5391                                         "pose-yaw", player->video360_metadata.init_view_heading,
5392                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5393                 }
5394
5395                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5396                                 "passthrough", !player->is_video360_enabled, NULL);
5397         }
5398
5399         /* set video sink */
5400         switch (surface_type) {
5401         case MM_DISPLAY_SURFACE_OVERLAY:
5402                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5403                         goto ERROR;
5404                 if (strlen(player->ini.videosink_element_overlay) > 0)
5405                         videosink_element = player->ini.videosink_element_overlay;
5406                 else
5407                         goto ERROR;
5408                 break;
5409         case MM_DISPLAY_SURFACE_NULL:
5410                 if (strlen(player->ini.videosink_element_fake) > 0)
5411                         videosink_element = player->ini.videosink_element_fake;
5412                 else
5413                         goto ERROR;
5414                 break;
5415         case MM_DISPLAY_SURFACE_REMOTE:
5416                 if (strlen(player->ini.videosink_element_fake) > 0)
5417                         videosink_element = player->ini.videosink_element_fake;
5418                 else
5419                         goto ERROR;
5420                 break;
5421         default:
5422                 LOGE("unidentified surface type");
5423                 goto ERROR;
5424         }
5425         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5426
5427         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5428
5429         /* additional setting for sink plug-in */
5430         switch (surface_type) {
5431         case MM_DISPLAY_SURFACE_OVERLAY:
5432         {
5433                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5434                 if (!use_tbm) {
5435                         LOGD("selected videosink name: %s", videosink_element);
5436
5437                         /* support shard memory with S/W codec on HawkP */
5438                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5439                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5440                                         "use-tbm", use_tbm, NULL);
5441                         }
5442                 } else {
5443                         if (attrs) {
5444                                 int gapless = 0;
5445
5446                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5447
5448                                 if (gapless > 0) {
5449                                         LOGD("disable last-sample");
5450                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5451                                 }
5452                         }
5453                 }
5454                 if (player->set_mode.media_packet_video_stream) {
5455                         int enable = 0;
5456                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5457                         if (enable)
5458                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5459
5460                         MMPLAYER_SIGNAL_CONNECT(player,
5461                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5462                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5463                                                                         "handoff",
5464                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5465                                                                         (gpointer)player);
5466
5467                         MMPLAYER_SIGNAL_CONNECT(player,
5468                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5469                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5470                                                                         "preroll-handoff",
5471                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5472                                                                         (gpointer)player);
5473                 }
5474                 break;
5475         }
5476         case MM_DISPLAY_SURFACE_REMOTE:
5477         {
5478                 if (player->set_mode.media_packet_video_stream) {
5479                         LOGE("add data probe at videosink");
5480                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5481                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5482
5483                         MMPLAYER_SIGNAL_CONNECT(player,
5484                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5485                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5486                                                                         "handoff",
5487                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5488                                                                         (gpointer)player);
5489
5490                         MMPLAYER_SIGNAL_CONNECT(player,
5491                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5492                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5493                                                                         "preroll-handoff",
5494                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5495                                                                         (gpointer)player);
5496                         if (attrs) {
5497                                 int gapless = 0;
5498
5499                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5500
5501                                 if (gapless > 0) {
5502                                         LOGD("disable last-sample");
5503                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5504                                 }
5505                         }
5506                 }
5507                 break;
5508         }
5509         default:
5510                 break;
5511         }
5512
5513         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5514                 goto ERROR;
5515
5516         if (videobin[MMPLAYER_V_SINK].gst) {
5517                 GstPad *sink_pad = NULL;
5518                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5519                 if (sink_pad) {
5520                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5521                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5522                         gst_object_unref(GST_OBJECT(sink_pad));
5523                 } else
5524                         LOGW("failed to get sink pad from videosink\n");
5525         }
5526
5527         /* store it as it's sink element */
5528         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5529
5530         /* adding created elements to bin */
5531         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5532                 LOGE("failed to add elements\n");
5533                 goto ERROR;
5534         }
5535
5536         /* Linking elements in the bucket by added order */
5537         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5538                 LOGE("failed to link elements\n");
5539                 goto ERROR;
5540         }
5541
5542         /* get first element's sinkpad for creating ghostpad */
5543         if (element_bucket)
5544                 first_element = (MMPlayerGstElement *)element_bucket->data;
5545         if (!first_element) {
5546                 LOGE("failed to get first element from bucket\n");
5547                 goto ERROR;
5548         }
5549
5550         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5551         if (!pad) {
5552                 LOGE("failed to get pad from first element\n");
5553                 goto ERROR;
5554         }
5555
5556         /* create ghostpad */
5557         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5558         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5559                 LOGE("failed to add ghostpad to videobin\n");
5560                 goto ERROR;
5561         }
5562         gst_object_unref(pad);
5563
5564         /* done. free allocated variables */
5565         if (element_bucket)
5566                 g_list_free(element_bucket);
5567
5568         MMPLAYER_FLEAVE();
5569
5570         return MM_ERROR_NONE;
5571
5572 ERROR:
5573         LOGE("ERROR : releasing videobin\n");
5574
5575         g_list_free(element_bucket);
5576
5577         if (pad)
5578                 gst_object_unref(GST_OBJECT(pad));
5579
5580         /* release videobin with it's childs */
5581         if (videobin[MMPLAYER_V_BIN].gst)
5582                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5583
5584
5585         MMPLAYER_FREEIF(videobin);
5586
5587         player->pipeline->videobin = NULL;
5588
5589         return MM_ERROR_PLAYER_INTERNAL;
5590 }
5591
5592 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5593 {
5594         GList *element_bucket = NULL;
5595         MMPlayerGstElement *textbin = player->pipeline->textbin;
5596
5597         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5598         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5599         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5600                                                         "signal-handoffs", FALSE,
5601                                                         NULL);
5602
5603         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5604         MMPLAYER_SIGNAL_CONNECT(player,
5605                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5606                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5607                                                         "handoff",
5608                                                         G_CALLBACK(__mmplayer_update_subtitle),
5609                                                         (gpointer)player);
5610
5611         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5612         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5613
5614         if (!player->play_subtitle) {
5615                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5616                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5617         }
5618
5619         /* adding created elements to bin */
5620         LOGD("adding created elements to bin\n");
5621         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5622                 LOGE("failed to add elements\n");
5623                 goto ERROR;
5624         }
5625
5626         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5627         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5628         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5629
5630         /* linking elements in the bucket by added order. */
5631         LOGD("Linking elements in the bucket by added order.\n");
5632         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5633                 LOGE("failed to link elements\n");
5634                 goto ERROR;
5635         }
5636
5637         /* done. free allocated variables */
5638         g_list_free(element_bucket);
5639
5640         if (textbin[MMPLAYER_T_QUEUE].gst) {
5641                 GstPad *pad = NULL;
5642                 GstPad *ghostpad = NULL;
5643
5644                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5645                 if (!pad) {
5646                         LOGE("failed to get sink pad of text queue");
5647                         goto ERROR;
5648                 }
5649
5650                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5651                 gst_object_unref(pad);
5652
5653                 if (!ghostpad) {
5654                         LOGE("failed to create ghostpad of textbin\n");
5655                         goto ERROR;
5656                 }
5657
5658                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5659                         LOGE("failed to add ghostpad to textbin\n");
5660                         gst_object_unref(ghostpad);
5661                         goto ERROR;
5662                 }
5663         }
5664
5665         return MM_ERROR_NONE;
5666
5667 ERROR:
5668         g_list_free(element_bucket);
5669
5670         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5671                 LOGE("remove textbin sink from sink list");
5672                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5673         }
5674
5675         /* release element at __mmplayer_gst_create_text_sink_bin */
5676         return MM_ERROR_PLAYER_INTERNAL;
5677 }
5678
5679 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5680 {
5681         MMPlayerGstElement *textbin = NULL;
5682         GList *element_bucket = NULL;
5683         int surface_type = 0;
5684         gint i = 0;
5685
5686         MMPLAYER_FENTER();
5687
5688         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5689
5690         /* alloc handles */
5691         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5692         if (!textbin) {
5693                 LOGE("failed to allocate memory for textbin\n");
5694                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5695         }
5696
5697         /* create bin */
5698         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5699         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5700         if (!textbin[MMPLAYER_T_BIN].gst) {
5701                 LOGE("failed to create textbin\n");
5702                 goto ERROR;
5703         }
5704
5705         /* take it */
5706         player->pipeline->textbin = textbin;
5707
5708         /* fakesink */
5709         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5710         LOGD("surface type for subtitle : %d", surface_type);
5711         switch (surface_type) {
5712         case MM_DISPLAY_SURFACE_OVERLAY:
5713         case MM_DISPLAY_SURFACE_NULL:
5714         case MM_DISPLAY_SURFACE_REMOTE:
5715                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5716                         LOGE("failed to make plain text elements\n");
5717                         goto ERROR;
5718                 }
5719                 break;
5720         default:
5721                 goto ERROR;
5722                 break;
5723         }
5724
5725         MMPLAYER_FLEAVE();
5726
5727         return MM_ERROR_NONE;
5728
5729 ERROR:
5730
5731         LOGD("ERROR : releasing textbin\n");
5732
5733         g_list_free(element_bucket);
5734
5735         /* release signal */
5736         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5737
5738         /* release element which are not added to bin */
5739         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5740                 /* NOTE : skip bin */
5741                 if (textbin[i].gst) {
5742                         GstObject* parent = NULL;
5743                         parent = gst_element_get_parent(textbin[i].gst);
5744
5745                         if (!parent) {
5746                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5747                                 textbin[i].gst = NULL;
5748                         } else {
5749                                 gst_object_unref(GST_OBJECT(parent));
5750                         }
5751                 }
5752         }
5753
5754         /* release textbin with it's childs */
5755         if (textbin[MMPLAYER_T_BIN].gst)
5756                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5757
5758         MMPLAYER_FREEIF(player->pipeline->textbin);
5759         player->pipeline->textbin = NULL;
5760
5761         MMPLAYER_FLEAVE();
5762         return MM_ERROR_PLAYER_INTERNAL;
5763 }
5764
5765
5766 static int
5767 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5768 {
5769         MMPlayerGstElement* mainbin = NULL;
5770         MMPlayerGstElement* textbin = NULL;
5771         MMHandleType attrs = 0;
5772         GstElement *subsrc = NULL;
5773         GstElement *subparse = NULL;
5774         gchar *subtitle_uri = NULL;
5775         const gchar *charset = NULL;
5776         GstPad *pad = NULL;
5777
5778         MMPLAYER_FENTER();
5779
5780         /* get mainbin */
5781         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5782                                                                 player->pipeline &&
5783                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5784
5785         mainbin = player->pipeline->mainbin;
5786
5787         attrs = MMPLAYER_GET_ATTRS(player);
5788         if (!attrs) {
5789                 LOGE("cannot get content attribute\n");
5790                 return MM_ERROR_PLAYER_INTERNAL;
5791         }
5792
5793         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5794         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5795                 LOGE("subtitle uri is not proper filepath.\n");
5796                 return MM_ERROR_PLAYER_INVALID_URI;
5797         }
5798
5799         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5800                 LOGE("failed to get storage info of subtitle path");
5801                 return MM_ERROR_PLAYER_INVALID_URI;
5802         }
5803
5804         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5805
5806         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5807         player->subtitle_language_list = NULL;
5808         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5809
5810         /* create the subtitle source */
5811         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5812         if (!subsrc) {
5813                 LOGE("failed to create filesrc element\n");
5814                 goto ERROR;
5815         }
5816         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5817
5818         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5819         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5820
5821         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5822                 LOGW("failed to add queue\n");
5823                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5824                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5825                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5826                 goto ERROR;
5827         }
5828
5829         /* subparse */
5830         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5831         if (!subparse) {
5832                 LOGE("failed to create subparse element\n");
5833                 goto ERROR;
5834         }
5835
5836         charset = util_get_charset(subtitle_uri);
5837         if (charset) {
5838                 LOGD("detected charset is %s\n", charset);
5839                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5840         }
5841
5842         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5843         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5844
5845         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5846                 LOGW("failed to add subparse\n");
5847                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5848                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5849                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5850                 goto ERROR;
5851         }
5852
5853         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5854                 LOGW("failed to link subsrc and subparse\n");
5855                 goto ERROR;
5856         }
5857
5858         player->play_subtitle = TRUE;
5859         player->adjust_subtitle_pos = 0;
5860
5861         LOGD("play subtitle using subtitle file\n");
5862
5863         if (player->pipeline->textbin == NULL) {
5864                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5865                         LOGE("failed to create text sink bin. continuing without text\n");
5866                         goto ERROR;
5867                 }
5868
5869                 textbin = player->pipeline->textbin;
5870
5871                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5872                         LOGW("failed to add textbin\n");
5873
5874                         /* release signal */
5875                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5876
5877                         /* release textbin with it's childs */
5878                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5879                         MMPLAYER_FREEIF(player->pipeline->textbin);
5880                         player->pipeline->textbin = textbin = NULL;
5881                         goto ERROR;
5882                 }
5883
5884                 LOGD("link text input selector and textbin ghost pad");
5885
5886                 player->textsink_linked = 1;
5887                 player->external_text_idx = 0;
5888                 LOGI("player->textsink_linked set to 1\n");
5889         } else {
5890                 textbin = player->pipeline->textbin;
5891                 LOGD("text bin has been created. reuse it.");
5892                 player->external_text_idx = 1;
5893         }
5894
5895         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5896                 LOGW("failed to link subparse and textbin\n");
5897                 goto ERROR;
5898         }
5899
5900         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5901         if (!pad) {
5902                 LOGE("failed to get sink pad from textsink to probe data");
5903                 goto ERROR;
5904         }
5905
5906         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5907                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5908
5909         gst_object_unref(pad);
5910         pad = NULL;
5911
5912         /* create dot. for debugging */
5913         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5914         MMPLAYER_FLEAVE();
5915
5916         return MM_ERROR_NONE;
5917
5918 ERROR:
5919         /* release text pipeline resource */
5920         player->textsink_linked = 0;
5921
5922         /* release signal */
5923         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5924
5925         if (player->pipeline->textbin) {
5926                 LOGE("remove textbin");
5927
5928                 /* release textbin with it's childs */
5929                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5930                 MMPLAYER_FREEIF(player->pipeline->textbin);
5931                 player->pipeline->textbin = NULL;
5932
5933         }
5934
5935         /* release subtitle elem */
5936         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5937         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5938
5939         return MM_ERROR_PLAYER_INTERNAL;
5940 }
5941
5942 gboolean
5943 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5944 {
5945         mm_player_t* player = (mm_player_t*) data;
5946         MMMessageParamType msg = {0, };
5947         GstClockTime duration = 0;
5948         gpointer text = NULL;
5949         guint text_size = 0;
5950         gboolean ret = TRUE;
5951         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5952
5953         MMPLAYER_FENTER();
5954
5955         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5956         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5957
5958         if (player->is_subtitle_force_drop) {
5959                 LOGW("subtitle is dropped forcedly.");
5960                 return ret;
5961         }
5962
5963         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5964         text = mapinfo.data;
5965         text_size = mapinfo.size;
5966         duration = GST_BUFFER_DURATION(buffer);
5967
5968         if (player->set_mode.subtitle_off) {
5969                 LOGD("subtitle is OFF.\n");
5970                 return TRUE;
5971         }
5972
5973         if (!text || (text_size == 0)) {
5974                 LOGD("There is no subtitle to be displayed.\n");
5975                 return TRUE;
5976         }
5977
5978         msg.data = (void *) text;
5979         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5980
5981         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5982
5983         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5984         gst_buffer_unmap(buffer, &mapinfo);
5985
5986         MMPLAYER_FLEAVE();
5987
5988         return ret;
5989 }
5990
5991 static GstPadProbeReturn
5992 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5993 {
5994         mm_player_t *player = (mm_player_t *) u_data;
5995         GstClockTime cur_timestamp = 0;
5996         gint64 adjusted_timestamp = 0;
5997         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5998
5999         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6000
6001         if (player->set_mode.subtitle_off) {
6002                 LOGD("subtitle is OFF.\n");
6003                 return TRUE;
6004         }
6005
6006         if (player->adjust_subtitle_pos == 0) {
6007                 LOGD("nothing to do");
6008                 return TRUE;
6009         }
6010
6011         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6012         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6013
6014         if (adjusted_timestamp < 0) {
6015                 LOGD("adjusted_timestamp under zero");
6016                 MMPLAYER_FLEAVE();
6017                 return FALSE;
6018         }
6019
6020         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6021         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6022                                 GST_TIME_ARGS(cur_timestamp),
6023                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6024
6025         return GST_PAD_PROBE_OK;
6026 }
6027 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6028 {
6029         MMPLAYER_FENTER();
6030
6031         /* check player and subtitlebin are created */
6032         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6033         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6034
6035         if (position == 0) {
6036                 LOGD("nothing to do\n");
6037                 MMPLAYER_FLEAVE();
6038                 return MM_ERROR_NONE;
6039         }
6040
6041         switch (format) {
6042         case MM_PLAYER_POS_FORMAT_TIME:
6043                 {
6044                         /* check current postion */
6045                         player->adjust_subtitle_pos = position;
6046
6047                         LOGD("save adjust_subtitle_pos in player") ;
6048                 }
6049                 break;
6050
6051         default:
6052                 {
6053                         LOGW("invalid format.\n");
6054                         MMPLAYER_FLEAVE();
6055                         return MM_ERROR_INVALID_ARGUMENT;
6056                 }
6057         }
6058
6059         MMPLAYER_FLEAVE();
6060
6061         return MM_ERROR_NONE;
6062 }
6063
6064 static void
6065 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6066 {
6067         GstElement *appsrc = element;
6068         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6069         GstBuffer *buffer = NULL;
6070         GstFlowReturn ret = GST_FLOW_OK;
6071         gint len = size;
6072
6073         MMPLAYER_RETURN_IF_FAIL(element);
6074         MMPLAYER_RETURN_IF_FAIL(buf);
6075
6076         buffer = gst_buffer_new();
6077
6078         if (buf->offset >= buf->len) {
6079                 LOGD("call eos appsrc\n");
6080                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6081                 return;
6082         }
6083
6084         if (buf->len - buf->offset < size)
6085                 len = buf->len - buf->offset;
6086
6087         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6088         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6089         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6090
6091         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6092         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6093
6094         buf->offset += len;
6095 }
6096
6097 static gboolean
6098 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6099 {
6100         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6101
6102         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6103
6104         buf->offset  = (int)size;
6105
6106         return TRUE;
6107 }
6108
6109 static GstBusSyncReply
6110 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6111 {
6112         mm_player_t *player = (mm_player_t *)data;
6113         GstBusSyncReply reply = GST_BUS_DROP;
6114
6115         if (!(player->pipeline && player->pipeline->mainbin)) {
6116                 LOGE("player pipeline handle is null");
6117                 return GST_BUS_PASS;
6118         }
6119
6120         if (!__mmplayer_check_useful_message(player, message)) {
6121                 gst_message_unref(message);
6122                 return GST_BUS_DROP;
6123         }
6124
6125         switch (GST_MESSAGE_TYPE(message)) {
6126         case GST_MESSAGE_STATE_CHANGED:
6127                 /* post directly for fast launch */
6128                 if (player->sync_handler) {
6129                         __mmplayer_gst_callback(message, player);
6130                         reply = GST_BUS_DROP;
6131                 } else
6132                         reply = GST_BUS_PASS;
6133                 break;
6134         case GST_MESSAGE_TAG:
6135                 __mmplayer_gst_extract_tag_from_msg(player, message);
6136
6137                 #if 0 // debug
6138                 {
6139                         GstTagList *tags = NULL;
6140
6141                         gst_message_parse_tag(message, &tags);
6142                         if (tags) {
6143                                 LOGE("TAGS received from element \"%s\".\n",
6144                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6145
6146                                 gst_tag_list_foreach(tags, print_tag, NULL);
6147                                 gst_tag_list_free(tags);
6148                                 tags = NULL;
6149                         }
6150                         break;
6151                 }
6152                 #endif
6153                 break;
6154
6155         case GST_MESSAGE_DURATION_CHANGED:
6156                 __mmplayer_gst_handle_duration(player, message);
6157                 break;
6158         case GST_MESSAGE_ASYNC_DONE:
6159                 /* NOTE:Don't call gst_callback directly
6160                  * because previous frame can be showed even though this message is received for seek.
6161                  */
6162         default:
6163                 reply = GST_BUS_PASS;
6164                 break;
6165         }
6166
6167         if (reply == GST_BUS_DROP)
6168                 gst_message_unref(message);
6169
6170         return reply;
6171 }
6172
6173 static gboolean
6174 __mmplayer_gst_create_decoder(mm_player_t *player,
6175                                                                 MMPlayerTrackType track,
6176                                                                 GstPad* srcpad,
6177                                                                 enum MainElementID elemId,
6178                                                                 const gchar* name)
6179 {
6180         gboolean ret = TRUE;
6181         GstPad *sinkpad = NULL;
6182
6183         MMPLAYER_FENTER();
6184
6185         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6186                                                 player->pipeline &&
6187                                                 player->pipeline->mainbin, FALSE);
6188         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6189         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6190         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6191
6192         GstElement *decodebin = NULL;
6193         GstCaps *dec_caps = NULL;
6194
6195         /* create decodebin */
6196         decodebin = gst_element_factory_make("decodebin", name);
6197
6198         if (!decodebin) {
6199                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6200                 ret = FALSE;
6201                 goto ERROR;
6202         }
6203
6204         /* raw pad handling signal */
6205         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6206                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6207
6208         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6209         before looking for any elements that can handle that stream.*/
6210         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6211                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6212
6213         /* This signal is emitted when a element is added to the bin.*/
6214         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6215                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6216
6217         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6218                 LOGE("failed to add new decodebin\n");
6219                 ret = FALSE;
6220                 goto ERROR;
6221         }
6222
6223         dec_caps = gst_pad_query_caps(srcpad, NULL);
6224         if (dec_caps) {
6225                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6226                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6227                 gst_caps_unref(dec_caps);
6228         }
6229
6230         player->pipeline->mainbin[elemId].id = elemId;
6231         player->pipeline->mainbin[elemId].gst = decodebin;
6232
6233         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6234
6235         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6236                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6237                 gst_object_unref(GST_OBJECT(decodebin));
6238         }
6239
6240         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6241                 LOGE("failed to sync second level decodebin state with parent\n");
6242
6243         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6244
6245 ERROR:
6246         if (sinkpad) {
6247                 gst_object_unref(GST_OBJECT(sinkpad));
6248                 sinkpad = NULL;
6249         }
6250         MMPLAYER_FLEAVE();
6251
6252         return ret;
6253 }
6254
6255 /**
6256  * This function is to create  audio or video pipeline for playing.
6257  *
6258  * @param       player          [in]    handle of player
6259  *
6260  * @return      This function returns zero on success.
6261  * @remark
6262  * @see
6263  */
6264 static int
6265 __mmplayer_gst_create_pipeline(mm_player_t* player)
6266 {
6267         GstBus  *bus = NULL;
6268         MMPlayerGstElement *mainbin = NULL;
6269         MMHandleType attrs = 0;
6270         GstElement* element = NULL;
6271         GstElement* elem_src_audio = NULL;
6272         GstElement* elem_src_subtitle = NULL;
6273         GstElement* es_video_queue = NULL;
6274         GstElement* es_audio_queue = NULL;
6275         GstElement* es_subtitle_queue = NULL;
6276         GList* element_bucket = NULL;
6277         gboolean need_state_holder = TRUE;
6278         gint i = 0;
6279 #ifdef SW_CODEC_ONLY
6280         int surface_type = 0;
6281 #endif
6282         MMPLAYER_FENTER();
6283
6284         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6285
6286         /* get profile attribute */
6287         attrs = MMPLAYER_GET_ATTRS(player);
6288         if (!attrs) {
6289                 LOGE("cannot get content attribute\n");
6290                 goto INIT_ERROR;
6291         }
6292
6293         /* create pipeline handles */
6294         if (player->pipeline) {
6295                 LOGW("pipeline should be released before create new one\n");
6296                 goto INIT_ERROR;
6297         }
6298
6299         player->video360_metadata.is_spherical = -1;
6300         player->is_openal_plugin_used = FALSE;
6301
6302         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6303         if (player->pipeline == NULL)
6304                 goto INIT_ERROR;
6305
6306         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6307
6308         /* create mainbin */
6309         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6310         if (mainbin == NULL)
6311                 goto INIT_ERROR;
6312
6313         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6314
6315         /* create pipeline */
6316         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6317         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6318         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6319                 LOGE("failed to create pipeline\n");
6320                 goto INIT_ERROR;
6321         }
6322         player->demux_pad_index = 0;
6323         player->subtitle_language_list = NULL;
6324
6325         player->is_subtitle_force_drop = FALSE;
6326         player->last_multiwin_status = FALSE;
6327
6328         _mmplayer_track_initialize(player);
6329         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6330
6331         /* create source element */
6332         switch (player->profile.uri_type) {
6333         /* rtsp streamming */
6334         case MM_PLAYER_URI_TYPE_URL_RTSP:
6335                 {
6336                         gchar *user_agent;
6337
6338                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6339
6340                         if (!element) {
6341                                 LOGE("failed to create streaming source element\n");
6342                                 break;
6343                         }
6344
6345                         /* make it zero */
6346                         user_agent = NULL;
6347
6348                         /* get attribute */
6349                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6350
6351                         SECURE_LOGD("user_agent : %s\n", user_agent);
6352
6353                         /* setting property to streaming source */
6354                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6355                         if (user_agent)
6356                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6357
6358                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6359                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6360                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6361                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6362                 }
6363                 break;
6364
6365         /* http streaming*/
6366         case MM_PLAYER_URI_TYPE_URL_HTTP:
6367                 {
6368                         gchar *user_agent, *cookies, **cookie_list;
6369                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6370                         user_agent = cookies = NULL;
6371                         cookie_list = NULL;
6372                         gint mode = MM_PLAYER_PD_MODE_NONE;
6373
6374                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6375
6376                         player->pd_mode = mode;
6377
6378                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6379
6380                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6381                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6382                                 if (!element) {
6383                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6384                                         break;
6385                                 }
6386                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6387
6388                                 /* get attribute */
6389                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6390                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6391
6392                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6393                                         LOGD("get timeout from ini\n");
6394                                         http_timeout = player->ini.http_timeout;
6395                                 }
6396
6397                                 /* get attribute */
6398                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6399                                 SECURE_LOGD("cookies : %s\n", cookies);
6400                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6401                                 LOGD("timeout : %d\n",  http_timeout);
6402
6403                                 /* setting property to streaming source */
6404                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6405                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6406                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6407
6408                                 /* parsing cookies */
6409                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6410                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6411                                         g_strfreev(cookie_list);
6412                                 }
6413                                 if (user_agent)
6414                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6415
6416                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6417                                         LOGW("it's dash. and it's still experimental feature.");
6418                         } else {
6419                                 // progressive download
6420                                 gchar* location = NULL;
6421
6422                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6423                                         gchar *path = NULL;
6424
6425                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6426
6427                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6428
6429                                         LOGD("PD Location : %s\n", path);
6430
6431                                         if (path) {
6432                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6433                                                         LOGE("failed to get storage info");
6434                                                         break;
6435                                                 }
6436                                                 player->pd_file_save_path = g_strdup(path);
6437                                         } else {
6438                                                 LOGE("can't find pd location so, it should be set \n");
6439                                                 break;
6440                                         }
6441                                 }
6442
6443                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6444                                 if (!element) {
6445                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6446                                         break;
6447                                 }
6448
6449                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6450                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6451                                 else
6452                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6453                                 g_object_get(element, "location", &location, NULL);
6454                                 LOGD("PD_LOCATION [%s].\n", location);
6455                                 if (location)
6456                                         g_free(location);
6457                         }
6458                 }
6459                 break;
6460
6461         /* file source */
6462         case MM_PLAYER_URI_TYPE_FILE:
6463                 {
6464                         LOGD("using filesrc for 'file://' handler.\n");
6465                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6466                                 LOGE("failed to get storage info");
6467                                 break;
6468                         }
6469
6470                         element = gst_element_factory_make("filesrc", "source");
6471                         if (!element) {
6472                                 LOGE("failed to create filesrc\n");
6473                                 break;
6474                         }
6475
6476                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6477                 }
6478                 break;
6479
6480         case MM_PLAYER_URI_TYPE_SS:
6481                 {
6482                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6483                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6484                         if (!element) {
6485                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6486                                 break;
6487                         }
6488
6489                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6490                                 LOGD("get timeout from ini\n");
6491                                 http_timeout = player->ini.http_timeout;
6492                         }
6493
6494                         /* setting property to streaming source */
6495                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6496                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6497                 }
6498                 break;
6499         case MM_PLAYER_URI_TYPE_MS_BUFF:
6500                 {
6501                         LOGD("MS buff src is selected\n");
6502
6503                         if (player->v_stream_caps) {
6504                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6505                                 if (!element) {
6506                                         LOGF("failed to create video app source element[appsrc].\n");
6507                                         break;
6508                                 }
6509
6510                                 if (player->a_stream_caps) {
6511                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6512                                         if (!elem_src_audio) {
6513                                                 LOGF("failed to create audio app source element[appsrc].\n");
6514                                                 break;
6515                                         }
6516                                 }
6517                         } else if (player->a_stream_caps) {
6518                                 /* no video, only audio pipeline*/
6519                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6520                                 if (!element) {
6521                                         LOGF("failed to create audio app source element[appsrc].\n");
6522                                         break;
6523                                 }
6524                         }
6525
6526                         if (player->s_stream_caps) {
6527                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6528                                 if (!elem_src_subtitle) {
6529                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6530                                         break;
6531                                 }
6532                         }
6533
6534                         LOGD("setting app sources properties.\n");
6535                         LOGD("location : %s\n", player->profile.uri);
6536
6537                         if (player->v_stream_caps && element) {
6538                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6539                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6540                                                                                                 "caps", player->v_stream_caps, NULL);
6541
6542                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6544                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6545                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6546
6547                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6548                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6549                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6550                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6551
6552                                 if (player->a_stream_caps && elem_src_audio) {
6553                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6554                                                                                                                         "caps", player->a_stream_caps, NULL);
6555
6556                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6559                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6560
6561                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6562                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6563                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6564                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6565                                 }
6566                         } else if (player->a_stream_caps && element) {
6567                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6568                                                                                                 "caps", player->a_stream_caps, NULL);
6569
6570                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6572                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6573                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6574
6575                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6576                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6577                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6578                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6579                         }
6580
6581                         if (player->s_stream_caps && elem_src_subtitle) {
6582                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6583                                                                                                                  "caps", player->s_stream_caps, NULL);
6584
6585                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6587                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6588                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6589
6590                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6591
6592                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6593                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6594                         }
6595
6596                         if (player->v_stream_caps && element) {
6597                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6599                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6600                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6601
6602                                 if (player->a_stream_caps && elem_src_audio) {
6603                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6605                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6606                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6607                                 }
6608                         } else if (player->a_stream_caps && element) {
6609                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6611                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6612                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6613                         }
6614
6615                         if (player->s_stream_caps && elem_src_subtitle)
6616                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6617                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6618
6619                         need_state_holder = FALSE;
6620
6621                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6622                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6623                                 LOGE("failed to commit\n");
6624                 }
6625                 break;
6626         /* appsrc */
6627         case MM_PLAYER_URI_TYPE_MEM:
6628                 {
6629                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6630
6631                         LOGD("mem src is selected\n");
6632
6633                         element = gst_element_factory_make("appsrc", "mem-source");
6634                         if (!element) {
6635                                 LOGE("failed to create appsrc element\n");
6636                                 break;
6637                         }
6638
6639                         g_object_set(element, "stream-type", stream_type, NULL);
6640                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6641                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6642
6643                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6644                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6645                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6646                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6647                 }
6648                 break;
6649         case MM_PLAYER_URI_TYPE_URL:
6650                 break;
6651
6652         case MM_PLAYER_URI_TYPE_TEMP:
6653                 break;
6654
6655         case MM_PLAYER_URI_TYPE_NONE:
6656         default:
6657                 break;
6658         }
6659
6660         /* check source element is OK */
6661         if (!element) {
6662                 LOGE("no source element was created.\n");
6663                 goto INIT_ERROR;
6664         }
6665
6666         /* take source element */
6667         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6668         mainbin[MMPLAYER_M_SRC].gst = element;
6669         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6670
6671         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6672                 player->streamer = __mm_player_streaming_create();
6673                 __mm_player_streaming_initialize(player->streamer);
6674         }
6675
6676         if (MMPLAYER_IS_HTTP_PD(player)) {
6677                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6678
6679                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6680                 element = gst_element_factory_make("queue2", "queue2");
6681                 if (!element) {
6682                         LOGE("failed to create http streaming buffer element\n");
6683                         goto INIT_ERROR;
6684                 }
6685
6686                 /* take it */
6687                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6688                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6689                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6690
6691                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6692
6693                 player->streamer->is_pd_mode = TRUE;
6694
6695                 __mm_player_streaming_set_queue2(player->streamer,
6696                                 element,
6697                                 TRUE,
6698                                 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6699                                 pre_buffering_time,
6700                                 1.0,
6701                                 player->ini.http_buffering_limit,
6702                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6703                                 NULL,
6704                                 0);
6705         }
6706         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6707                 if (player->v_stream_caps) {
6708                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6709                         if (!es_video_queue) {
6710                                 LOGE("create es_video_queue for es player failed\n");
6711                                 goto INIT_ERROR;
6712                         }
6713                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6714                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6716                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6717
6718                         /* Adding audio appsrc to bucket */
6719                         if (player->a_stream_caps && elem_src_audio) {
6720                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6721                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6722                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6723
6724                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6725                                 if (!es_audio_queue) {
6726                                         LOGE("create es_audio_queue for es player failed\n");
6727                                         goto INIT_ERROR;
6728                                 }
6729                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6730
6731                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6732                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6733                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6734                         }
6735                 } else if (player->a_stream_caps) {
6736                         /* Only audio stream, no video */
6737                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6738                         if (!es_audio_queue) {
6739                                 LOGE("create es_audio_queue for es player failed\n");
6740                                 goto INIT_ERROR;
6741                         }
6742                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6743                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6744                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6745                 }
6746
6747                 if (player->s_stream_caps && elem_src_subtitle) {
6748                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6749                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6750                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6751
6752                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6753                         if (!es_subtitle_queue) {
6754                                 LOGE("create es_subtitle_queue for es player failed\n");
6755                                 goto INIT_ERROR;
6756                         }
6757                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6758                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6759                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6760                 }
6761         }
6762
6763         /* create autoplugging element if src element is not a rtsp src */
6764         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6765                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6766                 element = NULL;
6767                 enum MainElementID elemId = MMPLAYER_M_NUM;
6768
6769                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6770                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6771                         elemId = MMPLAYER_M_AUTOPLUG;
6772                         element = __mmplayer_create_decodebin(player);
6773                         if (element) {
6774                                 /* default size of mq in decodebin is 2M
6775                                  * but it can cause blocking issue during seeking depends on content. */
6776                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6777                         }
6778                         need_state_holder = FALSE;
6779                 } else {
6780                         elemId = MMPLAYER_M_TYPEFIND;
6781                         element = gst_element_factory_make("typefind", "typefinder");
6782                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6783                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6784                 }
6785
6786                 /* check autoplug element is OK */
6787                 if (!element) {
6788                         LOGE("can not create element(%d)\n", elemId);
6789                         goto INIT_ERROR;
6790                 }
6791
6792                 mainbin[elemId].id = elemId;
6793                 mainbin[elemId].gst = element;
6794
6795                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6796         }
6797
6798         /* add elements to pipeline */
6799         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6800                 LOGE("Failed to add elements to pipeline\n");
6801                 goto INIT_ERROR;
6802         }
6803
6804
6805         /* linking elements in the bucket by added order. */
6806         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6807                 LOGE("Failed to link some elements\n");
6808                 goto INIT_ERROR;
6809         }
6810
6811
6812         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6813         if (need_state_holder) {
6814                 /* create */
6815                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6816                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6817
6818                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6819                         LOGE("fakesink element could not be created\n");
6820                         goto INIT_ERROR;
6821                 }
6822                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6823
6824                 /* take ownership of fakesink. we are reusing it */
6825                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6826
6827                 /* add */
6828                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6829                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6830                         LOGE("failed to add fakesink to bin\n");
6831                         goto INIT_ERROR;
6832                 }
6833         }
6834
6835         /* now we have completed mainbin. take it */
6836         player->pipeline->mainbin = mainbin;
6837
6838         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6839                 GstPad *srcpad = NULL;
6840
6841                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6842                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6843                         if (srcpad) {
6844                                 __mmplayer_gst_create_decoder(player,
6845                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6846                                                                                                 srcpad,
6847                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6848                                                                                                 "video_decodebin");
6849
6850                                 gst_object_unref(GST_OBJECT(srcpad));
6851                                 srcpad = NULL;
6852                         }
6853                 }
6854
6855                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6856                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6857                         if (srcpad) {
6858                                 __mmplayer_gst_create_decoder(player,
6859                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6860                                                                                                 srcpad,
6861                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6862                                                                                                 "audio_decodebin");
6863
6864                                 gst_object_unref(GST_OBJECT(srcpad));
6865                                 srcpad = NULL;
6866                         } // else error
6867                 } //  else error
6868
6869                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6870                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6871         }
6872
6873         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6874         if (__mmplayer_check_subtitle(player)) {
6875                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6876                         LOGE("fail to create text pipeline");
6877         }
6878
6879         /* connect bus callback */
6880         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6881         if (!bus) {
6882                 LOGE("cannot get bus from pipeline.\n");
6883                 goto INIT_ERROR;
6884         }
6885
6886         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6887
6888         player->context.thread_default = g_main_context_get_thread_default();
6889
6890         if (player->context.thread_default == NULL) {
6891                 player->context.thread_default = g_main_context_default();
6892                 LOGD("thread-default context is the global default context");
6893         }
6894         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6895
6896         /* set sync handler to get tag synchronously */
6897         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6898
6899         /* finished */
6900         gst_object_unref(GST_OBJECT(bus));
6901         g_list_free(element_bucket);
6902
6903         /* create gst bus_msb_cb thread */
6904         g_mutex_init(&player->bus_msg_thread_mutex);
6905         g_cond_init(&player->bus_msg_thread_cond);
6906         player->bus_msg_thread_exit = FALSE;
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 (mainbin) {
7017                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7018                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7019                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7020                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7021                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7022                         gst_object_unref(bus);
7023
7024                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7025                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7026                         if (ret != MM_ERROR_NONE) {
7027                                 LOGE("fail to change state to NULL\n");
7028                                 return MM_ERROR_PLAYER_INTERNAL;
7029                         }
7030
7031                         LOGW("succeeded in changing state to NULL\n");
7032
7033                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7034
7035                         /* free fakesink */
7036                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7037                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7038
7039                         /* free avsysaudiosink
7040                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7041                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7042                         */
7043                         MMPLAYER_FREEIF(audiobin);
7044                         MMPLAYER_FREEIF(videobin);
7045                         MMPLAYER_FREEIF(textbin);
7046                         MMPLAYER_FREEIF(mainbin);
7047                 }
7048
7049                 if (tag_list)
7050                         gst_tag_list_free(tag_list);
7051
7052                 MMPLAYER_FREEIF(player->pipeline);
7053         }
7054         MMPLAYER_FREEIF(player->album_art);
7055
7056         if (player->v_stream_caps) {
7057                 gst_caps_unref(player->v_stream_caps);
7058                 player->v_stream_caps = NULL;
7059         }
7060         if (player->a_stream_caps) {
7061                 gst_caps_unref(player->a_stream_caps);
7062                 player->a_stream_caps = NULL;
7063         }
7064
7065         if (player->s_stream_caps) {
7066                 gst_caps_unref(player->s_stream_caps);
7067                 player->s_stream_caps = NULL;
7068         }
7069         _mmplayer_track_destroy(player);
7070
7071         if (player->sink_elements)
7072                 g_list_free(player->sink_elements);
7073         player->sink_elements = NULL;
7074
7075         if (player->bufmgr) {
7076                 tbm_bufmgr_deinit(player->bufmgr);
7077                 player->bufmgr = NULL;
7078         }
7079
7080         LOGW("finished destroy pipeline\n");
7081
7082         MMPLAYER_FLEAVE();
7083
7084         return ret;
7085 }
7086
7087 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
7088 {
7089         MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
7090
7091         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
7092
7093         audiobin = player->pipeline->audiobin; /* can be null */
7094         videobin = player->pipeline->videobin; /* can be null */
7095         textbin = player->pipeline->textbin;   /* can be null */
7096
7097         LOGD("Async will be set to %d about 0x%X type sink", async, type);
7098
7099         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
7100                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
7101
7102         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
7103                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
7104
7105         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
7106                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
7107
7108         return;
7109 }
7110
7111 static int __gst_realize(mm_player_t* player)
7112 {
7113         gint timeout = 0;
7114         int ret = MM_ERROR_NONE;
7115
7116         MMPLAYER_FENTER();
7117
7118         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7119
7120         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7121
7122         ret = __mmplayer_gst_create_pipeline(player);
7123         if (ret) {
7124                 LOGE("failed to create pipeline\n");
7125                 return ret;
7126         }
7127
7128         /* set pipeline state to READY */
7129         /* NOTE : state change to READY must be performed sync. */
7130         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7131         ret = __mmplayer_gst_set_state(player,
7132                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7133
7134         if (ret != MM_ERROR_NONE) {
7135                 /* return error if failed to set state */
7136                 LOGE("failed to set READY state");
7137                 return ret;
7138         }
7139
7140         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7141
7142         /* create dot before error-return. for debugging */
7143         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7144
7145         MMPLAYER_FLEAVE();
7146
7147         return ret;
7148 }
7149
7150 static int __gst_unrealize(mm_player_t* player)
7151 {
7152         int ret = MM_ERROR_NONE;
7153
7154         MMPLAYER_FENTER();
7155
7156         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7157
7158         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7159         MMPLAYER_PRINT_STATE(player);
7160
7161         /* release miscellaneous information */
7162         __mmplayer_release_misc(player);
7163
7164         /* destroy pipeline */
7165         ret = __mmplayer_gst_destroy_pipeline(player);
7166         if (ret != MM_ERROR_NONE) {
7167                 LOGE("failed to destory pipeline\n");
7168                 return ret;
7169         }
7170
7171         /* release miscellaneous information.
7172            these info needs to be released after pipeline is destroyed. */
7173         __mmplayer_release_misc_post(player);
7174
7175         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7176
7177         MMPLAYER_FLEAVE();
7178
7179         return ret;
7180 }
7181
7182 static int __gst_pending_seek(mm_player_t* player)
7183 {
7184         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7185         int ret = MM_ERROR_NONE;
7186
7187         MMPLAYER_FENTER();
7188
7189         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7190
7191         if (!player->pending_seek.is_pending) {
7192                 LOGD("pending seek is not reserved. nothing to do.\n");
7193                 return ret;
7194         }
7195
7196         /* check player state if player could pending seek or not. */
7197         current_state = MMPLAYER_CURRENT_STATE(player);
7198
7199         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7200                 LOGW("try to pending seek in %s state, try next time. \n",
7201                         MMPLAYER_STATE_GET_NAME(current_state));
7202                 return ret;
7203         }
7204
7205         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7206
7207         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7208
7209         if (MM_ERROR_NONE != ret)
7210                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7211
7212         player->pending_seek.is_pending = FALSE;
7213
7214         MMPLAYER_FLEAVE();
7215
7216         return ret;
7217 }
7218
7219 static int __gst_start(mm_player_t* player)
7220 {
7221         int ret = MM_ERROR_NONE;
7222         gboolean async = FALSE;
7223
7224         MMPLAYER_FENTER();
7225
7226         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7227
7228         /* NOTE : if SetPosition was called before Start. do it now */
7229         /* streaming doesn't support it. so it should be always sync */
7230         /* !!create one more api to check if there is pending seek rather than checking variables */
7231         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
7232                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7233                 ret = __gst_pause(player, FALSE);
7234                 if (ret != MM_ERROR_NONE) {
7235                         LOGE("failed to set state to PAUSED for pending seek");
7236                         return ret;
7237                 }
7238
7239                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7240                 if (__gst_pending_seek(player) != MM_ERROR_NONE)
7241                                 LOGW("failed to seek pending postion. starting from the begin of content");
7242         }
7243
7244         LOGD("current state before doing transition");
7245         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7246         MMPLAYER_PRINT_STATE(player);
7247
7248         /* set pipeline state to PLAYING  */
7249         ret = __mmplayer_gst_set_state(player,
7250                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7251
7252         if (ret == MM_ERROR_NONE) {
7253                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7254         } else {
7255                 LOGE("failed to set state to PLAYING");
7256                 return ret;
7257         }
7258
7259         /* generating debug info before returning error */
7260         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7261
7262         MMPLAYER_FLEAVE();
7263
7264         return ret;
7265 }
7266
7267 static int __gst_stop(mm_player_t* player)
7268 {
7269         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7270         MMHandleType attrs = 0;
7271         gboolean rewind = FALSE;
7272         gint timeout = 0;
7273         int ret = MM_ERROR_NONE;
7274
7275         MMPLAYER_FENTER();
7276
7277         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7279
7280         LOGD("current state before doing transition");
7281         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7282         MMPLAYER_PRINT_STATE(player);
7283
7284         attrs = MMPLAYER_GET_ATTRS(player);
7285         if (!attrs) {
7286                 LOGE("cannot get content attribute\n");
7287                 return MM_ERROR_PLAYER_INTERNAL;
7288         }
7289
7290         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7291         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7292
7293         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7294                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7295                 rewind = TRUE;
7296
7297         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7298                 /* disable the async state transition because there could be no data in the pipeline */
7299                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
7300         }
7301
7302         /* set gst state */
7303         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
7304
7305         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7306                 /* enable the async state transition as default operation */
7307                 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
7308         }
7309
7310         /* return if set_state has failed */
7311         if (ret != MM_ERROR_NONE) {
7312                 LOGE("failed to set state.\n");
7313                 return ret;
7314         }
7315
7316         /* rewind */
7317         if (rewind) {
7318                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7319                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7320                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7321                         LOGW("failed to rewind\n");
7322                         ret = MM_ERROR_PLAYER_SEEK;
7323                 }
7324         }
7325
7326         /* initialize */
7327         player->sent_bos = FALSE;
7328
7329         if (player->es_player_push_mode) //for cloudgame
7330                 timeout = 0;
7331
7332         /* wait for seek to complete */
7333         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7334         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7335                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7336         } else {
7337                 LOGE("fail to stop player.\n");
7338                 ret = MM_ERROR_PLAYER_INTERNAL;
7339                 __mmplayer_dump_pipeline_state(player);
7340         }
7341
7342         /* generate dot file if enabled */
7343         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7344
7345         MMPLAYER_FLEAVE();
7346
7347         return ret;
7348 }
7349
7350 int __gst_pause(mm_player_t* player, gboolean async)
7351 {
7352         int ret = MM_ERROR_NONE;
7353
7354         MMPLAYER_FENTER();
7355
7356         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7357         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7358
7359         LOGD("current state before doing transition");
7360         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7361         MMPLAYER_PRINT_STATE(player);
7362
7363         /* set pipeline status to PAUSED */
7364         ret = __mmplayer_gst_set_state(player,
7365                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7366
7367         if (FALSE == async) {
7368                 if (ret != MM_ERROR_NONE) {
7369                         GstMessage *msg = NULL;
7370                         GTimer *timer = NULL;
7371                         gdouble MAX_TIMEOUT_SEC = 3;
7372
7373                         LOGE("failed to set state to PAUSED");
7374
7375                         if (!player->bus_watcher) {
7376                                 LOGE("there is no bus msg thread. pipeline is shutting down.");
7377                                 return ret;
7378                         }
7379
7380                         if (player->msg_posted) {
7381                                 LOGE("error msg is already posted.");
7382                                 return ret;
7383                         }
7384
7385                         timer = g_timer_new();
7386                         g_timer_start(timer);
7387
7388                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7389
7390                         do {
7391                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7392                                 if (msg) {
7393                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7394                                                 GError *error = NULL;
7395
7396                                                 /* parse error code */
7397                                                 gst_message_parse_error(msg, &error, NULL);
7398
7399                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7400                                                         /* Note : the streaming error from the streaming source is handled
7401                                                          *   using __mmplayer_handle_streaming_error.
7402                                                          */
7403                                                         __mmplayer_handle_streaming_error(player, msg);
7404
7405                                                 } else if (error) {
7406                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7407
7408                                                         if (error->domain == GST_STREAM_ERROR)
7409                                                                 ret = __gst_handle_stream_error(player, error, msg);
7410                                                         else if (error->domain == GST_RESOURCE_ERROR)
7411                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7412                                                         else if (error->domain == GST_LIBRARY_ERROR)
7413                                                                 ret = __gst_handle_library_error(player, error->code);
7414                                                         else if (error->domain == GST_CORE_ERROR)
7415                                                                 ret = __gst_handle_core_error(player, error->code);
7416
7417                                                         g_error_free(error);
7418                                                 }
7419                                                 player->msg_posted = TRUE;
7420                                         }
7421                                         gst_message_unref(msg);
7422                                 }
7423                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7424                         /* clean */
7425                         gst_object_unref(bus);
7426                         g_timer_stop(timer);
7427                         g_timer_destroy(timer);
7428
7429                         return ret;
7430
7431                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7432                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7433
7434                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7435
7436                 } else {
7437                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7438                 }
7439         }
7440
7441         /* generate dot file before returning error */
7442         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7443
7444         MMPLAYER_FLEAVE();
7445
7446         return ret;
7447 }
7448
7449 int __gst_resume(mm_player_t* player, gboolean async)
7450 {
7451         int ret = MM_ERROR_NONE;
7452         gint timeout = 0;
7453
7454         MMPLAYER_FENTER();
7455
7456         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7457                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7458
7459         LOGD("current state before doing transition");
7460         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7461         MMPLAYER_PRINT_STATE(player);
7462
7463         if (async)
7464                 LOGD("do async state transition to PLAYING");
7465
7466         /* set pipeline state to PLAYING */
7467         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7468
7469         ret = __mmplayer_gst_set_state(player,
7470                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7471         if (ret != MM_ERROR_NONE) {
7472                 LOGE("failed to set state to PLAYING");
7473                 goto EXIT;
7474         } else {
7475                 if (async == FALSE)
7476                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7477         }
7478
7479 EXIT:
7480         /* generate dot file */
7481         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7482
7483         MMPLAYER_FLEAVE();
7484
7485         return ret;
7486 }
7487
7488 static int
7489 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7490 {
7491         gint64 dur_nsec = 0;
7492         gint64 pos_nsec = 0;
7493         gboolean ret = TRUE;
7494         gboolean accurated = FALSE;
7495         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7496
7497         MMPLAYER_FENTER();
7498         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7499         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7500
7501         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7502                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7503                 goto PENDING;
7504
7505         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7506                 /* check duration */
7507                 /* NOTE : duration cannot be zero except live streaming.
7508                  *              Since some element could have some timing problemn with quering duration, try again.
7509                  */
7510                 if (player->duration == 0) {
7511                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7512                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7513                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7514                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7515                                         player->pending_seek.is_pending = TRUE;
7516                                         player->pending_seek.format = format;
7517                                         player->pending_seek.pos = position;
7518                                         player->seek_state = MMPLAYER_SEEK_NONE;
7519                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7520                                         return MM_ERROR_NONE;
7521                                 } else {
7522                                         goto SEEK_ERROR;
7523                                 }
7524                         }
7525                         player->duration = dur_nsec;
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 > player->duration)
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->seek_state = MMPLAYER_SEEK_NONE;
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(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
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->seek_state != MMPLAYER_SEEK_NONE) {
7579                                 LOGD("not completed seek");
7580                                 return MM_ERROR_PLAYER_DOING_SEEK;
7581                         }
7582                 }
7583
7584                 if (!internal_called)
7585                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7586
7587                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7588                         gint64 cur_time = 0;
7589
7590                         /* get current position */
7591                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7592
7593                         /* flush */
7594                         GstEvent *event = gst_event_new_seek(1.0,
7595                                                         GST_FORMAT_TIME,
7596                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7597                                                         GST_SEEK_TYPE_SET, cur_time,
7598                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7599                         if (event)
7600                                 __gst_send_event_to_sink(player, event);
7601
7602                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7603                                 __gst_pause(player, FALSE);
7604                 }
7605
7606                 pos_nsec = position;
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->seek_state = MMPLAYER_SEEK_NONE;
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.");
7628                         goto SEEK_ERROR;
7629                 }
7630         }
7631         break;
7632
7633         case MM_PLAYER_POS_FORMAT_PERCENT:
7634         {
7635                 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7636
7637                 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7638                         LOGD("not completed seek");
7639                         return MM_ERROR_PLAYER_DOING_SEEK;
7640                 }
7641
7642                 if (!internal_called)
7643                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
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. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
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         if ((!internal_called) &&
7671             (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7672                 LOGD("buffering should be reset after seeking");
7673                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7674                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
7675         }
7676
7677         MMPLAYER_FLEAVE();
7678         return MM_ERROR_NONE;
7679
7680 PENDING:
7681         player->pending_seek.is_pending = TRUE;
7682         player->pending_seek.format = format;
7683         player->pending_seek.pos = position;
7684
7685         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7686                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7687                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7688                 player->pending_seek.pos);
7689
7690         return MM_ERROR_NONE;
7691
7692 INVALID_ARGS:
7693         LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7694         return MM_ERROR_INVALID_ARGUMENT;
7695
7696 SEEK_ERROR:
7697         player->seek_state = MMPLAYER_SEEK_NONE;
7698         return MM_ERROR_PLAYER_SEEK;
7699 }
7700
7701 #define TRICKPLAY_OFFSET GST_MSECOND
7702
7703 static int
7704 __gst_get_position(mm_player_t* player, int format, gint64* position)
7705 {
7706         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7707         gint64 pos_nsec = 0;
7708         gboolean ret = TRUE;
7709
7710         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7711                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7712
7713         current_state = MMPLAYER_CURRENT_STATE(player);
7714
7715         /* NOTE : query position except paused state to overcome some bad operation
7716          * please refer to below comments in details
7717          */
7718         if (current_state != MM_PLAYER_STATE_PAUSED)
7719                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7720
7721         /* NOTE : get last point to overcome some bad operation of some elements
7722          *(returning zero when getting current position in paused state
7723          * and when failed to get postion during seeking
7724          */
7725         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7726                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7727
7728                 if (player->playback_rate < 0.0)
7729                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7730                 else
7731                         pos_nsec = player->last_position;
7732
7733                 if (!ret)
7734                         pos_nsec = player->last_position;
7735                 else
7736                         player->last_position = pos_nsec;
7737
7738                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7739
7740         } else {
7741                 if (player->duration > 0 && pos_nsec > player->duration)
7742                         pos_nsec = player->duration;
7743
7744                 player->last_position = pos_nsec;
7745         }
7746
7747         switch (format) {
7748         case MM_PLAYER_POS_FORMAT_TIME:
7749                 *position = pos_nsec;
7750                 break;
7751
7752         case MM_PLAYER_POS_FORMAT_PERCENT:
7753         {
7754                 if (player->duration <= 0) {
7755                         LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7756                         *position = 0;
7757                 } else {
7758                         LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7759                         *position = (gint64)(pos_nsec * 100 / player->duration);
7760                 }
7761                 break;
7762         }
7763         default:
7764                 return MM_ERROR_PLAYER_INTERNAL;
7765         }
7766
7767         return MM_ERROR_NONE;
7768 }
7769
7770
7771 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7772 {
7773 #define STREAMING_IS_FINISHED   0
7774 #define BUFFERING_MAX_PER       100
7775 #define DEFAULT_PER_VALUE       -1
7776 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7777
7778         MMPlayerGstElement *mainbin = NULL;
7779         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7780         gint64 buffered_total = 0;
7781         gint64 position = 0;
7782         gint buffered_sec = -1;
7783         GstBufferingMode mode = GST_BUFFERING_STREAM;
7784         gint64 content_size_time = player->duration;
7785         guint64 content_size_bytes = player->http_content_size;
7786
7787         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7788                                                 player->pipeline &&
7789                                                 player->pipeline->mainbin,
7790                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7791
7792         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7793
7794         *start_pos = 0;
7795         *stop_pos = 0;
7796
7797         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7798                 /* and rtsp is not ready yet. */
7799                 LOGW("it's only used for http streaming case.\n");
7800                 return MM_ERROR_PLAYER_NO_OP;
7801         }
7802
7803         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7804                 LOGW("Time format is not supported yet.\n");
7805                 return MM_ERROR_INVALID_ARGUMENT;
7806         }
7807
7808         if (content_size_time <= 0 || content_size_bytes <= 0) {
7809                 LOGW("there is no content size.");
7810                 return MM_ERROR_NONE;
7811         }
7812
7813         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7814                 LOGW("fail to get current position.");
7815                 return MM_ERROR_NONE;
7816         }
7817
7818         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7819                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7820
7821         mainbin = player->pipeline->mainbin;
7822         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7823
7824         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7825                 GstQuery *query = NULL;
7826                 gint byte_in_rate = 0, byte_out_rate = 0;
7827                 gint64 estimated_total = 0;
7828
7829                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7830                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7831                         LOGW("fail to get buffering query from queue2");
7832                         if (query)
7833                                 gst_query_unref(query);
7834                         return MM_ERROR_NONE;
7835                 }
7836
7837                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7838                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7839
7840                 if (mode == GST_BUFFERING_STREAM) {
7841                         /* using only queue in case of push mode(ts / mp3) */
7842                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7843                                 GST_FORMAT_BYTES, &buffered_total)) {
7844                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7845                                 stop_per = 100 * buffered_total / content_size_bytes;
7846                         }
7847                 } else {
7848                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7849                         guint idx = 0;
7850                         guint num_of_ranges = 0;
7851                         gint64 start_byte = 0, stop_byte = 0;
7852
7853                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7854                         if (estimated_total != STREAMING_IS_FINISHED) {
7855                                 /* buffered size info from queue2 */
7856                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7857                                 for (idx = 0; idx < num_of_ranges; idx++) {
7858                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7859                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7860
7861                                         buffered_total += (stop_byte - start_byte);
7862                                 }
7863                         } else
7864                                 stop_per = BUFFERING_MAX_PER;
7865                 }
7866                 gst_query_unref(query);
7867         }
7868
7869         if (stop_per == DEFAULT_PER_VALUE) {
7870                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7871                 if (dur_sec > 0) {
7872                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7873
7874                         /* buffered size info from multiqueue */
7875                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7876                                 guint curr_size_bytes = 0;
7877                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7878                                         "curr-size-bytes", &curr_size_bytes, NULL);
7879                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7880                                 buffered_total += curr_size_bytes;
7881                         }
7882
7883                         if (avg_byterate > 0)
7884                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7885                         else if (player->total_maximum_bitrate > 0)
7886                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7887                         else if (player->total_bitrate > 0)
7888                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7889
7890                         if (buffered_sec >= 0)
7891                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7892                 }
7893         }
7894
7895         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7896         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7897
7898         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7899                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7900
7901         return MM_ERROR_NONE;
7902 }
7903
7904 static int
7905 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7906 {
7907         MMPLAYER_FENTER();
7908
7909         if (!player) {
7910                 LOGW("set_message_callback is called with invalid player handle\n");
7911                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7912         }
7913
7914         player->msg_cb = callback;
7915         player->msg_cb_param = user_param;
7916
7917         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7918
7919         MMPLAYER_FLEAVE();
7920
7921         return MM_ERROR_NONE;
7922 }
7923
7924 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7925 {
7926         int ret = MM_ERROR_PLAYER_INVALID_URI;
7927         char *path = NULL;
7928
7929         MMPLAYER_FENTER();
7930
7931         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7932         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7933         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7934
7935         memset(data, 0, sizeof(MMPlayerParseProfile));
7936
7937         if ((path = strstr(uri, "es_buff://"))) {
7938                 if (strlen(path)) {
7939                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7940                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7941                         ret = MM_ERROR_NONE;
7942                 }
7943         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7944                 if (strlen(path)) {
7945                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7947                         ret = MM_ERROR_NONE;
7948                 }
7949         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7950                 if (strlen(path)) {
7951                         gchar *tmp = NULL;
7952                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7953                         tmp = g_ascii_strdown(uri, strlen(uri));
7954
7955                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7956                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7957                         else
7958                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7959
7960                         ret = MM_ERROR_NONE;
7961                         g_free(tmp);
7962                 }
7963         } else if ((path = strstr(uri, "rtspu://"))) {
7964                 if (strlen(path)) {
7965                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7966                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7967                         ret = MM_ERROR_NONE;
7968                 }
7969         } else if ((path = strstr(uri, "rtspr://"))) {
7970                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7971                 char *separater = strstr(path, "*");
7972
7973                 if (separater) {
7974                         int urgent_len = 0;
7975                         char *urgent = separater + strlen("*");
7976
7977                         if ((urgent_len = strlen(urgent))) {
7978                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7979                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7980                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7981                                 ret = MM_ERROR_NONE;
7982                         }
7983                 }
7984         } else if ((path = strstr(uri, "mms://"))) {
7985                 if (strlen(path)) {
7986                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7987                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7988                         ret = MM_ERROR_NONE;
7989                 }
7990         } else if ((path = strstr(uri, "mem://"))) {
7991                 if (strlen(path)) {
7992                         int mem_size = 0;
7993                         char *buffer = NULL;
7994                         char *seperator = strchr(path, ',');
7995                         char ext[100] = {0,}, size[100] = {0,};
7996
7997                         if (seperator) {
7998                                 if ((buffer = strstr(path, "ext="))) {
7999                                         buffer += strlen("ext=");
8000
8001                                         if (strlen(buffer)) {
8002                                                 strncpy(ext, buffer, 99);
8003
8004                                                 if ((seperator = strchr(ext, ','))
8005                                                         || (seperator = strchr(ext, ' '))
8006                                                         || (seperator = strchr(ext, '\0'))) {
8007                                                         seperator[0] = '\0';
8008                                                 }
8009                                         }
8010                                 }
8011
8012                                 if ((buffer = strstr(path, "size="))) {
8013                                         buffer += strlen("size=");
8014
8015                                         if (strlen(buffer) > 0) {
8016                                                 strncpy(size, buffer, 99);
8017
8018                                                 if ((seperator = strchr(size, ','))
8019                                                         || (seperator = strchr(size, ' '))
8020                                                         || (seperator = strchr(size, '\0'))) {
8021                                                         seperator[0] = '\0';
8022                                                 }
8023
8024                                                 mem_size = atoi(size);
8025                                         }
8026                                 }
8027                         }
8028
8029                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8030                         if (mem_size && param) {
8031                                 if (data->input_mem.buf)
8032                                         free(data->input_mem.buf);
8033                                 data->input_mem.buf = malloc(mem_size);
8034
8035                                 if (data->input_mem.buf) {
8036                                         memcpy(data->input_mem.buf, param, mem_size);
8037                                         data->input_mem.len = mem_size;
8038                                         ret = MM_ERROR_NONE;
8039                                 } else {
8040                                         LOGE("failed to alloc mem %d", mem_size);
8041                                         ret = MM_ERROR_PLAYER_INTERNAL;
8042                                 }
8043
8044                                 data->input_mem.offset = 0;
8045                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8046                         }
8047                 }
8048         } else {
8049                 gchar *location = NULL;
8050                 GError *err = NULL;
8051
8052                 if ((path = strstr(uri, "file://"))) {
8053
8054                         location = g_filename_from_uri(uri, NULL, &err);
8055
8056                         if (!location || (err != NULL)) {
8057                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8058                                  (err != NULL) ? err->message : "unknown error");
8059
8060                           if (err) g_error_free(err);
8061                           if (location) g_free(location);
8062
8063                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8064                           goto exit;
8065                         }
8066
8067                         LOGD("path from uri: %s", location);
8068                 }
8069
8070                 path = (location != NULL) ? (location) : ((char*)uri);
8071                 int file_stat = MM_ERROR_NONE;
8072
8073                 file_stat = util_exist_file_path(path);
8074
8075                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8076                 if (file_stat == MM_ERROR_NONE) {
8077                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8078
8079                         if (util_is_sdp_file(path)) {
8080                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8081                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8082                         } else {
8083                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8084                         }
8085                         ret = MM_ERROR_NONE;
8086                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8087                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8088                 } else {
8089                         LOGE("invalid uri, could not play..\n");
8090                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8091                 }
8092
8093                 if (location) g_free(location);
8094         }
8095
8096 exit:
8097         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8098                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8099         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8100                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8101
8102         /* dump parse result */
8103         SECURE_LOGW("incomming uri : %s\n", uri);
8104         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8105                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8106
8107         MMPLAYER_FLEAVE();
8108
8109         return ret;
8110 }
8111
8112 gboolean
8113 __mmplayer_can_do_interrupt(mm_player_t *player)
8114 {
8115         if (!player || !player->pipeline || !player->attrs) {
8116                 LOGW("not initialized");
8117                 goto FAILED;
8118         }
8119
8120         if (player->set_mode.pcm_extraction) {
8121                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8122                 goto FAILED;
8123         }
8124
8125         /* check if seeking */
8126         if (player->seek_state != MMPLAYER_SEEK_NONE) {
8127                 MMMessageParamType msg_param;
8128                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8129                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8130                 player->seek_state = MMPLAYER_SEEK_NONE;
8131                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8132                 goto FAILED;
8133         }
8134
8135         /* check other thread */
8136         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8137                 LOGW("locked already, cmd state : %d", player->cmd);
8138
8139                 /* check application command */
8140                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8141                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8142
8143                         /* lock will be released at mrp_resource_release_cb() */
8144                         MMPLAYER_CMD_LOCK(player);
8145                         goto INTERRUPT;
8146                 }
8147                 LOGW("nothing to do");
8148                 goto FAILED;
8149         } else {
8150                 LOGW("can interrupt immediately");
8151                 goto INTERRUPT;
8152         }
8153
8154 FAILED:    /* with CMD UNLOCKED */
8155         return FALSE;
8156
8157 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8158         return TRUE;
8159 }
8160
8161 static int
8162 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8163                 void *user_data)
8164 {
8165         mm_player_t *player = NULL;
8166
8167         MMPLAYER_FENTER();
8168
8169         if (user_data == NULL) {
8170                 LOGE("- user_data is null\n");
8171                 return FALSE;
8172         }
8173         player = (mm_player_t *)user_data;
8174
8175         /* do something to release resource here.
8176          * player stop and interrupt forwarding */
8177         if (!__mmplayer_can_do_interrupt(player)) {
8178                 LOGW("no need to interrupt, so leave");
8179         } else {
8180                 MMMessageParamType msg = {0, };
8181                 gint64 pos = 0;
8182
8183                 player->interrupted_by_resource = TRUE;
8184
8185                 /* get last play position */
8186                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8187                         LOGW("failed to get play position.");
8188                 } else {
8189                         msg.union_type = MM_MSG_UNION_TIME;
8190                         msg.time.elapsed = pos;
8191                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8192                 }
8193                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8194                 if (_mmplayer_unrealize((MMHandleType)player))
8195                         LOGW("failed to unrealize");
8196
8197                 /* lock is called in __mmplayer_can_do_interrupt() */
8198                 MMPLAYER_CMD_UNLOCK(player);
8199         }
8200
8201         if (res == player->video_overlay_resource)
8202                 player->video_overlay_resource = FALSE;
8203         else
8204                 player->video_decoder_resource = FALSE;
8205
8206         MMPLAYER_FLEAVE();
8207
8208         return FALSE;
8209 }
8210
8211 int
8212 _mmplayer_create_player(MMHandleType handle)
8213 {
8214         int ret = MM_ERROR_PLAYER_INTERNAL;
8215         bool enabled = false;
8216
8217         mm_player_t* player = MM_PLAYER_CAST(handle);
8218
8219         MMPLAYER_FENTER();
8220
8221         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8222
8223         /* initialize player state */
8224         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8225         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8226         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8227         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8228
8229         /* check current state */
8230         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8231
8232         /* construct attributes */
8233         player->attrs = _mmplayer_construct_attribute(handle);
8234
8235         if (!player->attrs) {
8236                 LOGE("Failed to construct attributes\n");
8237                 return ret;
8238         }
8239
8240         /* initialize gstreamer with configured parameter */
8241         if (!__mmplayer_init_gstreamer(player)) {
8242                 LOGE("Initializing gstreamer failed\n");
8243                 _mmplayer_deconstruct_attribute(handle);
8244                 return ret;
8245         }
8246
8247         /* create lock. note that g_tread_init() has already called in gst_init() */
8248         g_mutex_init(&player->fsink_lock);
8249
8250         /* create update tag lock */
8251         g_mutex_init(&player->update_tag_lock);
8252
8253         /* create next play mutex */
8254         g_mutex_init(&player->next_play_thread_mutex);
8255
8256         /* create next play cond */
8257         g_cond_init(&player->next_play_thread_cond);
8258
8259         /* create next play thread */
8260         player->next_play_thread =
8261                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8262         if (!player->next_play_thread) {
8263                 LOGE("failed to create next play thread");
8264                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8265                 g_mutex_clear(&player->next_play_thread_mutex);
8266                 g_cond_clear(&player->next_play_thread_cond);
8267                 goto ERROR;
8268         }
8269
8270         player->bus_msg_q = g_queue_new();
8271         if (!player->bus_msg_q) {
8272                 LOGE("failed to create queue for bus_msg");
8273                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8274                 goto ERROR;
8275         }
8276
8277         ret = _mmplayer_initialize_video_capture(player);
8278         if (ret != MM_ERROR_NONE) {
8279                 LOGE("failed to initialize video capture\n");
8280                 goto ERROR;
8281         }
8282
8283         /* initialize resource manager */
8284         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8285                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8286                         &player->resource_manager)) {
8287                 LOGE("failed to initialize resource manager\n");
8288                 goto ERROR;
8289         }
8290
8291         if (MMPLAYER_IS_HTTP_PD(player)) {
8292                 player->pd_downloader = NULL;
8293                 player->pd_file_save_path = NULL;
8294         }
8295
8296         /* create video bo lock and cond */
8297         g_mutex_init(&player->video_bo_mutex);
8298         g_cond_init(&player->video_bo_cond);
8299
8300         /* create media stream callback mutex */
8301         g_mutex_init(&player->media_stream_cb_lock);
8302
8303         /* create subtitle info lock and cond */
8304         g_mutex_init(&player->subtitle_info_mutex);
8305         g_cond_init(&player->subtitle_info_cond);
8306
8307         player->streaming_type = STREAMING_SERVICE_NONE;
8308
8309         /* give default value of audio effect setting */
8310         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8311         player->sound.rg_enable = false;
8312         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8313
8314         player->play_subtitle = FALSE;
8315         player->use_deinterleave = FALSE;
8316         player->max_audio_channels = 0;
8317         player->video_share_api_delta = 0;
8318         player->video_share_clock_delta = 0;
8319         player->has_closed_caption = FALSE;
8320         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8321         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8322         player->pending_resume = FALSE;
8323         if (player->ini.dump_element_keyword[0][0] == '\0')
8324                 player->ini.set_dump_element_flag = FALSE;
8325         else
8326                 player->ini.set_dump_element_flag = TRUE;
8327
8328         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8329         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8330         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8331
8332         /* Set video360 settings to their defaults for just-created player.
8333          * */
8334
8335         player->is_360_feature_enabled = FALSE;
8336         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8337                 LOGI("spherical feature info: %d", enabled);
8338                 if (enabled)
8339                         player->is_360_feature_enabled = TRUE;
8340         } else {
8341                 LOGE("failed to get spherical feature info");
8342         }
8343
8344         player->is_content_spherical = FALSE;
8345         player->is_video360_enabled = TRUE;
8346         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8347         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8348         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8349         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8350         player->video360_zoom = 1.0f;
8351         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8352         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8353
8354         /* set player state to null */
8355         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8356         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8357
8358         return MM_ERROR_NONE;
8359
8360 ERROR:
8361         /* free lock */
8362         g_mutex_clear(&player->fsink_lock);
8363
8364         /* free update tag lock */
8365         g_mutex_clear(&player->update_tag_lock);
8366
8367         g_queue_free(player->bus_msg_q);
8368
8369         /* free next play thread */
8370         if (player->next_play_thread) {
8371                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8372                 player->next_play_thread_exit = TRUE;
8373                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8374                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8375
8376                 g_thread_join(player->next_play_thread);
8377                 player->next_play_thread = NULL;
8378
8379                 g_mutex_clear(&player->next_play_thread_mutex);
8380                 g_cond_clear(&player->next_play_thread_cond);
8381         }
8382
8383         /* release attributes */
8384         _mmplayer_deconstruct_attribute(handle);
8385
8386         MMPLAYER_FLEAVE();
8387
8388         return ret;
8389 }
8390
8391 static gboolean
8392 __mmplayer_init_gstreamer(mm_player_t* player)
8393 {
8394         static gboolean initialized = FALSE;
8395         static const int max_argc = 50;
8396         gint* argc = NULL;
8397         gchar** argv = NULL;
8398         gchar** argv2 = NULL;
8399         GError *err = NULL;
8400         int i = 0;
8401         int arg_count = 0;
8402
8403         if (initialized) {
8404                 LOGD("gstreamer already initialized.\n");
8405                 return TRUE;
8406         }
8407
8408         /* alloc */
8409         argc = malloc(sizeof(int));
8410         argv = malloc(sizeof(gchar*) * max_argc);
8411         argv2 = malloc(sizeof(gchar*) * max_argc);
8412
8413         if (!argc || !argv || !argv2)
8414                 goto ERROR;
8415
8416         memset(argv, 0, sizeof(gchar*) * max_argc);
8417         memset(argv2, 0, sizeof(gchar*) * max_argc);
8418
8419         /* add initial */
8420         *argc = 1;
8421         argv[0] = g_strdup("mmplayer");
8422
8423         /* add gst_param */
8424         for (i = 0; i < 5; i++) {
8425                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8426                 if (strlen(player->ini.gst_param[i]) > 0) {
8427                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8428                         (*argc)++;
8429                 }
8430         }
8431
8432         /* we would not do fork for scanning plugins */
8433         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8434         (*argc)++;
8435
8436         /* check disable registry scan */
8437         if (player->ini.skip_rescan) {
8438                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8439                 (*argc)++;
8440         }
8441
8442         /* check disable segtrap */
8443         if (player->ini.disable_segtrap) {
8444                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8445                 (*argc)++;
8446         }
8447
8448         LOGD("initializing gstreamer with following parameter\n");
8449         LOGD("argc : %d\n", *argc);
8450         arg_count = *argc;
8451
8452         for (i = 0; i < arg_count; i++) {
8453                 argv2[i] = argv[i];
8454                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8455         }
8456
8457         /* initializing gstreamer */
8458         if (!gst_init_check(argc, &argv, &err)) {
8459                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8460                 if (err)
8461                         g_error_free(err);
8462
8463                 goto ERROR;
8464         }
8465         /* release */
8466         for (i = 0; i < arg_count; i++) {
8467                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8468                 MMPLAYER_FREEIF(argv2[i]);
8469         }
8470
8471         MMPLAYER_FREEIF(argv);
8472         MMPLAYER_FREEIF(argv2);
8473         MMPLAYER_FREEIF(argc);
8474
8475         /* done */
8476         initialized = TRUE;
8477
8478         return TRUE;
8479
8480 ERROR:
8481
8482         /* release */
8483         for (i = 0; i < arg_count; i++) {
8484                 LOGD("free[%d] : %s\n", i, argv2[i]);
8485                 MMPLAYER_FREEIF(argv2[i]);
8486         }
8487
8488         MMPLAYER_FREEIF(argv);
8489         MMPLAYER_FREEIF(argv2);
8490         MMPLAYER_FREEIF(argc);
8491
8492         return FALSE;
8493 }
8494
8495 int
8496 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8497 {
8498         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8499
8500         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8501                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8502                 MMPLAYER_FREEIF(player->pd_file_save_path);
8503         }
8504
8505         return MM_ERROR_NONE;
8506 }
8507
8508 static void
8509 __mmplayer_check_async_state_transition(mm_player_t* player)
8510 {
8511         GstState element_state = GST_STATE_VOID_PENDING;
8512         GstState element_pending_state = GST_STATE_VOID_PENDING;
8513         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8514         GstElement * element = NULL;
8515         gboolean async = FALSE;
8516
8517         /* check player handle */
8518         MMPLAYER_RETURN_IF_FAIL(player &&
8519                                                 player->pipeline &&
8520                                                 player->pipeline->mainbin &&
8521                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8522
8523         if (player->attrs)
8524                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8525
8526         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8527                 LOGD("don't need to check the pipeline state");
8528                 return;
8529         }
8530
8531         MMPLAYER_PRINT_STATE(player);
8532
8533         /* wait for state transition */
8534         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8535         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8536
8537         if (ret == GST_STATE_CHANGE_FAILURE) {
8538                 LOGE(" [%s] state : %s   pending : %s \n",
8539                         GST_ELEMENT_NAME(element),
8540                         gst_element_state_get_name(element_state),
8541                         gst_element_state_get_name(element_pending_state));
8542
8543                 /* dump state of all element */
8544                 __mmplayer_dump_pipeline_state(player);
8545
8546                 return;
8547         }
8548
8549         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8550         return;
8551 }
8552
8553 int
8554 _mmplayer_destroy(MMHandleType handle)
8555 {
8556         mm_player_t* player = MM_PLAYER_CAST(handle);
8557
8558         MMPLAYER_FENTER();
8559
8560         /* check player handle */
8561         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8562
8563         /* destroy can called at anytime */
8564         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8565
8566         /* check async state transition */
8567         __mmplayer_check_async_state_transition(player);
8568
8569         __mmplayer_destroy_streaming_ext(player);
8570
8571         /* release next play thread */
8572         if (player->next_play_thread) {
8573                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8574                 player->next_play_thread_exit = TRUE;
8575                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8576                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8577
8578                 LOGD("waitting for next play thread exit\n");
8579                 g_thread_join(player->next_play_thread);
8580                 g_mutex_clear(&player->next_play_thread_mutex);
8581                 g_cond_clear(&player->next_play_thread_cond);
8582                 LOGD("next play thread released\n");
8583         }
8584
8585         _mmplayer_release_video_capture(player);
8586
8587         /* de-initialize resource manager */
8588         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8589                         player->resource_manager))
8590                 LOGE("failed to deinitialize resource manager\n");
8591
8592         /* release pipeline */
8593         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8594                 LOGE("failed to destory pipeline\n");
8595                 return MM_ERROR_PLAYER_INTERNAL;
8596         }
8597
8598         g_queue_free(player->bus_msg_q);
8599
8600         /* release subtitle info lock and cond */
8601         g_mutex_clear(&player->subtitle_info_mutex);
8602         g_cond_clear(&player->subtitle_info_cond);
8603
8604         __mmplayer_release_dump_list(player->dump_list);
8605
8606         /* release miscellaneous information */
8607         __mmplayer_release_misc(player);
8608
8609         /* release miscellaneous information.
8610            these info needs to be released after pipeline is destroyed. */
8611         __mmplayer_release_misc_post(player);
8612
8613         /* release attributes */
8614         _mmplayer_deconstruct_attribute(handle);
8615
8616         /* release lock */
8617         g_mutex_clear(&player->fsink_lock);
8618
8619         /* release lock */
8620         g_mutex_clear(&player->update_tag_lock);
8621
8622         /* release video bo lock and cond */
8623         g_mutex_clear(&player->video_bo_mutex);
8624         g_cond_clear(&player->video_bo_cond);
8625
8626         /* release media stream callback lock */
8627         g_mutex_clear(&player->media_stream_cb_lock);
8628
8629         MMPLAYER_FLEAVE();
8630
8631         return MM_ERROR_NONE;
8632 }
8633
8634 int
8635 __mmplayer_realize_streaming_ext(mm_player_t* player)
8636 {
8637         int ret = MM_ERROR_NONE;
8638
8639         MMPLAYER_FENTER();
8640         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8641
8642         if (MMPLAYER_IS_HTTP_PD(player)) {
8643                 gboolean bret = FALSE;
8644
8645                 player->pd_downloader = _mmplayer_create_pd_downloader();
8646                 if (!player->pd_downloader) {
8647                         LOGE("Unable to create PD Downloader...");
8648                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8649                 }
8650
8651                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8652
8653                 if (FALSE == bret) {
8654                         LOGE("Unable to create PD Downloader...");
8655                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8656                 }
8657         }
8658
8659         MMPLAYER_FLEAVE();
8660         return ret;
8661 }
8662
8663 int
8664 _mmplayer_realize(MMHandleType hplayer)
8665 {
8666         mm_player_t* player = (mm_player_t*)hplayer;
8667         char *uri = NULL;
8668         void *param = NULL;
8669         MMHandleType attrs = 0;
8670         int ret = MM_ERROR_NONE;
8671
8672         MMPLAYER_FENTER();
8673
8674         /* check player handle */
8675         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8676
8677         /* check current state */
8678         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8679
8680         attrs = MMPLAYER_GET_ATTRS(player);
8681         if (!attrs) {
8682                 LOGE("fail to get attributes.\n");
8683                 return MM_ERROR_PLAYER_INTERNAL;
8684         }
8685         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8686         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8687
8688         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8689                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8690
8691                 if (ret != MM_ERROR_NONE) {
8692                         LOGE("failed to parse profile\n");
8693                         return ret;
8694                 }
8695         }
8696
8697         if (uri && (strstr(uri, "es_buff://"))) {
8698                 if (strstr(uri, "es_buff://push_mode"))
8699                         player->es_player_push_mode = TRUE;
8700                 else
8701                         player->es_player_push_mode = FALSE;
8702         }
8703
8704         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8705                 LOGW("mms protocol is not supported format.\n");
8706                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8707         }
8708
8709         if (MMPLAYER_IS_STREAMING(player))
8710                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8711         else
8712                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8713
8714         player->smooth_streaming = FALSE;
8715         player->videodec_linked  = 0;
8716         player->videosink_linked = 0;
8717         player->audiodec_linked  = 0;
8718         player->audiosink_linked = 0;
8719         player->textsink_linked = 0;
8720         player->is_external_subtitle_present = FALSE;
8721         player->is_external_subtitle_added_now = FALSE;
8722         /* set the subtitle ON default */
8723         player->is_subtitle_off = FALSE;
8724
8725         /* realize pipeline */
8726         ret = __gst_realize(player);
8727         if (ret != MM_ERROR_NONE)
8728                 LOGE("fail to realize the player.\n");
8729         else
8730                 ret = __mmplayer_realize_streaming_ext(player);
8731
8732         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8733
8734         MMPLAYER_FLEAVE();
8735
8736         return ret;
8737 }
8738
8739 int
8740 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8741 {
8742         MMPLAYER_FENTER();
8743         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8744
8745         /* destroy can called at anytime */
8746         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8747                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8748
8749         MMPLAYER_FLEAVE();
8750         return MM_ERROR_NONE;
8751 }
8752
8753 int
8754 _mmplayer_unrealize(MMHandleType hplayer)
8755 {
8756         mm_player_t* player = (mm_player_t*)hplayer;
8757         int ret = MM_ERROR_NONE;
8758
8759         MMPLAYER_FENTER();
8760
8761         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8762
8763         MMPLAYER_CMD_UNLOCK(player);
8764         /* destroy the gst bus msg thread which is created during realize.
8765            this funct have to be called before getting cmd lock. */
8766         _mmplayer_bus_msg_thread_destroy(player);
8767         MMPLAYER_CMD_LOCK(player);
8768
8769         /* check current state */
8770         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8771
8772         /* check async state transition */
8773         __mmplayer_check_async_state_transition(player);
8774
8775         __mmplayer_unrealize_streaming_ext(player);
8776
8777         /* unrealize pipeline */
8778         ret = __gst_unrealize(player);
8779
8780         /* set asm stop if success */
8781         if (MM_ERROR_NONE == ret) {
8782                 if (!player->interrupted_by_resource) {
8783                         if (player->video_decoder_resource != NULL) {
8784                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8785                                                 player->video_decoder_resource);
8786                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8787                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8788                                 else
8789                                         player->video_decoder_resource = NULL;
8790                         }
8791
8792                         if (player->video_overlay_resource != NULL) {
8793                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8794                                                 player->video_overlay_resource);
8795                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8796                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8797                                 else
8798                                         player->video_overlay_resource = NULL;
8799                         }
8800
8801                         ret = mm_resource_manager_commit(player->resource_manager);
8802                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8803                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8804                 }
8805         } else
8806                 LOGE("failed and don't change asm state to stop");
8807
8808         MMPLAYER_FLEAVE();
8809
8810         return ret;
8811 }
8812
8813 int
8814 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8815 {
8816         mm_player_t* player = (mm_player_t*)hplayer;
8817
8818         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8819
8820         return __gst_set_message_callback(player, callback, user_param);
8821 }
8822
8823 int
8824 _mmplayer_get_state(MMHandleType hplayer, int* state)
8825 {
8826         mm_player_t *player = (mm_player_t*)hplayer;
8827
8828         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8829
8830         *state = MMPLAYER_CURRENT_STATE(player);
8831
8832         return MM_ERROR_NONE;
8833 }
8834
8835
8836 int
8837 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8838 {
8839         mm_player_t* player = (mm_player_t*) hplayer;
8840         GstElement* vol_element = NULL;
8841         int i = 0;
8842
8843         MMPLAYER_FENTER();
8844
8845         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8846
8847         LOGD("volume [L]=%f:[R]=%f\n",
8848                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8849
8850         /* invalid factor range or not */
8851         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8852                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8853                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8854                         return MM_ERROR_INVALID_ARGUMENT;
8855                 }
8856         }
8857
8858         /* not support to set other value into each channel */
8859         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8860                 return MM_ERROR_INVALID_ARGUMENT;
8861
8862         /* Save volume to handle. Currently the first array element will be saved. */
8863         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8864
8865         /* check pipeline handle */
8866         if (!player->pipeline || !player->pipeline->audiobin) {
8867                 LOGD("audiobin is not created yet\n");
8868                 LOGD("but, current stored volume will be set when it's created.\n");
8869
8870                 /* NOTE : stored volume will be used in create_audiobin
8871                  * returning MM_ERROR_NONE here makes application to able to
8872                  * set volume at anytime.
8873                  */
8874                 return MM_ERROR_NONE;
8875         }
8876
8877         /* setting volume to volume element */
8878         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8879
8880         if (vol_element) {
8881                 LOGD("volume is set [%f]\n", player->sound.volume);
8882                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8883         }
8884
8885         MMPLAYER_FLEAVE();
8886
8887         return MM_ERROR_NONE;
8888 }
8889
8890
8891 int
8892 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8893 {
8894         mm_player_t* player = (mm_player_t*) hplayer;
8895         int i = 0;
8896
8897         MMPLAYER_FENTER();
8898
8899         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8900         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8901
8902         /* returning stored volume */
8903         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8904                 volume->level[i] = player->sound.volume;
8905
8906         MMPLAYER_FLEAVE();
8907
8908         return MM_ERROR_NONE;
8909 }
8910
8911 int
8912 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8913 {
8914         mm_player_t* player = (mm_player_t*) hplayer;
8915         GstElement* vol_element = NULL;
8916
8917         MMPLAYER_FENTER();
8918
8919         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8920
8921         /* mute value shoud 0 or 1 */
8922         if (mute != 0 && mute != 1) {
8923                 LOGE("bad mute value\n");
8924
8925                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8926                 return MM_ERROR_INVALID_ARGUMENT;
8927         }
8928
8929         player->sound.mute = mute;
8930
8931         /* just hold mute value if pipeline is not ready */
8932         if (!player->pipeline || !player->pipeline->audiobin) {
8933                 LOGD("pipeline is not ready. holding mute value\n");
8934                 return MM_ERROR_NONE;
8935         }
8936
8937         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8938
8939         /* NOTE : volume will only created when the bt is enabled */
8940         if (vol_element) {
8941                 LOGD("mute : %d\n", mute);
8942                 g_object_set(vol_element, "mute", mute, NULL);
8943         } else
8944                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8945
8946         MMPLAYER_FLEAVE();
8947
8948         return MM_ERROR_NONE;
8949 }
8950
8951 int
8952 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8953 {
8954         mm_player_t* player = (mm_player_t*) hplayer;
8955
8956         MMPLAYER_FENTER();
8957
8958         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8959         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8960
8961         /* just hold mute value if pipeline is not ready */
8962         if (!player->pipeline || !player->pipeline->audiobin) {
8963                 LOGD("pipeline is not ready. returning stored value\n");
8964                 *pmute = player->sound.mute;
8965                 return MM_ERROR_NONE;
8966         }
8967
8968         *pmute = player->sound.mute;
8969
8970         MMPLAYER_FLEAVE();
8971
8972         return MM_ERROR_NONE;
8973 }
8974
8975 int
8976 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8977 {
8978         mm_player_t* player = (mm_player_t*) hplayer;
8979
8980         MMPLAYER_FENTER();
8981
8982         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8983
8984         player->video_stream_changed_cb = callback;
8985         player->video_stream_changed_cb_user_param = user_param;
8986         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8987
8988         MMPLAYER_FLEAVE();
8989
8990         return MM_ERROR_NONE;
8991 }
8992
8993 int
8994 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8995 {
8996         mm_player_t* player = (mm_player_t*) hplayer;
8997
8998         MMPLAYER_FENTER();
8999
9000         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9001
9002         player->audio_stream_changed_cb = callback;
9003         player->audio_stream_changed_cb_user_param = user_param;
9004         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9005
9006         MMPLAYER_FLEAVE();
9007
9008         return MM_ERROR_NONE;
9009 }
9010
9011 int
9012 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9013 {
9014         mm_player_t* player = (mm_player_t*) hplayer;
9015
9016         MMPLAYER_FENTER();
9017
9018         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9019
9020         player->audio_stream_render_cb_ex = callback;
9021         player->audio_stream_cb_user_param = user_param;
9022         player->audio_stream_sink_sync = sync;
9023         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);
9024
9025         MMPLAYER_FLEAVE();
9026
9027         return MM_ERROR_NONE;
9028 }
9029
9030 int
9031 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9032 {
9033         mm_player_t* player = (mm_player_t*) hplayer;
9034
9035         MMPLAYER_FENTER();
9036
9037         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9038
9039         if (callback && !player->bufmgr)
9040                 player->bufmgr = tbm_bufmgr_init(-1);
9041
9042         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9043         player->video_stream_cb = callback;
9044         player->video_stream_cb_user_param = user_param;
9045
9046         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9047
9048         MMPLAYER_FLEAVE();
9049
9050         return MM_ERROR_NONE;
9051 }
9052
9053 int
9054 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9055 {
9056         mm_player_t* player = (mm_player_t*) hplayer;
9057
9058         MMPLAYER_FENTER();
9059
9060         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9061
9062         player->audio_stream_cb = callback;
9063         player->audio_stream_cb_user_param = user_param;
9064         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9065
9066         MMPLAYER_FLEAVE();
9067
9068         return MM_ERROR_NONE;
9069 }
9070
9071 static int
9072 __mmplayer_start_streaming_ext(mm_player_t *player)
9073 {
9074         gint ret = MM_ERROR_NONE;
9075
9076         MMPLAYER_FENTER();
9077         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9078
9079         if (MMPLAYER_IS_HTTP_PD(player)) {
9080                 if (!player->pd_downloader) {
9081                         ret = __mmplayer_realize_streaming_ext(player);
9082
9083                         if (ret != MM_ERROR_NONE) {
9084                                 LOGE("failed to realize streaming ext\n");
9085                                 return ret;
9086                         }
9087                 }
9088
9089                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9090                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9091                         if (!ret) {
9092                                 LOGE("ERROR while starting PD...\n");
9093                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9094                         }
9095                         ret = MM_ERROR_NONE;
9096                 }
9097         }
9098
9099         MMPLAYER_FLEAVE();
9100         return ret;
9101 }
9102
9103 int
9104 _mmplayer_start(MMHandleType hplayer)
9105 {
9106         mm_player_t* player = (mm_player_t*) hplayer;
9107         gint ret = MM_ERROR_NONE;
9108
9109         MMPLAYER_FENTER();
9110
9111         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9112
9113         /* check current state */
9114         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9115
9116         /* PD - start streaming */
9117         ret = __mmplayer_start_streaming_ext(player);
9118         if (ret != MM_ERROR_NONE) {
9119                 LOGE("failed to start streaming ext 0x%X", ret);
9120                 return ret;
9121         }
9122
9123         /* start pipeline */
9124         ret = __gst_start(player);
9125         if (ret != MM_ERROR_NONE)
9126                 LOGE("failed to start player.\n");
9127
9128         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9129                 LOGD("force playing start even during buffering");
9130                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9131         }
9132
9133         MMPLAYER_FLEAVE();
9134
9135         return ret;
9136 }
9137
9138 /* NOTE: post "not supported codec message" to application
9139  * when one codec is not found during AUTOPLUGGING in MSL.
9140  * So, it's separated with error of __mmplayer_gst_callback().
9141  * And, if any codec is not found, don't send message here.
9142  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9143  */
9144 int
9145 __mmplayer_handle_missed_plugin(mm_player_t* player)
9146 {
9147         MMMessageParamType msg_param;
9148         memset(&msg_param, 0, sizeof(MMMessageParamType));
9149         gboolean post_msg_direct = FALSE;
9150
9151         MMPLAYER_FENTER();
9152
9153         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9154
9155         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9156                         player->not_supported_codec, player->can_support_codec);
9157
9158         if (player->not_found_demuxer) {
9159                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9160                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9161
9162                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9163                 MMPLAYER_FREEIF(msg_param.data);
9164
9165                 return MM_ERROR_NONE;
9166         }
9167
9168         if (player->not_supported_codec) {
9169                 if (player->can_support_codec) {
9170                         // There is one codec to play
9171                         post_msg_direct = TRUE;
9172                 } else {
9173                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9174                                 post_msg_direct = TRUE;
9175                 }
9176
9177                 if (post_msg_direct) {
9178                         MMMessageParamType msg_param;
9179                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9180
9181                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9182                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9183
9184                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9185                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9186                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9187                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9188
9189                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9190                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9191                         }
9192
9193                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9194
9195                         MMPLAYER_FREEIF(msg_param.data);
9196
9197                         return MM_ERROR_NONE;
9198                 } else {
9199                         // no any supported codec case
9200                         LOGW("not found any codec, posting error code to application.\n");
9201
9202                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9203                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9204                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9205                         } else {
9206                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9207                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9208                         }
9209
9210                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9211
9212                         MMPLAYER_FREEIF(msg_param.data);
9213                 }
9214         }
9215
9216         MMPLAYER_FLEAVE();
9217
9218         return MM_ERROR_NONE;
9219 }
9220
9221 static void __mmplayer_check_pipeline(mm_player_t* player)
9222 {
9223         GstState element_state = GST_STATE_VOID_PENDING;
9224         GstState element_pending_state = GST_STATE_VOID_PENDING;
9225         gint timeout = 0;
9226         int ret = MM_ERROR_NONE;
9227
9228         if (player->gapless.reconfigure) {
9229                 LOGW("pipeline is under construction.\n");
9230
9231                 MMPLAYER_PLAYBACK_LOCK(player);
9232                 MMPLAYER_PLAYBACK_UNLOCK(player);
9233
9234                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9235
9236                 /* wait for state transition */
9237                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9238
9239                 if (ret == GST_STATE_CHANGE_FAILURE)
9240                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9241         }
9242 }
9243
9244 /* NOTE : it should be able to call 'stop' anytime*/
9245 int
9246 _mmplayer_stop(MMHandleType hplayer)
9247 {
9248         mm_player_t* player = (mm_player_t*)hplayer;
9249         int ret = MM_ERROR_NONE;
9250
9251         MMPLAYER_FENTER();
9252
9253         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9254
9255         /* check current state */
9256         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9257
9258         /* check pipline building state */
9259         __mmplayer_check_pipeline(player);
9260         __mmplayer_reset_gapless_state(player);
9261
9262         /* NOTE : application should not wait for EOS after calling STOP */
9263         __mmplayer_cancel_eos_timer(player);
9264
9265         __mmplayer_unrealize_streaming_ext(player);
9266
9267         /* reset */
9268         player->seek_state = MMPLAYER_SEEK_NONE;
9269
9270         /* stop pipeline */
9271         ret = __gst_stop(player);
9272
9273         if (ret != MM_ERROR_NONE)
9274                 LOGE("failed to stop player.\n");
9275
9276         MMPLAYER_FLEAVE();
9277
9278         return ret;
9279 }
9280
9281 int
9282 _mmplayer_pause(MMHandleType hplayer)
9283 {
9284         mm_player_t* player = (mm_player_t*)hplayer;
9285         gint64 pos_nsec = 0;
9286         gboolean async = FALSE;
9287         gint ret = MM_ERROR_NONE;
9288
9289         MMPLAYER_FENTER();
9290
9291         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9292
9293         /* check current state */
9294         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9295
9296         /* check pipline building state */
9297         __mmplayer_check_pipeline(player);
9298
9299         switch (MMPLAYER_CURRENT_STATE(player)) {
9300         case MM_PLAYER_STATE_READY:
9301                 {
9302                         /* check prepare async or not.
9303                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9304                          */
9305                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9306                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9307
9308                         /* Changing back sync of rtspsrc to async */
9309                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9310                                 LOGD("async prepare working mode for rtsp");
9311                                 async = TRUE;
9312                         }
9313                 }
9314                 break;
9315
9316         case MM_PLAYER_STATE_PLAYING:
9317                 {
9318                         /* NOTE : store current point to overcome some bad operation
9319                         *(returning zero when getting current position in paused state) of some
9320                         * elements
9321                         */
9322                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9323                                 LOGW("getting current position failed in paused\n");
9324
9325                         player->last_position = pos_nsec;
9326
9327                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9328                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9329                            This causes problem is position calculation during normal pause resume scenarios also.
9330                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9331                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9332                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9333                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9334                         }
9335                 }
9336                 break;
9337         }
9338
9339         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9340                 LOGD("doing async pause in case of ms buff src");
9341                 async = TRUE;
9342         }
9343
9344         /* pause pipeline */
9345         ret = __gst_pause(player, async);
9346
9347         if (ret != MM_ERROR_NONE)
9348                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9349
9350         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9351                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9352                         LOGE("failed to update display_rotation");
9353         }
9354
9355         MMPLAYER_FLEAVE();
9356
9357         return ret;
9358 }
9359
9360 /* in case of streaming, pause could take long time.*/
9361 int
9362 _mmplayer_abort_pause(MMHandleType hplayer)
9363 {
9364         mm_player_t* player = (mm_player_t*)hplayer;
9365         int ret = MM_ERROR_NONE;
9366
9367         MMPLAYER_FENTER();
9368
9369         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
9370                                                 player->pipeline &&
9371                                                 player->pipeline->mainbin,
9372                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
9373
9374         LOGD("set the pipeline state to READY");
9375
9376         /* set state to READY */
9377         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9378                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
9379         if (ret != MM_ERROR_NONE) {
9380                 LOGE("fail to change state to READY");
9381                 return MM_ERROR_PLAYER_INTERNAL;
9382         }
9383
9384         LOGD("succeeded in changing state to READY");
9385         return ret;
9386 }
9387
9388
9389 int
9390 _mmplayer_resume(MMHandleType hplayer)
9391 {
9392         mm_player_t* player = (mm_player_t*)hplayer;
9393         int ret = MM_ERROR_NONE;
9394         gboolean async = FALSE;
9395
9396         MMPLAYER_FENTER();
9397
9398         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9399
9400         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9401                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
9402                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
9403                         return ret;
9404                 }
9405
9406                 /* Changing back sync mode rtspsrc to async */
9407                 LOGD("async resume for rtsp case");
9408                 async = TRUE;
9409         }
9410
9411         /* check current state */
9412         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9413
9414         ret = __gst_resume(player, async);
9415         if (ret != MM_ERROR_NONE)
9416                 LOGE("failed to resume player.\n");
9417
9418         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9419                 LOGD("force resume even during buffering");
9420                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9421         }
9422
9423         MMPLAYER_FLEAVE();
9424
9425         return ret;
9426 }
9427
9428 int
9429 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9430 {
9431         mm_player_t* player = (mm_player_t*)hplayer;
9432         gint64 pos_nsec = 0;
9433         int ret = MM_ERROR_NONE;
9434         int mute = FALSE;
9435         signed long long start = 0, stop = 0;
9436         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9437         MMPLAYER_FENTER();
9438
9439         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9440         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9441
9442         /* The sound of video is not supported under 0.0 and over 2.0. */
9443         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9444                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9445                         mute = TRUE;
9446         }
9447         _mmplayer_set_mute(hplayer, mute);
9448
9449         if (player->playback_rate == rate)
9450                 return MM_ERROR_NONE;
9451
9452         /* If the position is reached at start potion during fast backward, EOS is posted.
9453          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9454          * */
9455         player->playback_rate = rate;
9456
9457         current_state = MMPLAYER_CURRENT_STATE(player);
9458
9459         if (current_state != MM_PLAYER_STATE_PAUSED)
9460                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9461
9462         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9463
9464         if ((current_state == MM_PLAYER_STATE_PAUSED)
9465                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9466                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9467                 pos_nsec = player->last_position;
9468         }
9469
9470         if (rate >= 0) {
9471                 start = pos_nsec;
9472                 stop = GST_CLOCK_TIME_NONE;
9473         } else {
9474                 start = GST_CLOCK_TIME_NONE;
9475                 stop = pos_nsec;
9476         }
9477
9478         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9479                                 player->playback_rate,
9480                                 GST_FORMAT_TIME,
9481                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9482                                 GST_SEEK_TYPE_SET, start,
9483                                 GST_SEEK_TYPE_SET, stop)) {
9484                 LOGE("failed to set speed playback\n");
9485                 return MM_ERROR_PLAYER_SEEK;
9486         }
9487
9488         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9489
9490         MMPLAYER_FLEAVE();
9491
9492         return MM_ERROR_NONE;;
9493 }
9494
9495 int
9496 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9497 {
9498         mm_player_t* player = (mm_player_t*)hplayer;
9499         int ret = MM_ERROR_NONE;
9500
9501         MMPLAYER_FENTER();
9502
9503         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9504
9505         /* check pipline building state */
9506         __mmplayer_check_pipeline(player);
9507
9508         ret = __gst_set_position(player, format, position, FALSE);
9509
9510         MMPLAYER_FLEAVE();
9511
9512         return ret;
9513 }
9514
9515 int
9516 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9517 {
9518         mm_player_t* player = (mm_player_t*)hplayer;
9519         int ret = MM_ERROR_NONE;
9520
9521         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9522
9523         ret = __gst_get_position(player, format, position);
9524
9525         return ret;
9526 }
9527
9528 int
9529 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9530 {
9531         mm_player_t* player = (mm_player_t*)hplayer;
9532         int ret = MM_ERROR_NONE;
9533
9534         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9535         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9536
9537         *duration = player->duration;
9538         return ret;
9539 }
9540
9541 int
9542 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
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_buffer_position(player, format, start_pos, stop_pos);
9550
9551         return ret;
9552 }
9553
9554 int
9555 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9556 {
9557         mm_player_t* player = (mm_player_t*)hplayer;
9558         int ret = MM_ERROR_NONE;
9559
9560         MMPLAYER_FENTER();
9561
9562         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9563
9564         ret = __gst_adjust_subtitle_position(player, format, position);
9565
9566         MMPLAYER_FLEAVE();
9567
9568         return ret;
9569 }
9570
9571 static gboolean
9572 __mmplayer_is_midi_type(gchar* str_caps)
9573 {
9574         if ((g_strrstr(str_caps, "audio/midi")) ||
9575                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9576                 (g_strrstr(str_caps, "application/x-smaf")) ||
9577                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9578                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9579                 (g_strrstr(str_caps, "audio/xmf")) ||
9580                 (g_strrstr(str_caps, "audio/mxmf"))) {
9581                 LOGD("midi\n");
9582                 return TRUE;
9583         }
9584
9585         return FALSE;
9586 }
9587
9588 static gboolean
9589 __mmplayer_is_only_mp3_type(gchar *str_caps)
9590 {
9591         if (g_strrstr(str_caps, "application/x-id3") ||
9592                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9593                 return TRUE;
9594         return FALSE;
9595 }
9596
9597 static void
9598 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9599 {
9600         GstStructure* caps_structure = NULL;
9601         gint samplerate = 0;
9602         gint channels = 0;
9603
9604         MMPLAYER_FENTER();
9605         MMPLAYER_RETURN_IF_FAIL(player && caps);
9606
9607         caps_structure = gst_caps_get_structure(caps, 0);
9608
9609         /* set stream information */
9610         gst_structure_get_int(caps_structure, "rate", &samplerate);
9611         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9612
9613         gst_structure_get_int(caps_structure, "channels", &channels);
9614         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9615
9616         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9617 }
9618
9619 static void
9620 __mmplayer_update_content_type_info(mm_player_t* player)
9621 {
9622         MMPLAYER_FENTER();
9623         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9624
9625         if (__mmplayer_is_midi_type(player->type)) {
9626                 player->bypass_audio_effect = TRUE;
9627         } else if (g_strrstr(player->type, "application/x-hls")) {
9628                 /* If it can't know exact type when it parses uri because of redirection case,
9629                  * it will be fixed by typefinder or when doing autoplugging.
9630                  */
9631                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9632                 if (player->streamer) {
9633                         player->streamer->is_adaptive_streaming = TRUE;
9634                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9635                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9636                 }
9637         } else if (g_strrstr(player->type, "application/dash+xml")) {
9638                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9639                 if (player->streamer) {
9640                         player->streamer->is_adaptive_streaming = TRUE;
9641                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9642                 }
9643         }
9644
9645         LOGD("uri type : %d", player->profile.uri_type);
9646         MMPLAYER_FLEAVE();
9647 }
9648
9649 static void
9650 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9651 GstCaps *caps, gpointer data)
9652 {
9653         mm_player_t* player = (mm_player_t*)data;
9654         GstPad* pad = NULL;
9655
9656         MMPLAYER_FENTER();
9657
9658         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9659
9660         /* store type string */
9661         MMPLAYER_FREEIF(player->type);
9662         player->type = gst_caps_to_string(caps);
9663         if (player->type) {
9664                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9665                                 player, player->type, probability, gst_caps_get_size(caps));
9666         }
9667
9668         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9669                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9670                 LOGE("not support media format\n");
9671
9672                 if (player->msg_posted == FALSE) {
9673                         MMMessageParamType msg_param;
9674                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9675
9676                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9677                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9678
9679                         /* don't post more if one was sent already */
9680                         player->msg_posted = TRUE;
9681                 }
9682                 return;
9683         }
9684
9685         __mmplayer_update_content_type_info(player);
9686
9687         pad = gst_element_get_static_pad(tf, "src");
9688         if (!pad) {
9689                 LOGE("fail to get typefind src pad.\n");
9690                 return;
9691         }
9692
9693         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9694                 gboolean async = FALSE;
9695                 LOGE("failed to autoplug %s\n", player->type);
9696
9697                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9698
9699                 if (async && player->msg_posted == FALSE)
9700                         __mmplayer_handle_missed_plugin(player);
9701
9702                 goto DONE;
9703         }
9704
9705 DONE:
9706         gst_object_unref(GST_OBJECT(pad));
9707
9708         MMPLAYER_FLEAVE();
9709
9710         return;
9711 }
9712
9713 static GstElement *
9714 __mmplayer_create_decodebin(mm_player_t* player)
9715 {
9716         GstElement *decodebin = NULL;
9717
9718         MMPLAYER_FENTER();
9719
9720         /* create decodebin */
9721         decodebin = gst_element_factory_make("decodebin", NULL);
9722
9723         if (!decodebin) {
9724                 LOGE("fail to create decodebin\n");
9725                 goto ERROR;
9726         }
9727
9728         /* raw pad handling signal */
9729         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9730                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9731
9732         /* no-more-pad pad handling signal */
9733         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9734                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9735
9736         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9737                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9738
9739         /* This signal is emitted when a pad for which there is no further possible
9740            decoding is added to the decodebin.*/
9741         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9742                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9743
9744         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9745            before looking for any elements that can handle that stream.*/
9746         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9747                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9748
9749         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9750            before looking for any elements that can handle that stream.*/
9751         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9752                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9753
9754         /* This signal is emitted once decodebin has finished decoding all the data.*/
9755         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9756                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9757
9758         /* This signal is emitted when a element is added to the bin.*/
9759         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9760                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9761
9762 ERROR:
9763         return decodebin;
9764 }
9765
9766 static gboolean
9767 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9768 {
9769         MMPlayerGstElement* mainbin = NULL;
9770         GstElement* decodebin = NULL;
9771         GstElement* queue2 = NULL;
9772         GstPad* sinkpad = NULL;
9773         GstPad* qsrcpad = NULL;
9774         gint64 dur_bytes = 0L;
9775
9776         guint max_buffer_size_bytes = 0;
9777         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9778
9779         MMPLAYER_FENTER();
9780         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9781
9782         mainbin = player->pipeline->mainbin;
9783
9784         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9785                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9786                 LOGD("creating http streaming buffering queue(queue2)\n");
9787
9788                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9789                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9790                 } else {
9791                         queue2 = gst_element_factory_make("queue2", "queue2");
9792                         if (!queue2) {
9793                                 LOGE("failed to create buffering queue element\n");
9794                                 goto ERROR;
9795                         }
9796
9797                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9798                                 LOGE("failed to add buffering queue\n");
9799                                 goto ERROR;
9800                         }
9801
9802                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9803                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9804
9805                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9806                                 LOGE("failed to link buffering queue");
9807                                 goto ERROR;
9808                         }
9809
9810                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9811                                 LOGE("fail to get duration");
9812
9813                         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9814
9815                         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9816
9817                         if (dur_bytes > 0) {
9818                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9819                                         type = MUXED_BUFFER_TYPE_FILE;
9820                                 } else {
9821                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9822                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9823                                 }
9824                         } else {
9825                                 dur_bytes = 0;
9826                         }
9827
9828                         /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9829                          *        skip the pull mode(file or ring buffering) setting. */
9830                         if (!g_strrstr(player->type, "video/mpegts")) {
9831                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9832                                 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9833
9834                                 __mm_player_streaming_set_queue2(player->streamer,
9835                                                                                                 queue2,
9836                                                                                                 FALSE,
9837                                                                                                 max_buffer_size_bytes,
9838                                                                                                 player->ini.http_buffering_time,
9839                                                                                                 1.0,                                /* no meaning */
9840                                                                                                 player->ini.http_buffering_limit,   /* no meaning */
9841                                                                                                 type,
9842                                                                                                 player->http_file_buffering_path,
9843                                                                                                 (guint64)dur_bytes);
9844                         }
9845
9846                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9847                                 LOGE("failed to sync queue2 state with parent\n");
9848                                 goto ERROR;
9849                         }
9850
9851                         srcpad = qsrcpad;
9852
9853                         gst_object_unref(GST_OBJECT(sinkpad));
9854
9855                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9856                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9857                 }
9858         }
9859
9860         /* create decodebin */
9861         decodebin = __mmplayer_create_decodebin(player);
9862
9863         if (!decodebin) {
9864                 LOGE("can not create autoplug element\n");
9865                 goto ERROR;
9866         }
9867
9868         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9869                 LOGE("failed to add decodebin\n");
9870                 goto ERROR;
9871         }
9872
9873         /* to force caps on the decodebin element and avoid reparsing stuff by
9874         * typefind. It also avoids a deadlock in the way typefind activates pads in
9875         * the state change */
9876         g_object_set(decodebin, "sink-caps", caps, NULL);
9877
9878         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9879
9880         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9881                 LOGE("failed to link decodebin\n");
9882                 goto ERROR;
9883         }
9884
9885         gst_object_unref(GST_OBJECT(sinkpad));
9886
9887         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9888         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9889
9890         /* set decodebin property about buffer in streaming playback. *
9891          * in case of HLS/DASH, it does not need to have big buffer   *
9892          * because it is kind of adaptive streaming.                  */
9893         if (!MMPLAYER_IS_HTTP_PD(player) &&
9894             (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9895             gdouble high_percent = 0.0;
9896
9897                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9898                 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9899
9900                 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9901                         GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9902
9903                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9904                                                                                         "high-percent", (gint)high_percent,
9905                                                                                         "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9906                                                                                         "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9907                                                                                         "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9908                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9909         }
9910
9911         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9912                 LOGE("failed to sync decodebin state with parent\n");
9913                 goto ERROR;
9914         }
9915
9916         MMPLAYER_FLEAVE();
9917
9918         return TRUE;
9919
9920 ERROR:
9921
9922         if (sinkpad)
9923                 gst_object_unref(GST_OBJECT(sinkpad));
9924
9925         if (queue2) {
9926                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9927                  * You need to explicitly set elements to the NULL state before
9928                  * dropping the final reference, to allow them to clean up.
9929                  */
9930                 gst_element_set_state(queue2, GST_STATE_NULL);
9931
9932                 /* And, it still has a parent "player".
9933                  * You need to let the parent manage the object instead of unreffing the object directly.
9934                  */
9935                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9936                 gst_object_unref(queue2);
9937                 queue2 = NULL;
9938         }
9939
9940         if (decodebin) {
9941                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9942                  * You need to explicitly set elements to the NULL state before
9943                  * dropping the final reference, to allow them to clean up.
9944                  */
9945                 gst_element_set_state(decodebin, GST_STATE_NULL);
9946
9947                 /* And, it still has a parent "player".
9948                  * You need to let the parent manage the object instead of unreffing the object directly.
9949                  */
9950
9951                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9952                 gst_object_unref(decodebin);
9953                 decodebin = NULL;
9954         }
9955
9956         return FALSE;
9957 }
9958
9959 static int
9960 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9961 {
9962         MMPLAYER_FENTER();
9963
9964         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9965         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9966
9967         LOGD("class : %s, mime : %s \n", factory_class, mime);
9968
9969         /* add missing plugin */
9970         /* NOTE : msl should check missing plugin for image mime type.
9971          * Some motion jpeg clips can have playable audio track.
9972          * So, msl have to play audio after displaying popup written video format not supported.
9973          */
9974         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9975                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9976                         LOGD("not found demuxer\n");
9977                         player->not_found_demuxer = TRUE;
9978                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9979
9980                         goto DONE;
9981                 }
9982         }
9983
9984         if (!g_strrstr(factory_class, "Demuxer")) {
9985                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9986                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9987                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9988
9989                         /* check that clip have multi tracks or not */
9990                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9991                                 LOGD("video plugin is already linked\n");
9992                         } else {
9993                                 LOGW("add VIDEO to missing plugin\n");
9994                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9995                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9996                         }
9997                 } else if (g_str_has_prefix(mime, "audio")) {
9998                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9999                                 LOGD("audio plugin is already linked\n");
10000                         } else {
10001                                 LOGW("add AUDIO to missing plugin\n");
10002                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10003                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10004                         }
10005                 }
10006         }
10007
10008 DONE:
10009         MMPLAYER_FLEAVE();
10010
10011         return MM_ERROR_NONE;
10012 }
10013
10014
10015 static void
10016 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10017 {
10018         mm_player_t* player = (mm_player_t*)data;
10019
10020         MMPLAYER_FENTER();
10021
10022         MMPLAYER_RETURN_IF_FAIL(player);
10023
10024         /* remove fakesink. */
10025         if (!__mmplayer_gst_remove_fakesink(player,
10026                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10027                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10028                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10029                  * source element are not same. To overcome this situation, this function will called
10030                  * several places and several times. Therefore, this is not an error case.
10031                  */
10032                 return;
10033         }
10034
10035         LOGD("[handle: %p] pipeline has completely constructed", player);
10036
10037         if ((player->ini.async_start) &&
10038                 (player->msg_posted == FALSE) &&
10039                 (player->cmd >= MMPLAYER_COMMAND_START))
10040                 __mmplayer_handle_missed_plugin(player);
10041
10042         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10043 }
10044
10045 static gboolean
10046 __mmplayer_verify_next_play_path(mm_player_t *player)
10047 {
10048         MMHandleType attrs = 0;
10049         MMPlayerParseProfile profile;
10050         gint uri_idx = 0, check_cnt = 0;
10051         char *uri = NULL;
10052         gint mode = MM_PLAYER_PD_MODE_NONE;
10053         gint video = 0;
10054         gint count = 0;
10055         gint gapless = 0;
10056         guint num_of_list = 0;
10057         static int profile_tv = -1;
10058
10059         MMPLAYER_FENTER();
10060
10061         LOGD("checking for gapless play");
10062
10063         if (player->pipeline->textbin) {
10064                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10065                 goto ERROR;
10066         }
10067
10068         attrs = MMPLAYER_GET_ATTRS(player);
10069         if (!attrs) {
10070                 LOGE("fail to get attributes.\n");
10071                 goto ERROR;
10072         }
10073
10074         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10075
10076         if (__builtin_expect(profile_tv == -1, 0)) {
10077                 char *profileName;
10078                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10079                 switch (*profileName) {
10080                 case 't':
10081                 case 'T':
10082                         profile_tv = 1;
10083                         break;
10084                 default:
10085                         profile_tv = 0;
10086                 }
10087                 free(profileName);
10088         }
10089         /* gapless playback is not supported in case of video at TV profile. */
10090         if (profile_tv && video) {
10091                 LOGW("not support video gapless playback");
10092                 goto ERROR;
10093         }
10094
10095         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10096                 if (mode == TRUE) {
10097                         LOGW("pd mode\n");
10098                         goto ERROR;
10099                 }
10100         }
10101
10102         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10103                 LOGE("can not get play count\n");
10104
10105         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10106                 LOGE("can not get gapless mode\n");
10107
10108         if (video && !gapless) {
10109                 LOGW("not enabled video gapless playback");
10110                 goto ERROR;
10111         }
10112
10113         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10114                 gapless = 1;
10115
10116         if (!gapless) {
10117                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10118                 goto ERROR;
10119         }
10120
10121         num_of_list = g_list_length(player->uri_info.uri_list);
10122
10123         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10124
10125         if (num_of_list == 0) {
10126                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10127                         LOGE("can not get profile_uri\n");
10128                         goto ERROR;
10129                 }
10130
10131                 if (!uri) {
10132                         LOGE("uri list is empty.\n");
10133                         goto ERROR;
10134                 }
10135
10136                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10137                 LOGD("add original path : %s ", uri);
10138
10139                 num_of_list = 1;
10140                 uri = NULL;
10141         }
10142
10143         uri_idx = player->uri_info.uri_idx;
10144
10145         while (TRUE) {
10146                 check_cnt++;
10147
10148                 if (check_cnt > num_of_list) {
10149                         LOGE("there is no valid uri.");
10150                         goto ERROR;
10151                 }
10152
10153                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10154
10155                 if (uri_idx < num_of_list-1) {
10156                         uri_idx++;
10157                 } else {
10158                         if ((count <= 1) && (count != -1)) {
10159                                 LOGD("no repeat.");
10160                                 goto ERROR;
10161                         } else if (count > 1) {
10162                                 /* decrease play count */
10163                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10164                                 count--;
10165
10166                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10167
10168                                 /* commit attribute */
10169                                 if (mmf_attrs_commit(attrs))
10170                                         LOGE("failed to commit attribute\n");
10171                         }
10172
10173                         /* count < 0 : repeat continually */
10174                         uri_idx = 0;
10175                 }
10176
10177                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10178                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10179
10180                 if (uri == NULL) {
10181                         LOGW("next uri does not exist\n");
10182                         continue;
10183                 }
10184
10185                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10186                         LOGE("failed to parse profile\n");
10187                         continue;
10188                 }
10189
10190                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10191                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10192                         LOGW("uri type is not supported(%d).", profile.uri_type);
10193                         continue;
10194                 }
10195
10196                 break;
10197         }
10198
10199         player->uri_info.uri_idx = uri_idx;
10200         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10201
10202         if (mmf_attrs_commit(player->attrs)) {
10203                 LOGE("failed to commit.\n");
10204                 goto ERROR;
10205         }
10206
10207         LOGD("next uri %s(%d)\n", uri, uri_idx);
10208
10209         return TRUE;
10210
10211 ERROR:
10212
10213         LOGE("unable to play next path. EOS will be posted soon.\n");
10214         return FALSE;
10215 }
10216
10217 static void
10218 __mmplayer_initialize_next_play(mm_player_t *player)
10219 {
10220         int i;
10221
10222         MMPLAYER_FENTER();
10223
10224         player->smooth_streaming = FALSE;
10225         player->videodec_linked = 0;
10226         player->audiodec_linked = 0;
10227         player->videosink_linked = 0;
10228         player->audiosink_linked = 0;
10229         player->textsink_linked = 0;
10230         player->is_external_subtitle_present = FALSE;
10231         player->is_external_subtitle_added_now = FALSE;
10232         player->not_supported_codec = MISSING_PLUGIN_NONE;
10233         player->can_support_codec = FOUND_PLUGIN_NONE;
10234         player->pending_seek.is_pending = FALSE;
10235         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10236         player->pending_seek.pos = 0;
10237         player->msg_posted = FALSE;
10238         player->has_many_types = FALSE;
10239         player->no_more_pad = FALSE;
10240         player->not_found_demuxer = 0;
10241         player->seek_state = MMPLAYER_SEEK_NONE;
10242         player->max_audio_channels = 0;
10243         player->is_subtitle_force_drop = FALSE;
10244         player->play_subtitle = FALSE;
10245         player->adjust_subtitle_pos = 0;
10246
10247         player->total_bitrate = 0;
10248         player->total_maximum_bitrate = 0;
10249
10250         _mmplayer_track_initialize(player);
10251         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10252
10253         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10254                 player->bitrate[i] = 0;
10255                 player->maximum_bitrate[i] = 0;
10256         }
10257
10258         if (player->v_stream_caps) {
10259                 gst_caps_unref(player->v_stream_caps);
10260                 player->v_stream_caps = NULL;
10261         }
10262
10263         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10264
10265         /* clean found parsers */
10266         if (player->parsers) {
10267                 GList *parsers = player->parsers;
10268                 for (; parsers; parsers = g_list_next(parsers)) {
10269                         gchar *name = parsers->data;
10270                         MMPLAYER_FREEIF(name);
10271                 }
10272                 g_list_free(player->parsers);
10273                 player->parsers = NULL;
10274         }
10275
10276         /* clean found audio decoders */
10277         if (player->audio_decoders) {
10278                 GList *a_dec = player->audio_decoders;
10279                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10280                         gchar *name = a_dec->data;
10281                         MMPLAYER_FREEIF(name);
10282                 }
10283                 g_list_free(player->audio_decoders);
10284                 player->audio_decoders = NULL;
10285         }
10286
10287         MMPLAYER_FLEAVE();
10288 }
10289
10290 static void
10291 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10292 {
10293         MMPlayerGstElement *mainbin = NULL;
10294         MMMessageParamType msg_param = {0,};
10295         GstElement *element = NULL;
10296         MMHandleType attrs = 0;
10297         char *uri = NULL;
10298         enum MainElementID elemId = MMPLAYER_M_NUM;
10299
10300         MMPLAYER_FENTER();
10301
10302         if ((player == NULL) ||
10303                 (player->pipeline == NULL) ||
10304                 (player->pipeline->mainbin == NULL)) {
10305                 LOGE("player is null.\n");
10306                 goto ERROR;
10307         }
10308
10309         mainbin = player->pipeline->mainbin;
10310         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10311
10312         attrs = MMPLAYER_GET_ATTRS(player);
10313         if (!attrs) {
10314                 LOGE("fail to get attributes.\n");
10315                 goto ERROR;
10316         }
10317
10318         /* Initialize Player values */
10319         __mmplayer_initialize_next_play(player);
10320
10321         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10322
10323         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10324                 LOGE("failed to parse profile\n");
10325                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10326                 goto ERROR;
10327         }
10328
10329         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10330                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10331                 LOGE("it's dash or hls. not support.");
10332                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10333                 goto ERROR;
10334         }
10335
10336         /* setup source */
10337         switch (player->profile.uri_type) {
10338         /* file source */
10339         case MM_PLAYER_URI_TYPE_FILE:
10340         {
10341                 LOGD("using filesrc for 'file://' handler.\n");
10342                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10343                         LOGE("failed to get storage info");
10344                         break;
10345                 }
10346
10347                 element = gst_element_factory_make("filesrc", "source");
10348
10349                 if (!element) {
10350                         LOGE("failed to create filesrc\n");
10351                         break;
10352                 }
10353
10354                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10355                 break;
10356         }
10357         case MM_PLAYER_URI_TYPE_URL_HTTP:
10358         {
10359                 gchar *user_agent, *cookies, **cookie_list;
10360                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10361                 user_agent = cookies = NULL;
10362                 cookie_list = NULL;
10363
10364                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10365                 if (!element) {
10366                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10367                         break;
10368                 }
10369                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10370
10371                 /* get attribute */
10372                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10373                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10374
10375                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10376                         LOGD("get timeout from ini\n");
10377                         http_timeout = player->ini.http_timeout;
10378                 }
10379
10380                 /* get attribute */
10381                 SECURE_LOGD("location : %s\n", player->profile.uri);
10382                 SECURE_LOGD("cookies : %s\n", cookies);
10383                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10384                 LOGD("timeout : %d\n", http_timeout);
10385
10386                 /* setting property to streaming source */
10387                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10388                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10389                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10390
10391                 /* parsing cookies */
10392                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10393                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10394                 if (user_agent)
10395                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10396                 break;
10397         }
10398         default:
10399                 LOGE("not support uri type %d\n", player->profile.uri_type);
10400                 break;
10401         }
10402
10403         if (!element) {
10404                 LOGE("no source element was created.\n");
10405                 goto ERROR;
10406         }
10407
10408         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10409                 LOGE("failed to add source element to pipeline\n");
10410                 gst_object_unref(GST_OBJECT(element));
10411                 element = NULL;
10412                 goto ERROR;
10413         }
10414
10415         /* take source element */
10416         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10417         mainbin[MMPLAYER_M_SRC].gst = element;
10418
10419         element = NULL;
10420
10421         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10422                 if (player->streamer == NULL) {
10423                         player->streamer = __mm_player_streaming_create();
10424                         __mm_player_streaming_initialize(player->streamer);
10425                 }
10426
10427                 elemId = MMPLAYER_M_TYPEFIND;
10428                 element = gst_element_factory_make("typefind", "typefinder");
10429                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10430                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10431         } else {
10432                 elemId = MMPLAYER_M_AUTOPLUG;
10433                 element = __mmplayer_create_decodebin(player);
10434         }
10435
10436         /* check autoplug element is OK */
10437         if (!element) {
10438                 LOGE("can not create element(%d)\n", elemId);
10439                 goto ERROR;
10440         }
10441
10442         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10443                 LOGE("failed to add sinkbin to pipeline\n");
10444                 gst_object_unref(GST_OBJECT(element));
10445                 element = NULL;
10446                 goto ERROR;
10447         }
10448
10449         mainbin[elemId].id = elemId;
10450         mainbin[elemId].gst = element;
10451
10452         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10453                 LOGE("Failed to link src - autoplug(or typefind)\n");
10454                 goto ERROR;
10455         }
10456
10457         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10458                 LOGE("Failed to change state of src element\n");
10459                 goto ERROR;
10460         }
10461
10462         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10463                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10464                         LOGE("Failed to change state of decodebin\n");
10465                         goto ERROR;
10466                 }
10467         } else {
10468                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10469                         LOGE("Failed to change state of src element\n");
10470                         goto ERROR;
10471                 }
10472         }
10473
10474         player->gapless.stream_changed = TRUE;
10475         player->gapless.running = TRUE;
10476         MMPLAYER_FLEAVE();
10477         return;
10478
10479 ERROR:
10480         if (player) {
10481                 MMPLAYER_PLAYBACK_UNLOCK(player);
10482
10483                 if (!player->msg_posted) {
10484                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10485                         player->msg_posted = TRUE;
10486                 }
10487         }
10488         return;
10489 }
10490
10491 static gboolean
10492 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10493 {
10494         mm_player_selector_t *selector = &player->selector[type];
10495         MMPlayerGstElement *sinkbin = NULL;
10496         enum MainElementID selectorId = MMPLAYER_M_NUM;
10497         enum MainElementID sinkId = MMPLAYER_M_NUM;
10498         GstPad *srcpad = NULL;
10499         GstPad *sinkpad = NULL;
10500         gboolean send_notice = FALSE;
10501
10502         MMPLAYER_FENTER();
10503         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10504
10505         LOGD("type %d", type);
10506
10507         switch (type) {
10508         case MM_PLAYER_TRACK_TYPE_AUDIO:
10509                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10510                 sinkId = MMPLAYER_A_BIN;
10511                 sinkbin = player->pipeline->audiobin;
10512                 break;
10513         case MM_PLAYER_TRACK_TYPE_VIDEO:
10514                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10515                 sinkId = MMPLAYER_V_BIN;
10516                 sinkbin = player->pipeline->videobin;
10517                 send_notice = TRUE;
10518                 break;
10519         case MM_PLAYER_TRACK_TYPE_TEXT:
10520                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10521                 sinkId = MMPLAYER_T_BIN;
10522                 sinkbin = player->pipeline->textbin;
10523                 break;
10524         default:
10525                 LOGE("requested type is not supportable");
10526                 return FALSE;
10527                 break;
10528         }
10529
10530         if (player->pipeline->mainbin[selectorId].gst) {
10531                 gint n;
10532
10533                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10534
10535                 if (selector->event_probe_id != 0)
10536                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10537                 selector->event_probe_id = 0;
10538
10539                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10540                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10541
10542                         if (srcpad && sinkpad) {
10543                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10544                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10545                                 gst_pad_unlink(srcpad, sinkpad);
10546
10547                                 /* send custom event to sink pad to handle it at video sink */
10548                                 if (send_notice) {
10549                                         LOGD("send custom event to sinkpad");
10550                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10551                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10552                                         gst_pad_send_event(sinkpad, event);
10553                                 }
10554                         }
10555
10556                         gst_object_unref(sinkpad);
10557                         sinkpad = NULL;
10558                 }
10559                 gst_object_unref(srcpad);
10560                 srcpad = NULL;
10561
10562                 LOGD("selector release");
10563
10564                 /* release and unref requests pad from the selector */
10565                 for (n = 0; n < selector->channels->len; n++) {
10566                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10567                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10568                 }
10569                 g_ptr_array_set_size(selector->channels, 0);
10570
10571                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10572                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10573
10574                 player->pipeline->mainbin[selectorId].gst = NULL;
10575                 selector = NULL;
10576         }
10577
10578         return TRUE;
10579 }
10580
10581 static void
10582 __mmplayer_deactivate_old_path(mm_player_t *player)
10583 {
10584         MMPLAYER_FENTER();
10585         MMPLAYER_RETURN_IF_FAIL(player);
10586
10587         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10588                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10589                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10590                 LOGE("deactivate selector error");
10591                 goto ERROR;
10592         }
10593
10594         _mmplayer_track_destroy(player);
10595         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10596
10597         if (player->streamer) {
10598                 __mm_player_streaming_deinitialize(player->streamer);
10599                 __mm_player_streaming_destroy(player->streamer);
10600                 player->streamer = NULL;
10601         }
10602
10603         MMPLAYER_PLAYBACK_LOCK(player);
10604         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10605
10606         MMPLAYER_FLEAVE();
10607         return;
10608
10609 ERROR:
10610
10611         if (!player->msg_posted) {
10612                 MMMessageParamType msg = {0,};
10613
10614                 /*post error*/
10615                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10616                 LOGE("next_uri_play> deactivate error");
10617
10618                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10619                 player->msg_posted = TRUE;
10620         }
10621         return;
10622 }
10623
10624 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10625 {
10626         int result = MM_ERROR_NONE;
10627         mm_player_t* player = (mm_player_t*) hplayer;
10628         MMPLAYER_FENTER();
10629
10630         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10631
10632         if (file_path) {
10633                 player->http_file_buffering_path = (gchar*)file_path;
10634                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10635         }
10636         MMPLAYER_FLEAVE();
10637         return result;
10638 }
10639
10640 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10641 {
10642         int result = MM_ERROR_NONE;
10643         mm_player_t* player = (mm_player_t*) hplayer;
10644         MMPLAYER_FENTER();
10645
10646         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10647
10648         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10649         if (mmf_attrs_commit(player->attrs)) {
10650                 LOGE("failed to commit the original uri.\n");
10651                 result = MM_ERROR_PLAYER_INTERNAL;
10652         } else {
10653                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10654                         LOGE("failed to add the original uri in the uri list.\n");
10655         }
10656
10657         MMPLAYER_FLEAVE();
10658         return result;
10659 }
10660
10661 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10662 {
10663         mm_player_t* player = (mm_player_t*) hplayer;
10664         guint num_of_list = 0;
10665
10666         MMPLAYER_FENTER();
10667
10668         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10669         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10670
10671         if (player->pipeline && player->pipeline->textbin) {
10672                 LOGE("subtitle path is enabled.\n");
10673                 return MM_ERROR_PLAYER_INVALID_STATE;
10674         }
10675
10676         num_of_list = g_list_length(player->uri_info.uri_list);
10677
10678         if (is_first_path == TRUE) {
10679                 if (num_of_list == 0) {
10680                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10681                         LOGD("add original path : %s", uri);
10682                 } else {
10683                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10684                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10685
10686                         LOGD("change original path : %s", uri);
10687                 }
10688         } else {
10689                 MMHandleType attrs = 0;
10690                 attrs = MMPLAYER_GET_ATTRS(player);
10691
10692                 if (num_of_list == 0) {
10693                         char *original_uri = NULL;
10694
10695                         if (attrs) {
10696                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10697
10698                                 if (!original_uri) {
10699                                         LOGE("there is no original uri.");
10700                                         return MM_ERROR_PLAYER_INVALID_STATE;
10701                                 }
10702
10703                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10704                                 player->uri_info.uri_idx = 0;
10705
10706                                 LOGD("add original path at first : %s(%d)", original_uri);
10707                         }
10708                 }
10709
10710                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10711                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10712         }
10713
10714         MMPLAYER_FLEAVE();
10715         return MM_ERROR_NONE;
10716 }
10717
10718 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10719 {
10720         mm_player_t* player = (mm_player_t*) hplayer;
10721         char *next_uri = NULL;
10722         guint num_of_list = 0;
10723
10724         MMPLAYER_FENTER();
10725         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10726
10727         num_of_list = g_list_length(player->uri_info.uri_list);
10728
10729         if (num_of_list > 0) {
10730                 gint uri_idx = player->uri_info.uri_idx;
10731
10732                 if (uri_idx < num_of_list-1)
10733                         uri_idx++;
10734                 else
10735                         uri_idx = 0;
10736
10737                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10738                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10739
10740                 *uri = g_strdup(next_uri);
10741         }
10742
10743         MMPLAYER_FLEAVE();
10744         return MM_ERROR_NONE;
10745 }
10746
10747 static void
10748 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10749 GstCaps *caps, gpointer data)
10750 {
10751         mm_player_t* player = (mm_player_t*)data;
10752         const gchar* klass = NULL;
10753         const gchar* mime = NULL;
10754         gchar* caps_str = NULL;
10755
10756         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10757         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10758         caps_str = gst_caps_to_string(caps);
10759
10760         LOGW("unknown type of caps : %s from %s",
10761                                         caps_str, GST_ELEMENT_NAME(elem));
10762
10763         MMPLAYER_FREEIF(caps_str);
10764
10765         /* There is no available codec. */
10766         __mmplayer_check_not_supported_codec(player, klass, mime);
10767 }
10768
10769 static gboolean
10770 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10771 GstCaps * caps,  gpointer data)
10772 {
10773         mm_player_t* player = (mm_player_t*)data;
10774         const char* mime = NULL;
10775         gboolean ret = TRUE;
10776
10777         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10778         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10779
10780         if (g_str_has_prefix(mime, "audio")) {
10781                 GstStructure* caps_structure = NULL;
10782                 gint samplerate = 0;
10783                 gint channels = 0;
10784                 gchar *caps_str = NULL;
10785
10786                 caps_structure = gst_caps_get_structure(caps, 0);
10787                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10788                 gst_structure_get_int(caps_structure, "channels", &channels);
10789
10790                 if ((channels > 0 && samplerate == 0)) {
10791                         LOGD("exclude audio...");
10792                         ret = FALSE;
10793                 }
10794
10795                 caps_str = gst_caps_to_string(caps);
10796                 /* set it directly because not sent by TAG */
10797                 if (g_strrstr(caps_str, "mobile-xmf"))
10798                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10799                 MMPLAYER_FREEIF(caps_str);
10800         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10801                 MMMessageParamType msg_param;
10802                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10803                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10804                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10805                 LOGD("video file is not supported on this device");
10806                 ret = FALSE;
10807         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10808                 LOGD("already video linked");
10809                 ret = FALSE;
10810         } else {
10811                 LOGD("found new stream");
10812         }
10813
10814         return ret;
10815 }
10816
10817 static int
10818 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10819 {
10820         int ret = MM_ERROR_NONE;
10821         int idx = 0;
10822         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10823
10824         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10825                 GstStructure* str = NULL;
10826                 gint channels = 0;
10827                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10828
10829                 LOGD("audio codec type: %d", codec_type);
10830                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10831                         /* sw codec will be skipped */
10832                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10833                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10834                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10835                                         ret = MM_ERROR_PLAYER_INTERNAL;
10836                                         goto DONE;
10837                                 }
10838                         }
10839                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10840                         /* hw codec will be skipped */
10841                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10842                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10843                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10844                                 ret = MM_ERROR_PLAYER_INTERNAL;
10845                                 goto DONE;
10846                         }
10847                 }
10848
10849                 str = gst_caps_get_structure(caps, 0);
10850                 if (str) {
10851                         gst_structure_get_int(str, "channels", &channels);
10852
10853                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10854                         if (player->max_audio_channels < channels)
10855                                 player->max_audio_channels = channels;
10856                 }
10857                 /* set stream information */
10858                 if (!player->audiodec_linked)
10859                         __mmplayer_set_audio_attrs(player, caps);
10860
10861                 /* update codec info */
10862                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10863                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10864                 player->audiodec_linked = 1;
10865
10866         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10867
10868                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10869
10870                 LOGD("video codec type: %d", codec_type);
10871                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10872                         /* sw codec is skipped */
10873                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10874                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10875                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10876                                         ret = MM_ERROR_PLAYER_INTERNAL;
10877                                         goto DONE;
10878                                 }
10879                         }
10880                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10881                         /* hw codec is skipped */
10882                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10883                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10884                                 ret = MM_ERROR_PLAYER_INTERNAL;
10885                                 goto DONE;
10886                         }
10887                 }
10888
10889                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10890                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10891
10892                         /* mark video decoder for acquire */
10893                         if (player->video_decoder_resource == NULL) {
10894                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10895                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10896                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10897                                                 &player->video_decoder_resource)
10898                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10899                                         LOGE("could not mark video_decoder resource for acquire");
10900                                         ret = MM_ERROR_PLAYER_INTERNAL;
10901                                         goto DONE;
10902                                 }
10903                         } else {
10904                                 LOGW("video decoder resource is already acquired, skip it.");
10905                                 ret = MM_ERROR_PLAYER_INTERNAL;
10906                                 goto DONE;
10907                         }
10908
10909                         player->interrupted_by_resource = FALSE;
10910                         /* acquire resources for video playing */
10911                         if (mm_resource_manager_commit(player->resource_manager)
10912                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10913                                 LOGE("could not acquire resources for video decoding\n");
10914                                 ret = MM_ERROR_PLAYER_INTERNAL;
10915                                 goto DONE;
10916                         }
10917                 }
10918
10919                 /* update codec info */
10920                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10921                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10922                 player->videodec_linked = 1;
10923         }
10924
10925 DONE:
10926         return ret;
10927 }
10928
10929 static gint
10930 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10931 GstCaps* caps, GstElementFactory* factory, gpointer data)
10932 {
10933         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10934          We are defining our own and will be removed when it actually exposed */
10935         typedef enum {
10936                 GST_AUTOPLUG_SELECT_TRY,
10937                 GST_AUTOPLUG_SELECT_EXPOSE,
10938                 GST_AUTOPLUG_SELECT_SKIP
10939         } GstAutoplugSelectResult;
10940
10941         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10942         mm_player_t* player = (mm_player_t*)data;
10943
10944         gchar* factory_name = NULL;
10945         gchar* caps_str = NULL;
10946         const gchar* klass = NULL;
10947         gint idx = 0;
10948
10949         factory_name = GST_OBJECT_NAME(factory);
10950         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10951         caps_str = gst_caps_to_string(caps);
10952
10953         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10954
10955         /* store type string */
10956         if (player->type == NULL) {
10957                 player->type = gst_caps_to_string(caps);
10958                 __mmplayer_update_content_type_info(player);
10959         }
10960
10961         /* filtering exclude keyword */
10962         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10963                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10964                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10965                                         factory_name, player->ini.exclude_element_keyword[idx]);
10966
10967                         result = GST_AUTOPLUG_SELECT_SKIP;
10968                         goto DONE;
10969                 }
10970         }
10971
10972         /* exclude webm format */
10973         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10974          * because webm format is not supportable.
10975          * If webm is disabled in "autoplug-continue", there is no state change
10976          * failure or error because the decodebin will expose the pad directly.
10977          * It make MSL invoke _prepare_async_callback.
10978          * So, we need to disable webm format in "autoplug-select" */
10979         if (caps_str && strstr(caps_str, "webm")) {
10980                 LOGW("webm is not supported");
10981                 result = GST_AUTOPLUG_SELECT_SKIP;
10982                 goto DONE;
10983         }
10984
10985         /* check factory class for filtering */
10986         /* NOTE : msl don't need to use image plugins.
10987          * So, those plugins should be skipped for error handling.
10988          */
10989         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10990                 LOGD("skipping [%s] by not required\n", factory_name);
10991                 result = GST_AUTOPLUG_SELECT_SKIP;
10992                 goto DONE;
10993         }
10994
10995         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10996                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10997                 // TO CHECK : subtitle if needed, add subparse exception.
10998                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10999                 result = GST_AUTOPLUG_SELECT_SKIP;
11000                 goto DONE;
11001         }
11002
11003         if (g_strrstr(factory_name, "mpegpsdemux")) {
11004                 LOGD("skipping PS container - not support\n");
11005                 result = GST_AUTOPLUG_SELECT_SKIP;
11006                 goto DONE;
11007         }
11008
11009         if (g_strrstr(factory_name, "mssdemux"))
11010                 player->smooth_streaming = TRUE;
11011
11012         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11013                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11014                 gint stype = 0;
11015                 gint width = 0;
11016                 GstStructure *str = NULL;
11017                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11018
11019                 /* don't make video because of not required */
11020                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11021                         (player->set_mode.media_packet_video_stream == FALSE)) {
11022                         LOGD("no video because it's not required. -> return expose");
11023                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11024                         goto DONE;
11025                 }
11026
11027                 /* get w/h for omx state-tune */
11028                 /* FIXME: deprecated? */
11029                 str = gst_caps_get_structure(caps, 0);
11030                 gst_structure_get_int(str, "width", &width);
11031
11032                 if (width != 0) {
11033                         if (player->v_stream_caps) {
11034                                 gst_caps_unref(player->v_stream_caps);
11035                                 player->v_stream_caps = NULL;
11036                         }
11037
11038                         player->v_stream_caps = gst_caps_copy(caps);
11039                         LOGD("take caps for video state tune");
11040                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11041                 }
11042         }
11043
11044         if (g_strrstr(klass, "Codec/Decoder")) {
11045                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11046                         LOGD("skipping %s codec", factory_name);
11047                         result = GST_AUTOPLUG_SELECT_SKIP;
11048                         goto DONE;
11049                 }
11050         }
11051
11052 DONE:
11053         MMPLAYER_FREEIF(caps_str);
11054
11055         return result;
11056 }
11057
11058 static void
11059 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11060 gpointer data)
11061 {
11062         //mm_player_t* player = (mm_player_t*)data;
11063         GstCaps* caps = NULL;
11064
11065         LOGD("[Decodebin2] pad-removed signal\n");
11066
11067         caps = gst_pad_query_caps(new_pad, NULL);
11068         if (caps) {
11069                 gchar* caps_str = NULL;
11070                 caps_str = gst_caps_to_string(caps);
11071
11072                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11073
11074                 MMPLAYER_FREEIF(caps_str);
11075                 gst_caps_unref(caps);
11076         }
11077 }
11078
11079 static void
11080 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11081 {
11082         mm_player_t* player = (mm_player_t*)data;
11083         GstIterator *iter = NULL;
11084         GValue item = { 0, };
11085         GstPad *pad = NULL;
11086         gboolean done = FALSE;
11087         gboolean is_all_drained = TRUE;
11088
11089         MMPLAYER_FENTER();
11090         MMPLAYER_RETURN_IF_FAIL(player);
11091
11092         LOGD("__mmplayer_gst_decode_drained");
11093
11094         if (player->use_deinterleave == TRUE) {
11095                 LOGD("group playing mode.");
11096                 return;
11097         }
11098
11099         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11100                 LOGW("Fail to get cmd lock");
11101                 return;
11102         }
11103
11104         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11105                 !__mmplayer_verify_next_play_path(player)) {
11106                 LOGD("decoding is finished.");
11107                 __mmplayer_reset_gapless_state(player);
11108                 MMPLAYER_CMD_UNLOCK(player);
11109                 return;
11110         }
11111
11112         player->gapless.reconfigure = TRUE;
11113
11114         /* check decodebin src pads whether they received EOS or not */
11115         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11116
11117         while (!done) {
11118                 switch (gst_iterator_next(iter, &item)) {
11119                 case GST_ITERATOR_OK:
11120                         pad = g_value_get_object(&item);
11121                         if (pad && !GST_PAD_IS_EOS(pad)) {
11122                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11123                                 is_all_drained = FALSE;
11124                                 break;
11125                         }
11126                         g_value_reset(&item);
11127                         break;
11128                 case GST_ITERATOR_RESYNC:
11129                         gst_iterator_resync(iter);
11130                         break;
11131                 case GST_ITERATOR_ERROR:
11132                 case GST_ITERATOR_DONE:
11133                         done = TRUE;
11134                         break;
11135                 }
11136         }
11137         g_value_unset(&item);
11138         gst_iterator_free(iter);
11139
11140         if (!is_all_drained) {
11141                 LOGD("Wait util the all pads get EOS.");
11142                 MMPLAYER_CMD_UNLOCK(player);
11143                 MMPLAYER_FLEAVE();
11144                 return;
11145         }
11146
11147         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11148         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11149
11150         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11151         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11152         __mmplayer_deactivate_old_path(player);
11153         MMPLAYER_CMD_UNLOCK(player);
11154
11155         MMPLAYER_FLEAVE();
11156 }
11157
11158 static void
11159 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11160 {
11161         mm_player_t* player = (mm_player_t*)data;
11162         const gchar* klass = NULL;
11163         gchar* factory_name = NULL;
11164
11165         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11166         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11167
11168         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11169
11170         if (__mmplayer_add_dump_buffer_probe(player, element))
11171                 LOGD("add buffer probe");
11172
11173         //<-
11174         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11175                 gchar* selected = NULL;
11176                 selected = g_strdup(GST_ELEMENT_NAME(element));
11177                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11178         }
11179         //-> temp code
11180
11181         if (g_strrstr(klass, "Parser")) {
11182                 gchar* selected = NULL;
11183
11184                 selected = g_strdup(factory_name);
11185                 player->parsers = g_list_append(player->parsers, selected);
11186         }
11187
11188         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11189                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11190                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11191
11192                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11193                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11194
11195                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11196                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11197                                                 "max-video-width", player->adaptive_info.limit.width,
11198                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11199
11200         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11201                 /* FIXIT : first value will be overwritten if there's more
11202                  * than 1 demuxer/parser
11203                  */
11204
11205                 //LOGD("plugged element is demuxer. take it\n");
11206                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11207                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11208
11209                 /*Added for multi audio support */ // Q. del?
11210                 if (g_strrstr(klass, "Demux")) {
11211                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11212                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11213                 }
11214         }
11215
11216         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11217                 int surface_type = 0;
11218
11219                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11220         }
11221
11222         // to support trust-zone only
11223         if (g_strrstr(factory_name, "asfdemux")) {
11224                 LOGD("set file-location %s\n", player->profile.uri);
11225                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11226
11227                 if (player->video_hub_download_mode == TRUE)
11228                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11229         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11230                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11231                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11232         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11233                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11234                         (__mmplayer_is_only_mp3_type(player->type))) {
11235                         LOGD("[mpegaudioparse] set streaming pull mode.");
11236                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11237                 }
11238         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11239                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11240         }
11241
11242         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11243                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11244                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11245
11246                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11247                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11248
11249                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11250                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11251                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11252                         (MMPLAYER_IS_DASH_STREAMING(player)))) {
11253                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11254                         __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11255                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11256                 }
11257
11258         }
11259
11260         return;
11261 }
11262
11263 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11264 {
11265         MMPLAYER_FENTER();
11266         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11267
11268         if (MMPLAYER_IS_STREAMING(player))
11269                 return FALSE;
11270
11271         /* This callback can be set to music player only. */
11272         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11273                 LOGW("audio callback is not supported for video");
11274                 return FALSE;
11275         }
11276
11277         if (player->audio_stream_cb) {
11278                 GstPad *pad = NULL;
11279
11280                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11281
11282                 if (!pad) {
11283                         LOGE("failed to get sink pad from audiosink to probe data\n");
11284                         return FALSE;
11285                 }
11286                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11287                         __mmplayer_audio_stream_probe, player, NULL);
11288
11289                 gst_object_unref(pad);
11290
11291                 pad = NULL;
11292         } else {
11293                 LOGE("There is no audio callback to configure.\n");
11294                 return FALSE;
11295         }
11296
11297         MMPLAYER_FLEAVE();
11298
11299         return TRUE;
11300 }
11301
11302 static void
11303 __mmplayer_release_misc(mm_player_t* player)
11304 {
11305         int i;
11306         bool cur_mode = player->set_mode.rich_audio;
11307         MMPLAYER_FENTER();
11308
11309         MMPLAYER_RETURN_IF_FAIL(player);
11310
11311         player->video_stream_cb = NULL;
11312         player->video_stream_cb_user_param = NULL;
11313         player->video_stream_prerolled = FALSE;
11314
11315         player->audio_stream_cb = NULL;
11316         player->audio_stream_render_cb_ex = NULL;
11317         player->audio_stream_cb_user_param = NULL;
11318         player->audio_stream_sink_sync = false;
11319
11320         player->video_stream_changed_cb = NULL;
11321         player->video_stream_changed_cb_user_param = NULL;
11322
11323         player->audio_stream_changed_cb = NULL;
11324         player->audio_stream_changed_cb_user_param = NULL;
11325
11326         player->sent_bos = FALSE;
11327         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11328
11329         player->seek_state = MMPLAYER_SEEK_NONE;
11330
11331         player->total_bitrate = 0;
11332         player->total_maximum_bitrate = 0;
11333
11334         player->not_found_demuxer = 0;
11335
11336         player->last_position = 0;
11337         player->duration = 0;
11338         player->http_content_size = 0;
11339         player->not_supported_codec = MISSING_PLUGIN_NONE;
11340         player->can_support_codec = FOUND_PLUGIN_NONE;
11341         player->pending_seek.is_pending = FALSE;
11342         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11343         player->pending_seek.pos = 0;
11344         player->msg_posted = FALSE;
11345         player->has_many_types = FALSE;
11346         player->max_audio_channels = 0;
11347         player->video_share_api_delta = 0;
11348         player->video_share_clock_delta = 0;
11349         player->is_subtitle_force_drop = FALSE;
11350         player->play_subtitle = FALSE;
11351         player->adjust_subtitle_pos = 0;
11352         player->last_multiwin_status = FALSE;
11353         player->has_closed_caption = FALSE;
11354         player->set_mode.media_packet_video_stream = FALSE;
11355         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11356         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11357         /* recover mode */
11358         player->set_mode.rich_audio = cur_mode;
11359
11360         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11361                 player->bitrate[i] = 0;
11362                 player->maximum_bitrate[i] = 0;
11363         }
11364
11365         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11366
11367         /* remove media stream cb(appsrc cb) */
11368         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11369                 player->media_stream_buffer_status_cb[i] = NULL;
11370                 player->media_stream_seek_data_cb[i] = NULL;
11371                 player->buffer_cb_user_param[i] = NULL;
11372                 player->seek_cb_user_param[i] = NULL;
11373         }
11374         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11375
11376         /* free memory related to audio effect */
11377         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11378
11379         if (player->adaptive_info.var_list) {
11380                 g_list_free_full(player->adaptive_info.var_list, g_free);
11381                 player->adaptive_info.var_list = NULL;
11382         }
11383
11384         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11385         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11386         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11387
11388         /* Reset video360 settings to their defaults in case if the pipeline is to be
11389          * re-created.
11390          * */
11391         player->video360_metadata.is_spherical = -1;
11392         player->is_openal_plugin_used = FALSE;
11393
11394         player->is_content_spherical = FALSE;
11395         player->is_video360_enabled = TRUE;
11396         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11397         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11398         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11399         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11400         player->video360_zoom = 1.0f;
11401         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11402         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11403
11404         player->sound.rg_enable = false;
11405
11406         MMPLAYER_FLEAVE();
11407 }
11408
11409 static void
11410 __mmplayer_release_misc_post(mm_player_t* player)
11411 {
11412         char *original_uri = NULL;
11413         MMPLAYER_FENTER();
11414
11415         /* player->pipeline is already released before. */
11416
11417         MMPLAYER_RETURN_IF_FAIL(player);
11418
11419         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11420
11421         /* clean found parsers */
11422         if (player->parsers) {
11423                 GList *parsers = player->parsers;
11424                 for (; parsers; parsers = g_list_next(parsers)) {
11425                         gchar *name = parsers->data;
11426                         MMPLAYER_FREEIF(name);
11427                 }
11428                 g_list_free(player->parsers);
11429                 player->parsers = NULL;
11430         }
11431
11432         /* clean found audio decoders */
11433         if (player->audio_decoders) {
11434                 GList *a_dec = player->audio_decoders;
11435                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11436                         gchar *name = a_dec->data;
11437                         MMPLAYER_FREEIF(name);
11438                 }
11439                 g_list_free(player->audio_decoders);
11440                 player->audio_decoders = NULL;
11441         }
11442
11443         /* clean the uri list except original uri */
11444         if (player->uri_info.uri_list) {
11445                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11446
11447                 if (player->attrs) {
11448                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11449                         LOGD("restore original uri = %s\n", original_uri);
11450
11451                         if (mmf_attrs_commit(player->attrs))
11452                                 LOGE("failed to commit the original uri.\n");
11453                 }
11454
11455                 GList *uri_list = player->uri_info.uri_list;
11456                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11457                         gchar *uri = uri_list->data;
11458                         MMPLAYER_FREEIF(uri);
11459                 }
11460                 g_list_free(player->uri_info.uri_list);
11461                 player->uri_info.uri_list = NULL;
11462         }
11463
11464         /* clear the audio stream buffer list */
11465         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11466
11467         /* clear the video stream bo list */
11468         __mmplayer_video_stream_destroy_bo_list(player);
11469         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11470
11471         if (player->profile.input_mem.buf) {
11472                 free(player->profile.input_mem.buf);
11473                 player->profile.input_mem.buf = NULL;
11474         }
11475         player->profile.input_mem.len = 0;
11476         player->profile.input_mem.offset = 0;
11477
11478         player->uri_info.uri_idx = 0;
11479         MMPLAYER_FLEAVE();
11480 }
11481
11482 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11483 {
11484         GstElement *element = NULL;
11485         GstPad *sinkpad;
11486
11487         LOGD("creating %s to plug\n", name);
11488
11489         element = gst_element_factory_make(name, NULL);
11490         if (!element) {
11491                 LOGE("failed to create queue\n");
11492                 return NULL;
11493         }
11494
11495         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11496                 LOGE("failed to set state READY to %s\n", name);
11497                 gst_object_unref(element);
11498                 return NULL;
11499         }
11500
11501         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11502                 LOGE("failed to add %s\n", name);
11503                 gst_object_unref(element);
11504                 return NULL;
11505         }
11506
11507         sinkpad = gst_element_get_static_pad(element, "sink");
11508
11509         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11510                 LOGE("failed to link %s\n", name);
11511                 gst_object_unref(sinkpad);
11512                 gst_object_unref(element);
11513                 return NULL;
11514         }
11515
11516         LOGD("linked %s to pipeline successfully\n", name);
11517
11518         gst_object_unref(sinkpad);
11519
11520         return element;
11521 }
11522
11523 gboolean
11524 __mmplayer_check_subtitle(mm_player_t* player)
11525 {
11526         MMHandleType attrs = 0;
11527         char *subtitle_uri = NULL;
11528
11529         MMPLAYER_FENTER();
11530
11531         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11532
11533         /* get subtitle attribute */
11534         attrs = MMPLAYER_GET_ATTRS(player);
11535         if (!attrs)
11536                 return FALSE;
11537
11538         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11539         if (!subtitle_uri || !strlen(subtitle_uri))
11540                 return FALSE;
11541
11542         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11543         player->is_external_subtitle_present = TRUE;
11544
11545         MMPLAYER_FLEAVE();
11546
11547         return TRUE;
11548 }
11549
11550 static gboolean
11551 __mmplayer_can_extract_pcm(mm_player_t* player)
11552 {
11553         MMHandleType attrs = 0;
11554         gboolean sound_extraction = FALSE;
11555
11556         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11557
11558         attrs = MMPLAYER_GET_ATTRS(player);
11559         if (!attrs) {
11560                 LOGE("fail to get attributes.");
11561                 return FALSE;
11562         }
11563
11564         /* get sound_extraction property */
11565         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11566
11567         if (!sound_extraction) {
11568                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11569                 return FALSE;
11570         }
11571
11572         return TRUE;
11573 }
11574
11575 static gboolean
11576 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11577 {
11578         LOGD("\n");
11579         MMMessageParamType msg_param;
11580         gchar *msg_src_element = NULL;
11581         GstStructure *s = NULL;
11582         guint error_id = 0;
11583         gchar *error_string = NULL;
11584
11585         MMPLAYER_FENTER();
11586
11587         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11588         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11589
11590         s = gst_structure_copy(gst_message_get_structure(message));
11591
11592
11593         if (!gst_structure_get_uint(s, "error_id", &error_id))
11594                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11595
11596         switch (error_id) {
11597         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11598                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11599                 break;
11600         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11601                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11602                 break;
11603         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11604                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11605                 break;
11606         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11607                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11608                 break;
11609         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11610                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11611                 break;
11612         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11613                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11614                 break;
11615         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11616                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11617                 break;
11618         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11619                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11620                 break;
11621         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11622                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11623                 break;
11624         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11625                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11626                 break;
11627         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11628                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11629                 break;
11630         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11631                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11632                 break;
11633         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11634                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11635                 break;
11636         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11637                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11638                 break;
11639         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11640                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11641                 break;
11642         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11643                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11644                 break;
11645         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11646                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11647                 break;
11648         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11649                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11650                 break;
11651         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11652                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11653                 break;
11654         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11655                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11656                 break;
11657         case MMPLAYER_STREAMING_ERROR_GONE:
11658                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11659                 break;
11660         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11661                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11662                 break;
11663         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11664                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11665                 break;
11666         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11667                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11668                 break;
11669         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11670                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11671                 break;
11672         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11673                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11674                 break;
11675         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11676                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11677                 break;
11678         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11679                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11680                 break;
11681         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11682                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11683                 break;
11684         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11685                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11686                 break;
11687         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11688                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11689                 break;
11690         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11691                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11692                 break;
11693         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11694                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11695                 break;
11696         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11697                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11698                 break;
11699         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11700                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11701                 break;
11702         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11703                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11704                 break;
11705         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11706                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11707                 break;
11708         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11709                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11710                 break;
11711         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11712                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11713                 break;
11714         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11715                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11716                 break;
11717         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11718                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11719                 break;
11720         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11721                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11722                 break;
11723         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11724                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11725                 break;
11726         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11727                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11728                 break;
11729         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11730                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11731                 break;
11732         default:
11733                 {
11734                         gst_structure_free(s);
11735                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11736                 }
11737         }
11738
11739         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11740         if (error_string)
11741                 msg_param.data = (void *) error_string;
11742
11743         if (message->src) {
11744                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11745
11746                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11747                         msg_src_element, msg_param.code, (char*)msg_param.data);
11748         }
11749
11750         /* post error to application */
11751         if (!player->msg_posted) {
11752                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11753
11754                 /* don't post more if one was sent already */
11755                 player->msg_posted = TRUE;
11756         } else
11757                 LOGD("skip error post because it's sent already.\n");
11758
11759         gst_structure_free(s);
11760         MMPLAYER_FLEAVE();
11761         g_free(error_string);
11762
11763         return TRUE;
11764
11765 }
11766
11767 static void
11768 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11769 {
11770         MMPLAYER_RETURN_IF_FAIL(player);
11771
11772         /* post now if delay is zero */
11773         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11774                 LOGD("eos delay is zero. posting EOS now\n");
11775                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11776
11777                 if (player->set_mode.pcm_extraction)
11778                         __mmplayer_cancel_eos_timer(player);
11779
11780                 return;
11781         }
11782
11783         /* cancel if existing */
11784         __mmplayer_cancel_eos_timer(player);
11785
11786         /* init new timeout */
11787         /* NOTE : consider give high priority to this timer */
11788         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11789
11790         player->eos_timer = g_timeout_add(delay_in_ms,
11791                 __mmplayer_eos_timer_cb, player);
11792
11793         player->context.global_default = g_main_context_default();
11794         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11795
11796         /* check timer is valid. if not, send EOS now */
11797         if (player->eos_timer == 0) {
11798                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11799                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11800         }
11801 }
11802
11803 static void
11804 __mmplayer_cancel_eos_timer(mm_player_t* player)
11805 {
11806         MMPLAYER_RETURN_IF_FAIL(player);
11807
11808         if (player->eos_timer) {
11809                 LOGD("cancel eos timer");
11810                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11811                 player->eos_timer = 0;
11812         }
11813
11814         return;
11815 }
11816
11817 static gboolean
11818 __mmplayer_eos_timer_cb(gpointer u_data)
11819 {
11820         mm_player_t* player = NULL;
11821         MMHandleType attrs = 0;
11822         int count = 0;
11823
11824         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11825
11826         player = (mm_player_t*) u_data;
11827         attrs = MMPLAYER_GET_ATTRS(player);
11828
11829         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11830
11831         if (count == -1) {
11832                 gint ret_value = 0;
11833                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11834                 if (ret_value != MM_ERROR_NONE)
11835                         LOGE("seeking to 0 failed in repeat play");
11836         } else {
11837                 /* posting eos */
11838                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11839         }
11840
11841         /* we are returning FALSE as we need only one posting */
11842         return FALSE;
11843 }
11844
11845 /* sending event to one of sinkelements */
11846 static gboolean
11847 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11848 {
11849         GstEvent * event2 = NULL;
11850         GList *sinks = NULL;
11851         gboolean res = FALSE;
11852         MMPLAYER_FENTER();
11853
11854         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11855         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11856
11857         /* While adding subtitles in live feeds seek is getting called.
11858            Adding defensive check in framework layer.*/
11859         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11860                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11861                         LOGE("Should not send seek event during live playback");
11862                         return TRUE;
11863                 }
11864         }
11865
11866         if (player->play_subtitle)
11867                 event2 = gst_event_copy((const GstEvent *)event);
11868
11869         sinks = player->sink_elements;
11870         while (sinks) {
11871                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11872
11873                 if (GST_IS_ELEMENT(sink)) {
11874                         /* keep ref to the event */
11875                         gst_event_ref(event);
11876
11877                         if ((res = gst_element_send_event(sink, event))) {
11878                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11879                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11880
11881                                 /* rtsp case, asyn_done is not called after seek during pause state */
11882                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11883                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11884                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11885                                                         LOGD("RTSP seek completed, after pause state..\n");
11886                                                         player->seek_state = MMPLAYER_SEEK_NONE;
11887                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11888                                                 }
11889
11890                                         }
11891                                 }
11892
11893                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11894                                         sinks = g_list_next(sinks);
11895                                         continue;
11896                                 } else {
11897                                         break;
11898                                 }
11899                         }
11900
11901                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11902                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11903                 }
11904
11905                 sinks = g_list_next(sinks);
11906         }
11907
11908         /* Note : Textbin is not linked to the video or audio bin.
11909          * It needs to send the event to the text sink seperatelly.
11910          */
11911          if (player->play_subtitle && player->pipeline) {
11912                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11913
11914                 if (GST_IS_ELEMENT(text_sink)) {
11915                         /* keep ref to the event */
11916                         gst_event_ref(event2);
11917
11918                         if ((res = gst_element_send_event(text_sink, event2)))
11919                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11920                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11921                         else
11922                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11923                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11924
11925                         gst_event_unref(event2);
11926                 }
11927          }
11928
11929         gst_event_unref(event);
11930
11931         MMPLAYER_FLEAVE();
11932
11933         return res;
11934 }
11935
11936 static void
11937 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11938 {
11939         MMPLAYER_FENTER();
11940
11941         MMPLAYER_RETURN_IF_FAIL(player);
11942         MMPLAYER_RETURN_IF_FAIL(sink);
11943
11944         player->sink_elements =
11945                 g_list_append(player->sink_elements, sink);
11946
11947         MMPLAYER_FLEAVE();
11948 }
11949
11950 static void
11951 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11952 {
11953         MMPLAYER_FENTER();
11954
11955         MMPLAYER_RETURN_IF_FAIL(player);
11956         MMPLAYER_RETURN_IF_FAIL(sink);
11957
11958         player->sink_elements =
11959                         g_list_remove(player->sink_elements, sink);
11960
11961         MMPLAYER_FLEAVE();
11962 }
11963
11964 static gboolean
11965 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11966                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11967                         gint64 cur, GstSeekType stop_type, gint64 stop)
11968 {
11969         GstEvent* event = NULL;
11970         gboolean result = FALSE;
11971
11972         MMPLAYER_FENTER();
11973
11974         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11975
11976         if (player->pipeline && player->pipeline->textbin)
11977                 __mmplayer_drop_subtitle(player, FALSE);
11978
11979         event = gst_event_new_seek(rate, format, flags, cur_type,
11980                 cur, stop_type, stop);
11981
11982         result = __gst_send_event_to_sink(player, event);
11983
11984         MMPLAYER_FLEAVE();
11985
11986         return result;
11987 }
11988
11989 /* NOTE : be careful with calling this api. please refer to below glib comment
11990  * glib comment : Note that there is a bug in GObject that makes this function much
11991  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11992  * will no longer be called, but, the signal handler is not currently disconnected.
11993  * If the instance is itself being freed at the same time than this doesn't matter,
11994  * since the signal will automatically be removed, but if instance persists,
11995  * then the signal handler will leak. You should not remove the signal yourself
11996  * because in a future versions of GObject, the handler will automatically be
11997  * disconnected.
11998  *
11999  * It's possible to work around this problem in a way that will continue to work
12000  * with future versions of GObject by checking that the signal handler is still
12001  * connected before disconnected it:
12002  *
12003  *  if (g_signal_handler_is_connected(instance, id))
12004  *    g_signal_handler_disconnect(instance, id);
12005  */
12006 static void
12007 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12008 {
12009         GList* sig_list = NULL;
12010         MMPlayerSignalItem* item = NULL;
12011
12012         MMPLAYER_FENTER();
12013
12014         MMPLAYER_RETURN_IF_FAIL(player);
12015
12016         LOGD("release signals type : %d", type);
12017
12018         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12019                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12020                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12021                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12022                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12023                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12024                 return;
12025         }
12026
12027         sig_list = player->signals[type];
12028
12029         for (; sig_list; sig_list = sig_list->next) {
12030                 item = sig_list->data;
12031
12032                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12033                         if (g_signal_handler_is_connected(item->obj, item->sig))
12034                                 g_signal_handler_disconnect(item->obj, item->sig);
12035                 }
12036
12037                 MMPLAYER_FREEIF(item);
12038         }
12039
12040         g_list_free(player->signals[type]);
12041         player->signals[type] = NULL;
12042
12043         MMPLAYER_FLEAVE();
12044
12045         return;
12046 }
12047
12048 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12049 {
12050         mm_player_t* player = 0;
12051         int prev_display_surface_type = 0;
12052         void *prev_display_overlay = NULL;
12053         const gchar *klass = NULL;
12054         gchar *cur_videosink_name = NULL;
12055         int ret = 0;
12056         int i = 0;
12057         int num_of_dec = 2; /* DEC1, DEC2 */
12058
12059         MMPLAYER_FENTER();
12060
12061         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12062         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12063
12064         player = MM_PLAYER_CAST(handle);
12065
12066         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12067                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12068                 MMPLAYER_FLEAVE();
12069                 return MM_ERROR_INVALID_ARGUMENT;
12070         }
12071
12072         /* load previous attributes */
12073         if (player->attrs) {
12074                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12075                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12076                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12077                 if (prev_display_surface_type == surface_type) {
12078                         LOGD("incoming display surface type is same as previous one, do nothing..");
12079                         MMPLAYER_FLEAVE();
12080                         return MM_ERROR_NONE;
12081                 }
12082         } else {
12083                 LOGE("failed to load attributes");
12084                 MMPLAYER_FLEAVE();
12085                 return MM_ERROR_PLAYER_INTERNAL;
12086         }
12087
12088         /* check videosink element is created */
12089         if (!player->pipeline || !player->pipeline->videobin ||
12090                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12091                 LOGD("videosink element is not yet ready");
12092
12093                 /* videobin is not created yet, so we just set attributes related to display surface */
12094                 LOGD("store display attribute for given surface type(%d)", surface_type);
12095                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12096                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12097                 if (mmf_attrs_commit(player->attrs)) {
12098                         LOGE("failed to commit attribute");
12099                         MMPLAYER_FLEAVE();
12100                         return MM_ERROR_PLAYER_INTERNAL;
12101                 }
12102                 MMPLAYER_FLEAVE();
12103                 return MM_ERROR_NONE;
12104         } else {
12105                 /* get player command status */
12106                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12107                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12108                         MMPLAYER_FLEAVE();
12109                         return MM_ERROR_PLAYER_INVALID_STATE;
12110                 }
12111
12112                 /* surface change */
12113                 for (i = 0 ; i < num_of_dec ; i++) {
12114                         if (player->pipeline->mainbin &&
12115                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12116                                 GstElementFactory *decfactory;
12117                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12118
12119                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12120                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12121                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12122                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12123                                                 if (ret) {
12124                                                         goto ERROR_CASE;
12125                                                 } else {
12126                                                         LOGW("success to changing display surface(%d)", surface_type);
12127                                                         MMPLAYER_FLEAVE();
12128                                                         return MM_ERROR_NONE;
12129                                                 }
12130                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12131                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12132                                                 if (ret) {
12133                                                         goto ERROR_CASE;
12134                                                 } else {
12135                                                         LOGW("success to changing display surface(%d)", surface_type);
12136                                                         MMPLAYER_FLEAVE();
12137                                                         return MM_ERROR_NONE;
12138                                                 }
12139                                         } else {
12140                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12141                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12142                                                 goto ERROR_CASE;
12143                                         }
12144                                 }
12145                         }
12146                 }
12147         }
12148
12149 ERROR_CASE:
12150         /* rollback to previous attributes */
12151         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12152         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12153         if (mmf_attrs_commit(player->attrs)) {
12154                 LOGE("failed to commit attributes to rollback");
12155                 MMPLAYER_FLEAVE();
12156                 return MM_ERROR_PLAYER_INTERNAL;
12157         }
12158         MMPLAYER_FLEAVE();
12159         return ret;
12160 }
12161
12162 /* NOTE : It does not support some use cases, eg using colorspace converter */
12163 int
12164 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12165 {
12166         GstPad *src_pad_dec = NULL;
12167         GstPad *sink_pad_videosink = NULL;
12168         GstPad *sink_pad_videobin = NULL;
12169         GstClock *clock = NULL;
12170         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12171         int ret = MM_ERROR_NONE;
12172         gboolean is_audiobin_created = TRUE;
12173
12174         MMPLAYER_FENTER();
12175
12176         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12177         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12178         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12179
12180         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12181         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12182
12183         /* get information whether if audiobin is created */
12184         if (!player->pipeline->audiobin ||
12185                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12186                 LOGW("audiobin is null, this video content may not have audio data");
12187                 is_audiobin_created = FALSE;
12188         }
12189
12190         /* get current state of player */
12191         previous_state = MMPLAYER_CURRENT_STATE(player);
12192         LOGD("previous state(%d)", previous_state);
12193
12194
12195         /* get src pad of decoder and block it */
12196         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12197         if (!src_pad_dec) {
12198                 LOGE("failed to get src pad from decode in mainbin");
12199                 return MM_ERROR_PLAYER_INTERNAL;
12200         }
12201
12202         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12203                 LOGW("trying to block pad(video)");
12204 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12205                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12206                         NULL, NULL, NULL);
12207                 {
12208                         LOGE("failed to set block pad(video)");
12209                         return MM_ERROR_PLAYER_INTERNAL;
12210                 }
12211                 LOGW("pad is blocked(video)");
12212         } else {
12213                 /* no data flows, so no need to do pad_block */
12214                 if (player->seek_state != MMPLAYER_SEEK_NONE)
12215                         LOGW("not completed seek(%d), do nothing", player->seek_state);
12216
12217                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12218         }
12219
12220         /* remove pad */
12221         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12222                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12223                 LOGE("failed to remove previous ghost_pad for videobin");
12224                 return MM_ERROR_PLAYER_INTERNAL;
12225         }
12226
12227         /* change state of videobin to NULL */
12228         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12229         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12230         if (ret != GST_STATE_CHANGE_SUCCESS) {
12231                 LOGE("failed to change state of videobin to NULL");
12232                 return MM_ERROR_PLAYER_INTERNAL;
12233         }
12234
12235         /* unlink between decoder and videobin and remove previous videosink from videobin */
12236         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12237         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12238                 LOGE("failed to remove former videosink from videobin");
12239                 return MM_ERROR_PLAYER_INTERNAL;
12240         }
12241
12242         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12243
12244         /* create a new videosink and add it to videobin */
12245         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12246         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12247                 LOGE("failed to create videosink element\n");
12248                 MMPLAYER_FLEAVE();
12249                 return MM_ERROR_PLAYER_INTERNAL;
12250         }
12251         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12252         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12253         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12254
12255         /* save attributes */
12256         if (player->attrs) {
12257                 /* set a new display surface type */
12258                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12259                 /* set a new diplay overlay */
12260                 switch (surface_type) {
12261                 case MM_DISPLAY_SURFACE_OVERLAY:
12262                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12263                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12264                         break;
12265                 default:
12266                         LOGE("invalid type(%d) for changing display surface", surface_type);
12267                         MMPLAYER_FLEAVE();
12268                         return MM_ERROR_INVALID_ARGUMENT;
12269                 }
12270                 if (mmf_attrs_commit(player->attrs)) {
12271                         LOGE("failed to commit");
12272                         MMPLAYER_FLEAVE();
12273                         return MM_ERROR_PLAYER_INTERNAL;
12274                 }
12275         } else {
12276                 LOGE("player->attrs is null, failed to save attributes");
12277                 MMPLAYER_FLEAVE();
12278                 return MM_ERROR_PLAYER_INTERNAL;
12279         }
12280
12281         /* update video param */
12282         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12283                 LOGE("failed to update video param");
12284                 return MM_ERROR_PLAYER_INTERNAL;
12285         }
12286
12287         /* change state of videobin to READY */
12288         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12289         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12290         if (ret != GST_STATE_CHANGE_SUCCESS) {
12291                 LOGE("failed to change state of videobin to READY");
12292                 return MM_ERROR_PLAYER_INTERNAL;
12293         }
12294
12295         /* change ghostpad */
12296         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12297         if (!sink_pad_videosink) {
12298                 LOGE("failed to get sink pad from videosink element");
12299                 return MM_ERROR_PLAYER_INTERNAL;
12300         }
12301         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12302         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12303                 LOGE("failed to set active to ghost_pad");
12304                 return MM_ERROR_PLAYER_INTERNAL;
12305         }
12306         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12307                 LOGE("failed to change ghostpad for videobin");
12308                 return MM_ERROR_PLAYER_INTERNAL;
12309         }
12310         gst_object_unref(sink_pad_videosink);
12311
12312         /* link decoder with videobin */
12313         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12314         if (!sink_pad_videobin) {
12315                 LOGE("failed to get sink pad from videobin");
12316                 return MM_ERROR_PLAYER_INTERNAL;
12317         }
12318         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12319                 LOGE("failed to link");
12320                 return MM_ERROR_PLAYER_INTERNAL;
12321         }
12322         gst_object_unref(sink_pad_videobin);
12323
12324         /* clock setting for a new videosink plugin */
12325         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12326                         so we set it from audiosink plugin or pipeline(system clock) */
12327         if (!is_audiobin_created) {
12328                 LOGW("audiobin is not created, get clock from pipeline..");
12329                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12330         } else {
12331                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12332         }
12333         if (clock) {
12334                 GstClockTime now;
12335                 GstClockTime base_time;
12336                 LOGD("set the clock to videosink");
12337                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12338                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12339                 if (clock) {
12340                         LOGD("got clock of videosink");
12341                         now = gst_clock_get_time(clock);
12342                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12343                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12344                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12345                 } else {
12346                         LOGE("failed to get clock of videosink after setting clock");
12347                         return MM_ERROR_PLAYER_INTERNAL;
12348                 }
12349         } else
12350                 LOGW("failed to get clock, maybe it is the time before first playing");
12351
12352         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12353                 /* change state of videobin to PAUSED */
12354                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12355                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12356                 if (ret != GST_STATE_CHANGE_FAILURE) {
12357                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12358                 } else {
12359                         LOGE("failed to change state of videobin to PLAYING");
12360                         return MM_ERROR_PLAYER_INTERNAL;
12361                 }
12362
12363                 /* release blocked and unref src pad of video decoder */
12364                 #if 0
12365                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12366                         LOGE("failed to set pad blocked FALSE(video)");
12367                         return MM_ERROR_PLAYER_INTERNAL;
12368                 }
12369                 #endif
12370                 LOGW("pad is unblocked(video)");
12371         } else {
12372                 if (player->seek_state != MMPLAYER_SEEK_NONE)
12373                         LOGW("not completed seek(%d)", player->seek_state);
12374                 /* change state of videobin to PAUSED */
12375                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12376                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12377                 if (ret != GST_STATE_CHANGE_FAILURE) {
12378                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12379                 } else {
12380                         LOGE("failed to change state of videobin to PLAYING");
12381                         return MM_ERROR_PLAYER_INTERNAL;
12382                 }
12383
12384                 /* already skipped pad block */
12385                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12386         }
12387
12388         /* do get/set position for new videosink plugin */
12389         {
12390                 gint64 position = 0;
12391
12392                 LOGD("do get/set position for new videosink plugin");
12393                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12394                         LOGE("failed to get position");
12395                         return MM_ERROR_PLAYER_INTERNAL;
12396                 }
12397 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12398                 /* accurate seek */
12399                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12400                         LOGE("failed to set position");
12401                         return MM_ERROR_PLAYER_INTERNAL;
12402                 }
12403 #else
12404                 /* key unit seek */
12405                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12406                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12407                                                         GST_SEEK_TYPE_SET, position,
12408                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12409                 if (!ret) {
12410                         LOGE("failed to set position");
12411                         return MM_ERROR_PLAYER_INTERNAL;
12412                 }
12413 #endif
12414         }
12415
12416         if (src_pad_dec)
12417                 gst_object_unref(src_pad_dec);
12418         LOGD("success to change sink");
12419
12420         MMPLAYER_FLEAVE();
12421
12422         return MM_ERROR_NONE;
12423 }
12424
12425
12426 /* Note : if silent is true, then subtitle would not be displayed. :*/
12427 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12428 {
12429         mm_player_t* player = (mm_player_t*) hplayer;
12430
12431         MMPLAYER_FENTER();
12432
12433         /* check player handle */
12434         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12435
12436         player->set_mode.subtitle_off = silent;
12437
12438         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12439
12440         MMPLAYER_FLEAVE();
12441
12442         return MM_ERROR_NONE;
12443 }
12444
12445 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12446 {
12447         MMPlayerGstElement* mainbin = NULL;
12448         MMPlayerGstElement* textbin = NULL;
12449         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12450         GstState current_state = GST_STATE_VOID_PENDING;
12451         GstState element_state = GST_STATE_VOID_PENDING;
12452         GstState element_pending_state = GST_STATE_VOID_PENDING;
12453         gint64 time = 0;
12454         GstEvent *event = NULL;
12455         int result = MM_ERROR_NONE;
12456
12457         GstClock *curr_clock = NULL;
12458         GstClockTime base_time, start_time, curr_time;
12459
12460
12461         MMPLAYER_FENTER();
12462
12463         /* check player handle */
12464         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12465                                                                 player->pipeline &&
12466                                                                 player->pipeline->mainbin &&
12467                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12468
12469         mainbin = player->pipeline->mainbin;
12470         textbin = player->pipeline->textbin;
12471
12472         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12473
12474         // sync clock with current pipeline
12475         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12476         curr_time = gst_clock_get_time(curr_clock);
12477
12478         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12479         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12480
12481         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12482                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12483
12484         if (current_state > GST_STATE_READY) {
12485                 // sync state with current pipeline
12486                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12487                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12488                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12489
12490                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12491                 if (GST_STATE_CHANGE_FAILURE == ret) {
12492                         LOGE("fail to state change.\n");
12493                         result = MM_ERROR_PLAYER_INTERNAL;
12494                         goto ERROR;
12495                 }
12496         }
12497
12498         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12499         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12500
12501         if (curr_clock) {
12502                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12503                 gst_object_unref(curr_clock);
12504         }
12505
12506         // seek to current position
12507         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12508                 result = MM_ERROR_PLAYER_INVALID_STATE;
12509                 LOGE("gst_element_query_position failed, invalid state\n");
12510                 goto ERROR;
12511         }
12512
12513         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12514         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);
12515         if (event) {
12516                 __gst_send_event_to_sink(player, event);
12517         } else {
12518                 result = MM_ERROR_PLAYER_INTERNAL;
12519                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12520                 goto ERROR;
12521         }
12522
12523         /* sync state with current pipeline */
12524         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12525         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12526         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12527
12528         return MM_ERROR_NONE;
12529
12530 ERROR:
12531         /* release text pipeline resource */
12532         player->textsink_linked = 0;
12533
12534         /* release signal */
12535         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12536
12537         /* release textbin with it's childs */
12538         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12539         MMPLAYER_FREEIF(player->pipeline->textbin);
12540         player->pipeline->textbin = NULL;
12541
12542         /* release subtitle elem */
12543         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12544         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12545
12546         return result;
12547 }
12548
12549 static int
12550 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12551 {
12552         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12553         GstState current_state = GST_STATE_VOID_PENDING;
12554
12555         MMHandleType attrs = 0;
12556         MMPlayerGstElement* mainbin = NULL;
12557         MMPlayerGstElement* textbin = NULL;
12558
12559         gchar* subtitle_uri = NULL;
12560         int result = MM_ERROR_NONE;
12561         const gchar *charset = NULL;
12562
12563         MMPLAYER_FENTER();
12564
12565         /* check player handle */
12566         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12567                                                                 player->pipeline &&
12568                                                                 player->pipeline->mainbin &&
12569                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12570         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12571
12572         mainbin = player->pipeline->mainbin;
12573         textbin = player->pipeline->textbin;
12574
12575         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12576         if (current_state < GST_STATE_READY) {
12577                 result = MM_ERROR_PLAYER_INVALID_STATE;
12578                 LOGE("Pipeline is not in proper state\n");
12579                 goto EXIT;
12580         }
12581
12582         attrs = MMPLAYER_GET_ATTRS(player);
12583         if (!attrs) {
12584                 LOGE("cannot get content attribute\n");
12585                 result = MM_ERROR_PLAYER_INTERNAL;
12586                 goto EXIT;
12587         }
12588
12589         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12590         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12591                 LOGE("subtitle uri is not proper filepath\n");
12592                 result = MM_ERROR_PLAYER_INVALID_URI;
12593                 goto EXIT;
12594         }
12595
12596         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12597                 LOGE("failed to get storage info of subtitle path");
12598                 result = MM_ERROR_PLAYER_INVALID_URI;
12599                 goto EXIT;
12600         }
12601
12602         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12603         LOGD("new subtitle file path is [%s]\n", filepath);
12604
12605         if (!strcmp(filepath, subtitle_uri)) {
12606                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12607                 goto EXIT;
12608         } else {
12609                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12610                 if (mmf_attrs_commit(player->attrs)) {
12611                         LOGE("failed to commit.\n");
12612                         goto EXIT;
12613                 }
12614         }
12615
12616         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12617         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12618         player->subtitle_language_list = NULL;
12619         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12620
12621         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12622         if (ret != GST_STATE_CHANGE_SUCCESS) {
12623                 LOGE("failed to change state of textbin to READY");
12624                 result = MM_ERROR_PLAYER_INTERNAL;
12625                 goto EXIT;
12626         }
12627
12628         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12629         if (ret != GST_STATE_CHANGE_SUCCESS) {
12630                 LOGE("failed to change state of subparse to READY");
12631                 result = MM_ERROR_PLAYER_INTERNAL;
12632                 goto EXIT;
12633         }
12634
12635         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12636         if (ret != GST_STATE_CHANGE_SUCCESS) {
12637                 LOGE("failed to change state of filesrc to READY");
12638                 result = MM_ERROR_PLAYER_INTERNAL;
12639                 goto EXIT;
12640         }
12641
12642         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12643
12644         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12645
12646         charset = util_get_charset(filepath);
12647         if (charset) {
12648                 LOGD("detected charset is %s\n", charset);
12649                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12650         }
12651
12652         result = _mmplayer_sync_subtitle_pipeline(player);
12653
12654 EXIT:
12655         MMPLAYER_FLEAVE();
12656         return result;
12657 }
12658
12659 /* API to switch between external subtitles */
12660 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12661 {
12662         int result = MM_ERROR_NONE;
12663         mm_player_t* player = (mm_player_t*)hplayer;
12664         char *path = NULL;
12665
12666         MMPLAYER_FENTER();
12667
12668         /* check player handle */
12669         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12670
12671         /* filepath can be null in idle state */
12672         if (filepath) {
12673                 /* check file path */
12674                 if ((path = strstr(filepath, "file://")))
12675                         result = util_exist_file_path(path + 7);
12676                 else
12677                         result = util_exist_file_path(filepath);
12678
12679                 if (result != MM_ERROR_NONE) {
12680                         LOGE("invalid subtitle path 0x%X", result);
12681                         return result; /* file not found or permission denied */
12682                 }
12683         }
12684
12685         if (!player->pipeline) {
12686                 /* IDLE state */
12687                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12688                 if (mmf_attrs_commit(player->attrs)) {
12689                         LOGE("failed to commit");       /* subtitle path will not be created */
12690                         return MM_ERROR_PLAYER_INTERNAL;
12691                 }
12692         } else {
12693                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12694                 /* check filepath */
12695                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12696
12697                 if (!__mmplayer_check_subtitle(player)) {
12698                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12699                         if (mmf_attrs_commit(player->attrs)) {
12700                                 LOGE("failed to commit");
12701                                 return MM_ERROR_PLAYER_INTERNAL;
12702                         }
12703
12704                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12705                                 LOGE("fail to create text pipeline");
12706                                 return MM_ERROR_PLAYER_INTERNAL;
12707                         }
12708
12709                         result = _mmplayer_sync_subtitle_pipeline(player);
12710                 } else {
12711                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12712                 }
12713
12714                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12715                 player->is_external_subtitle_added_now = TRUE;
12716
12717                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12718                 if (!player->subtitle_language_list) {
12719                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12720                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12721                                 LOGW("subtitle language list is not updated yet");
12722                 }
12723                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12724         }
12725
12726         MMPLAYER_FLEAVE();
12727         return result;
12728 }
12729
12730 static int
12731 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12732 {
12733         int result = MM_ERROR_NONE;
12734         gchar* change_pad_name = NULL;
12735         GstPad* sinkpad = NULL;
12736         MMPlayerGstElement* mainbin = NULL;
12737         enum MainElementID elemId = MMPLAYER_M_NUM;
12738         GstCaps* caps = NULL;
12739         gint total_track_num = 0;
12740
12741         MMPLAYER_FENTER();
12742
12743         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12744                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12745
12746         LOGD("Change Track(%d) to %d\n", type, index);
12747
12748         mainbin = player->pipeline->mainbin;
12749
12750         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12751                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12752         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12753                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12754         } else {
12755                 /* Changing Video Track is not supported. */
12756                 LOGE("Track Type Error\n");
12757                 goto EXIT;
12758         }
12759
12760         if (mainbin[elemId].gst == NULL) {
12761                 result = MM_ERROR_PLAYER_NO_OP;
12762                 LOGD("Req track doesn't exist\n");
12763                 goto EXIT;
12764         }
12765
12766         total_track_num = player->selector[type].total_track_num;
12767         if (total_track_num <= 0) {
12768                 result = MM_ERROR_PLAYER_NO_OP;
12769                 LOGD("Language list is not available \n");
12770                 goto EXIT;
12771         }
12772
12773         if ((index < 0) || (index >= total_track_num)) {
12774                 result = MM_ERROR_INVALID_ARGUMENT;
12775                 LOGD("Not a proper index : %d \n", index);
12776                 goto EXIT;
12777         }
12778
12779         /*To get the new pad from the selector*/
12780         change_pad_name = g_strdup_printf("sink_%u", index);
12781         if (change_pad_name == NULL) {
12782                 result = MM_ERROR_PLAYER_INTERNAL;
12783                 LOGD("Pad does not exists\n");
12784                 goto EXIT;
12785         }
12786
12787         LOGD("new active pad name: %s\n", change_pad_name);
12788
12789         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12790         if (sinkpad == NULL) {
12791                 LOGD("sinkpad is NULL");
12792                 result = MM_ERROR_PLAYER_INTERNAL;
12793                 goto EXIT;
12794         }
12795
12796         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12797         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12798
12799         caps = gst_pad_get_current_caps(sinkpad);
12800         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12801
12802         if (sinkpad)
12803                 gst_object_unref(sinkpad);
12804
12805         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12806                 __mmplayer_set_audio_attrs(player, caps);
12807
12808 EXIT:
12809
12810         MMPLAYER_FREEIF(change_pad_name);
12811         return result;
12812 }
12813
12814 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12815 {
12816         int result = MM_ERROR_NONE;
12817         mm_player_t* player = NULL;
12818         MMPlayerGstElement* mainbin = NULL;
12819
12820         gint current_active_index = 0;
12821
12822         GstState current_state = GST_STATE_VOID_PENDING;
12823         GstEvent* event = NULL;
12824         gint64 time = 0;
12825
12826         MMPLAYER_FENTER();
12827
12828         player = (mm_player_t*)hplayer;
12829         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12830
12831         if (!player->pipeline) {
12832                 LOGE("Track %d pre setting -> %d\n", type, index);
12833
12834                 player->selector[type].active_pad_index = index;
12835                 goto EXIT;
12836         }
12837
12838         mainbin = player->pipeline->mainbin;
12839
12840         current_active_index = player->selector[type].active_pad_index;
12841
12842         /*If index is same as running index no need to change the pad*/
12843         if (current_active_index == index)
12844                 goto EXIT;
12845
12846         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12847                 result = MM_ERROR_PLAYER_INVALID_STATE;
12848                 goto EXIT;
12849         }
12850
12851         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12852         if (current_state < GST_STATE_PAUSED) {
12853                 result = MM_ERROR_PLAYER_INVALID_STATE;
12854                 LOGW("Pipeline not in porper state\n");
12855                 goto EXIT;
12856         }
12857
12858         result = __mmplayer_change_selector_pad(player, type, index);
12859         if (result != MM_ERROR_NONE) {
12860                 LOGE("change selector pad error\n");
12861                 goto EXIT;
12862         }
12863
12864         player->selector[type].active_pad_index = index;
12865
12866         if (current_state == GST_STATE_PLAYING) {
12867                 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);
12868                 if (event) {
12869                         __gst_send_event_to_sink(player, event);
12870                 } else {
12871                         result = MM_ERROR_PLAYER_INTERNAL;
12872                         goto EXIT;
12873                 }
12874         }
12875
12876 EXIT:
12877         return result;
12878 }
12879
12880 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12881 {
12882         mm_player_t* player = (mm_player_t*) hplayer;
12883
12884         MMPLAYER_FENTER();
12885
12886         /* check player handle */
12887         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12888
12889         *silent = player->set_mode.subtitle_off;
12890
12891         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12892
12893         MMPLAYER_FLEAVE();
12894
12895         return MM_ERROR_NONE;
12896 }
12897
12898 gboolean
12899 __is_ms_buff_src(mm_player_t* player)
12900 {
12901         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12902
12903         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12904 }
12905
12906 gboolean
12907 __has_suffix(mm_player_t* player, const gchar* suffix)
12908 {
12909         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12910         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12911
12912         gboolean ret = FALSE;
12913         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12914         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12915
12916         if (g_str_has_suffix(player->profile.uri, suffix))
12917                 ret = TRUE;
12918
12919         MMPLAYER_FREEIF(t_url);
12920         MMPLAYER_FREEIF(t_suffix);
12921
12922         return ret;
12923 }
12924
12925 int
12926 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12927 {
12928         mm_player_t* player = (mm_player_t*) hplayer;
12929
12930         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12931
12932         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12933                 MMPLAYER_PRINT_STATE(player);
12934                 LOGE("wrong-state : can't set the download mode to parse");
12935                 return MM_ERROR_PLAYER_INVALID_STATE;
12936         }
12937
12938         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12939         player->video_hub_download_mode = mode;
12940
12941         return MM_ERROR_NONE;
12942 }
12943
12944 int
12945 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12946 {
12947         mm_player_t* player = (mm_player_t*) hplayer;
12948
12949         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12950
12951         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12952         player->sync_handler = enable;
12953
12954         return MM_ERROR_NONE;
12955 }
12956
12957 int
12958 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12959                                                                                 gint64 video_time, gint64 media_clock, gint64 audio_time)
12960 {
12961         mm_player_t* player = (mm_player_t*) hplayer;
12962         MMPlayerGstElement* mainbin = NULL;
12963         GstClockTime start_time_audio = 0, start_time_video = 0;
12964         GstClockTimeDiff base_time = 0, new_base_time = 0;
12965         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12966         gint64 api_delta = 0;
12967         gint64 position = 0, position_delta = 0;
12968         gint64 adj_base_time = 0;
12969         GstClock *curr_clock = NULL;
12970         GstClockTime curr_time = 0;
12971         gboolean query_ret = TRUE;
12972         int result = MM_ERROR_NONE;
12973
12974         MMPLAYER_FENTER();
12975
12976         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12977         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12978         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12979
12980         /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12981                                                                         clock, clock_delta, video_time, media_clock, audio_time); */
12982
12983         if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
12984                 LOGD("skip setting master clock. %lld", video_time);
12985                 goto EXIT;
12986         }
12987
12988         mainbin = player->pipeline->mainbin;
12989
12990         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12991         curr_time = gst_clock_get_time(curr_clock);
12992
12993         current_state = MMPLAYER_CURRENT_STATE(player);
12994
12995         if (current_state == MM_PLAYER_STATE_PLAYING)
12996                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12997
12998         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12999                 (!query_ret)) {
13000                 position = player->last_position;
13001                 LOGD("query fail. %"G_GINT64_FORMAT, position);
13002         }
13003
13004         clock *= GST_USECOND;
13005         clock_delta *= GST_USECOND;
13006
13007         api_delta = clock - curr_time;
13008         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13009                 player->video_share_api_delta = api_delta;
13010         else
13011                 clock_delta += (api_delta - player->video_share_api_delta);
13012
13013         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13014                 player->video_share_clock_delta = (gint64)clock_delta;
13015
13016                 position_delta = (position/GST_USECOND) - video_time;
13017                 position_delta *= GST_USECOND;
13018
13019                 adj_base_time = position_delta;
13020                 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13021
13022         } else {
13023                 gint64 new_play_time = 0;
13024                 gint64 network_delay = 0;
13025
13026                 video_time *= GST_USECOND;
13027
13028                 network_delay = clock_delta - player->video_share_clock_delta;
13029                 new_play_time = video_time + network_delay;
13030
13031                 adj_base_time = position - new_play_time;
13032
13033                 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13034                          "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13035                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13036         }
13037
13038         /* Adjust Current Stream Time with base_time of sink
13039          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13040          * 2. Set new base time
13041          *    if adj_base_time is positive value, the stream time will be decreased.
13042          * 3. If seek event is occurred, the start time will be reset. */
13043         if ((player->pipeline->audiobin) &&
13044                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13045                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13046
13047                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13048                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13049                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13050                 }
13051
13052                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13053         }
13054
13055         if ((player->pipeline->videobin) &&
13056                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13057                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13058
13059                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13060                         LOGD("video sink : gst_element_set_start_time -> NONE");
13061                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13062                 }
13063
13064                 // if videobin exist, get base_time from videobin.
13065                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13066         }
13067
13068         new_base_time = base_time + adj_base_time;
13069
13070         if ((player->pipeline->audiobin) &&
13071                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13072                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13073
13074         if ((player->pipeline->videobin) &&
13075                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13076                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13077
13078 EXIT:
13079         MMPLAYER_FLEAVE();
13080
13081         return result;
13082 }
13083
13084 int
13085 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13086 {
13087         mm_player_t* player = (mm_player_t*) hplayer;
13088         MMPlayerGstElement* mainbin = NULL;
13089         GstClock *curr_clock = NULL;
13090         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13091         gint64 position = 0;
13092         gboolean query_ret = TRUE;
13093
13094         MMPLAYER_FENTER();
13095
13096         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13097         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13098         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13099
13100         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13101         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13102         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13103
13104         mainbin = player->pipeline->mainbin;
13105
13106         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13107
13108         current_state = MMPLAYER_CURRENT_STATE(player);
13109
13110         if (current_state != MM_PLAYER_STATE_PAUSED)
13111                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13112
13113         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13114                 (!query_ret))
13115                 position = player->last_position;
13116
13117         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13118
13119         LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13120
13121         if (curr_clock)
13122                 gst_object_unref(curr_clock);
13123
13124         MMPLAYER_FLEAVE();
13125
13126         return MM_ERROR_NONE;
13127 }
13128
13129 static gboolean
13130 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13131 {
13132         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13133         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13134
13135         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13136         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13137
13138         int idx = 0;
13139
13140         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13141                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13142                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13143                         mm_player_dump_t *dump_s;
13144                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13145
13146                         if (dump_s == NULL) {
13147                                 LOGE("malloc fail");
13148                                 return FALSE;
13149                         }
13150
13151                         dump_s->dump_element_file = NULL;
13152                         dump_s->dump_pad = NULL;
13153                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13154
13155                         if (dump_s->dump_pad) {
13156                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13157                                 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]);
13158                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13159                                 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);
13160                                 /* add list for removed buffer probe and close FILE */
13161                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13162                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13163                                 return TRUE;
13164                         } else {
13165                                 g_free(dump_s);
13166                                 dump_s = NULL;
13167                                 LOGE("failed to get %s sink pad added", factory_name);
13168                         }
13169
13170
13171                 }
13172         }
13173         return FALSE;
13174 }
13175
13176 static GstPadProbeReturn
13177 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13178 {
13179         FILE *dump_data = (FILE *) u_data;
13180 //      int written = 0;
13181         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13182         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13183
13184         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13185
13186         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13187
13188 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13189
13190         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13191
13192         return GST_PAD_PROBE_OK;
13193 }
13194
13195 static void
13196 __mmplayer_release_dump_list(GList *dump_list)
13197 {
13198         if (dump_list) {
13199                 GList *d_list = dump_list;
13200                 for (; d_list; d_list = g_list_next(d_list)) {
13201                         mm_player_dump_t *dump_s = d_list->data;
13202                         if (dump_s->dump_pad) {
13203                                 if (dump_s->probe_handle_id)
13204                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13205                         }
13206                         if (dump_s->dump_element_file) {
13207                                 fclose(dump_s->dump_element_file);
13208                                 dump_s->dump_element_file = NULL;
13209                         }
13210                         MMPLAYER_FREEIF(dump_s);
13211                 }
13212                 g_list_free(dump_list);
13213                 dump_list = NULL;
13214         }
13215 }
13216
13217 int
13218 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13219 {
13220         mm_player_t* player = (mm_player_t*) hplayer;
13221
13222         MMPLAYER_FENTER();
13223
13224         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13225         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13226
13227         *exist = player->has_closed_caption;
13228
13229         MMPLAYER_FLEAVE();
13230
13231         return MM_ERROR_NONE;
13232 }
13233
13234 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13235 {
13236         MMPLAYER_FENTER();
13237         if (buffer) {
13238                 // LOGD("unref internal gst buffer %p", buffer);
13239                 gst_buffer_unref((GstBuffer *)buffer);
13240                 buffer = NULL;
13241         }
13242         MMPLAYER_FLEAVE();
13243 }
13244
13245 void
13246 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13247 {
13248         mm_player_t *player  = (mm_player_t*)user_data;
13249         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13250         guint64 current_level_bytes = 0;
13251
13252         MMPLAYER_RETURN_IF_FAIL(player);
13253
13254         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13255
13256         LOGI("app-src: feed audio(%llu)", current_level_bytes);
13257         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13258
13259         if (player->media_stream_buffer_status_cb[type])
13260                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13261         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13262
13263 }
13264
13265 void
13266 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13267 {
13268         mm_player_t *player  = (mm_player_t*)user_data;
13269         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13270         guint64 current_level_bytes = 0;
13271
13272         MMPLAYER_RETURN_IF_FAIL(player);
13273
13274         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13275
13276         LOGI("app-src: feed video(%llu)", current_level_bytes);
13277
13278         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13279         if (player->media_stream_buffer_status_cb[type])
13280                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13281         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13282 }
13283
13284 void
13285 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13286 {
13287         mm_player_t *player  = (mm_player_t*)user_data;
13288         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13289         guint64 current_level_bytes = 0;
13290
13291         MMPLAYER_RETURN_IF_FAIL(player);
13292
13293         LOGI("app-src: feed subtitle");
13294
13295         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13296
13297         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13298         if (player->media_stream_buffer_status_cb[type])
13299                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13300
13301         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13302 }
13303
13304 void
13305 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13306 {
13307         mm_player_t *player  = (mm_player_t*)user_data;
13308         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13309         guint64 current_level_bytes = 0;
13310
13311         MMPLAYER_RETURN_IF_FAIL(player);
13312
13313         LOGI("app-src: audio buffer is full");
13314
13315         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13316
13317         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13318
13319         if (player->media_stream_buffer_status_cb[type])
13320                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13321
13322         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13323 }
13324
13325 void
13326 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13327 {
13328         mm_player_t *player  = (mm_player_t*)user_data;
13329         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13330         guint64 current_level_bytes = 0;
13331
13332         MMPLAYER_RETURN_IF_FAIL(player);
13333
13334         LOGI("app-src: video buffer is full");
13335
13336         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13337
13338         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13339         if (player->media_stream_buffer_status_cb[type])
13340                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13341
13342         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13343 }
13344
13345 gboolean
13346 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13347 {
13348         mm_player_t *player  = (mm_player_t*)user_data;
13349         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13350
13351         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13352
13353         LOGD("app-src: seek audio data %llu", position);
13354         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13355
13356         if (player->media_stream_seek_data_cb[type])
13357                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13358         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13359
13360         return TRUE;
13361 }
13362
13363 gboolean
13364 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13365 {
13366         mm_player_t *player  = (mm_player_t*)user_data;
13367         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13368
13369         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13370
13371         LOGD("app-src: seek video data %llu", position);
13372         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13373         if (player->media_stream_seek_data_cb[type])
13374                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13375         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13376
13377         return TRUE;
13378 }
13379
13380 gboolean
13381 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13382 {
13383         mm_player_t *player  = (mm_player_t*)user_data;
13384         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13385
13386         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13387
13388         LOGD("app-src: seek subtitle data");
13389         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13390
13391         if (player->media_stream_seek_data_cb[type])
13392                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13393         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13394
13395         return TRUE;
13396 }
13397
13398 int
13399 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13400 {
13401         mm_player_t* player = (mm_player_t*) hplayer;
13402
13403         MMPLAYER_FENTER();
13404
13405         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13406
13407         player->pcm_samplerate = samplerate;
13408         player->pcm_channel = channel;
13409
13410         MMPLAYER_FLEAVE();
13411         return MM_ERROR_NONE;
13412 }
13413
13414 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13415 {
13416         mm_player_t* player = (mm_player_t*) hplayer;
13417
13418         MMPLAYER_FENTER();
13419
13420         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13421         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13422
13423         if (MMPLAYER_IS_HTTP_PD(player))
13424                 *timeout = player->ini.live_state_change_timeout*2;
13425         else if (MMPLAYER_IS_STREAMING(player))
13426                 *timeout = player->ini.live_state_change_timeout;
13427         else
13428                 *timeout = player->ini.localplayback_state_change_timeout;
13429
13430         LOGD("timeout = %d\n", *timeout);
13431
13432         MMPLAYER_FLEAVE();
13433         return MM_ERROR_NONE;
13434 }
13435
13436 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
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         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13444
13445         *num = player->video_num_buffers;
13446         *extra_num = player->video_extra_num_buffers;
13447
13448         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13449
13450         MMPLAYER_FLEAVE();
13451         return MM_ERROR_NONE;
13452 }
13453
13454 static void
13455 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13456 {
13457         int i = 0;
13458         MMPLAYER_FENTER();
13459         MMPLAYER_RETURN_IF_FAIL(player);
13460
13461         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13462
13463                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13464                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13465                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13466                         player->storage_info[i].id = -1;
13467                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13468
13469                         if (path_type != MMPLAYER_PATH_MAX)
13470                                 break;
13471                 }
13472         }
13473
13474         MMPLAYER_FLEAVE();
13475 }
13476
13477 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13478 {
13479         int ret = MM_ERROR_NONE;
13480         mm_player_t* player = (mm_player_t*)hplayer;
13481         MMMessageParamType msg_param = {0, };
13482
13483         MMPLAYER_FENTER();
13484         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13485
13486         LOGW("state changed storage %d:%d", id, state);
13487
13488         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13489                 return MM_ERROR_NONE;
13490
13491         /* FIXME: text path should be handled seperately. */
13492         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13493                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13494                 LOGW("external storage is removed");
13495
13496                 if (player->msg_posted == FALSE) {
13497                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13498                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13499                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13500                         player->msg_posted = TRUE;
13501                 }
13502
13503                 /* unrealize the player */
13504                 ret = _mmplayer_unrealize(hplayer);
13505                 if (ret != MM_ERROR_NONE)
13506                         LOGE("failed to unrealize");
13507         }
13508
13509         MMPLAYER_FLEAVE();
13510         return ret;
13511 }
13512
13513 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13514 {
13515         int ret = MM_ERROR_NONE;
13516         mm_player_t* player = (mm_player_t*) hplayer;
13517         int idx = 0, total = 0;
13518         gchar *result = NULL, *tmp = NULL;
13519
13520         MMPLAYER_FENTER();
13521         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13522         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13523
13524         total = *num = g_list_length(player->adaptive_info.var_list);
13525         if (total <= 0) {
13526                 LOGW("There is no stream variant info.");
13527                 return ret;
13528         }
13529
13530         result = g_strdup("");
13531         for (idx = 0 ; idx < total ; idx++) {
13532                 VariantData *v_data = NULL;
13533                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13534
13535                 if (v_data) {
13536                         gchar data[64] = {0};
13537                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13538
13539                         tmp = g_strconcat(result, data, NULL);
13540                         g_free(result);
13541                         result = tmp;
13542                 } else {
13543                         LOGW("There is no variant data in %d", idx);
13544                         (*num)--;
13545                 }
13546         }
13547
13548         *var_info = (char *)result;
13549
13550         LOGD("variant info %d:%s", *num, *var_info);
13551         MMPLAYER_FLEAVE();
13552         return ret;
13553 }
13554
13555 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13556 {
13557         int ret = MM_ERROR_NONE;
13558         mm_player_t* player = (mm_player_t*) hplayer;
13559
13560         MMPLAYER_FENTER();
13561         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13562
13563         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13564
13565         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13566         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13567         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13568
13569         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13570                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13571                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13572                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13573
13574                 /* FIXME: seek to current position for applying new variant limitation */
13575         }
13576
13577         MMPLAYER_FLEAVE();
13578         return ret;
13579
13580 }
13581
13582 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13583 {
13584         int ret = MM_ERROR_NONE;
13585         mm_player_t* player = (mm_player_t*) hplayer;
13586
13587         MMPLAYER_FENTER();
13588         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13589         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13590
13591         *bandwidth = player->adaptive_info.limit.bandwidth;
13592         *width = player->adaptive_info.limit.width;
13593         *height = player->adaptive_info.limit.height;
13594
13595         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13596
13597         MMPLAYER_FLEAVE();
13598         return ret;
13599 }
13600
13601 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13602 {
13603         int ret = MM_ERROR_NONE;
13604         mm_player_t* player = (mm_player_t*) hplayer;
13605
13606         MMPLAYER_FENTER();
13607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13608
13609         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13610                 LOGW("buffer_ms will not be applied.");
13611
13612
13613         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13614
13615         if (player->streamer == NULL) {
13616                 player->streamer = __mm_player_streaming_create();
13617                 __mm_player_streaming_initialize(player->streamer);
13618         }
13619
13620         if (buffer_ms >= 0)
13621                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13622
13623         if (rebuffer_ms >= 0)
13624                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13625
13626         MMPLAYER_FLEAVE();
13627         return ret;
13628
13629 }
13630
13631 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13632 {
13633         int ret = MM_ERROR_NONE;
13634         mm_player_t* player = (mm_player_t*) hplayer;
13635
13636         MMPLAYER_FENTER();
13637         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13639
13640         if (player->streamer == NULL) {
13641                 player->streamer = __mm_player_streaming_create();
13642                 __mm_player_streaming_initialize(player->streamer);
13643         }
13644
13645         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13646         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13647
13648         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13649
13650         MMPLAYER_FLEAVE();
13651         return ret;
13652 }
13653
13654 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13655 {
13656 #define IDX_FIRST_SW_CODEC 0
13657         mm_player_t* player = (mm_player_t*) hplayer;
13658         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13659         MMHandleType attrs = 0;
13660
13661         MMPLAYER_FENTER();
13662         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13663
13664         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13665                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13666                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13667
13668         switch (stream_type) {
13669         case MM_PLAYER_STREAM_TYPE_AUDIO:
13670                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13671                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13672                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13673                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13674                         LOGE("There is no a codec for codec_type %d", codec_type);
13675                         return MM_ERROR_PLAYER_NO_OP;
13676                 }
13677         break;
13678         case MM_PLAYER_STREAM_TYPE_VIDEO:
13679                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13680                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13681                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13682                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13683                         LOGE("There is no v codec for codec_type %d", codec_type);
13684                         return MM_ERROR_PLAYER_NO_OP;
13685                 }
13686
13687         break;
13688         default:
13689                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13690                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13691         break;
13692         }
13693
13694         LOGD("update %s codec_type to %d", attr_name, codec_type);
13695
13696         attrs = MMPLAYER_GET_ATTRS(player);
13697         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13698
13699         if (mmf_attrs_commit(player->attrs)) {
13700                 LOGE("failed to commit codec_type attributes");
13701                 return MM_ERROR_PLAYER_INTERNAL;
13702         }
13703
13704         MMPLAYER_FLEAVE();
13705         return MM_ERROR_NONE;
13706 }
13707
13708 int
13709 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13710 {
13711         mm_player_t* player = (mm_player_t*) hplayer;
13712         GstElement* rg_vol_element = NULL;
13713
13714         MMPLAYER_FENTER();
13715
13716         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13717
13718         player->sound.rg_enable = enabled;
13719
13720         /* just hold rgvolume enable value if pipeline is not ready */
13721         if (!player->pipeline || !player->pipeline->audiobin) {
13722                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13723                 return MM_ERROR_NONE;
13724         }
13725
13726         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13727
13728         if (!rg_vol_element) {
13729                 LOGD("rgvolume element is not created");
13730                 return MM_ERROR_PLAYER_INTERNAL;
13731         }
13732
13733         if (enabled)
13734                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13735         else
13736                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13737
13738         MMPLAYER_FLEAVE();
13739
13740         return MM_ERROR_NONE;
13741 }
13742
13743 int
13744 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13745 {
13746         mm_player_t* player = (mm_player_t*) hplayer;
13747         GstElement* rg_vol_element = NULL;
13748         gboolean enable = FALSE;
13749
13750         MMPLAYER_FENTER();
13751
13752         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13753         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13754
13755         /* just hold enable_rg value if pipeline is not ready */
13756         if (!player->pipeline || !player->pipeline->audiobin) {
13757                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13758                 *enabled = player->sound.rg_enable;
13759                 return MM_ERROR_NONE;
13760         }
13761
13762         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13763
13764         if (!rg_vol_element) {
13765                 LOGD("rgvolume element is not created");
13766                 return MM_ERROR_PLAYER_INTERNAL;
13767         }
13768
13769         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13770         *enabled = enable;
13771
13772         MMPLAYER_FLEAVE();
13773
13774         return MM_ERROR_NONE;
13775 }