fixed building failure
[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 #include <mm_sound.h>
44 #include <mm_sound_focus.h>
45
46 #include "mm_player_priv.h"
47 #include "mm_player_ini.h"
48 #include "mm_player_attrs.h"
49 #include "mm_player_capture.h"
50 #include "mm_player_utils.h"
51 #include "mm_player_tracks.h"
52 #include "mm_player_360.h"
53
54 #include <system_info.h>
55 #include <sound_manager.h>
56
57 /*===========================================================================================
58 |                                                                                                                                                                                       |
59 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
60 |                                                                                                                                                                                       |
61 ========================================================================================== */
62
63 /*---------------------------------------------------------------------------
64 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
65 ---------------------------------------------------------------------------*/
66
67 /*---------------------------------------------------------------------------
68 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
69 ---------------------------------------------------------------------------*/
70
71 /*---------------------------------------------------------------------------
72 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
73 ---------------------------------------------------------------------------*/
74
75 /*---------------------------------------------------------------------------
76 |    LOCAL #defines:                                                                                                            |
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
80
81 #define MM_VOLUME_FACTOR_DEFAULT                1.0
82 #define MM_VOLUME_FACTOR_MIN                    0
83 #define MM_VOLUME_FACTOR_MAX                    1.0
84
85 /* Don't need to sleep for sound fadeout
86  * fadeout related fucntion will be deleted(Deprecated)
87  */
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
89
90 #define DEFAULT_PLAYBACK_RATE                   1.0
91 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
92
93 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
94         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
95         (player->ini.http_use_file_buffer) && \
96         (player->http_file_buffering_path) && \
97         (strlen(player->http_file_buffering_path) > 0))
98
99 #define PLAYER_DISPLAY_MODE_DST_ROI             5
100
101 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102
103 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
104 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 100
105
106 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
107
108 /*---------------------------------------------------------------------------
109 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
110 ---------------------------------------------------------------------------*/
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
122 ---------------------------------------------------------------------------*/
123 static sound_stream_info_h stream_info;
124
125 /*---------------------------------------------------------------------------
126 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
127 ---------------------------------------------------------------------------*/
128 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
129 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
130 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
131 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
132 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
134 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
135
136 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
137 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
138 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
139 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
140 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
141 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
142 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
143 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
144 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
145 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
146 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
147 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
148 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
149 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
150 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
151 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
152 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
153
154 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
155 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
156 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
157 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static void             __mmplayer_release_misc(mm_player_t* player);
159 static void             __mmplayer_release_misc_post(mm_player_t* player);
160 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
161 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
162 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
163 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
164 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
165 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
166 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
169 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
171
172 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
173 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
174 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
175 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
176 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
177 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
178 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
179 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
180 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
181 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
182 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
183 static gpointer __mmplayer_next_play_thread(gpointer data);
184 static gpointer __mmplayer_repeat_thread(gpointer data);
185 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
186
187 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
188 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
189 static void __mmplayer_release_dump_list(GList *dump_list);
190
191 static int              __gst_realize(mm_player_t* player);
192 static int              __gst_unrealize(mm_player_t* player);
193 static int              __gst_start(mm_player_t* player);
194 static int              __gst_stop(mm_player_t* player);
195 static int              __gst_pause(mm_player_t* player, gboolean async);
196 static int              __gst_resume(mm_player_t* player, gboolean async);
197 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
198                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
199                                         gint64 cur, GstSeekType stop_type, gint64 stop);
200 static int __gst_pending_seek(mm_player_t* player);
201
202 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
203 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
204 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
205 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
206 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
207
208 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
209
210 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
211 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
212
213 /*fadeout */
214 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
215 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
216
217 /* util */
218 static gboolean __is_ms_buff_src(mm_player_t* player);
219 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
220
221 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
222 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
223 static int __mmplayer_start_streaming_ext(mm_player_t *player);
224 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
225 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
226
227 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
228 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
229 static void __mmplayer_check_pipeline(mm_player_t* player);
230 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
231 static void __mmplayer_deactivate_old_path(mm_player_t *player);
232
233 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
234 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
235
236 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
237 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
238 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
239 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
240 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
241 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
242 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
243 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
247 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
248 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
249 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
250 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
251 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
252
253 /*===========================================================================================
254 |                                                                                                                                                                                       |
255 |  FUNCTION DEFINITIONS                                                                                                                                         |
256 |                                                                                                                                                                                       |
257 ========================================================================================== */
258
259 #if 0 //debug
260 static void
261 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
262 {
263         gint i, count;
264
265         count = gst_tag_list_get_tag_size(list, tag);
266
267         LOGD("count = %d", count);
268
269         for (i = 0; i < count; i++) {
270                 gchar *str;
271
272                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
273                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
274                                 g_assert_not_reached();
275                 } else
276                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
277
278                 if (i == 0)
279                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
280                 else
281                         g_print("                 : %s\n", str);
282
283                 g_free(str);
284         }
285 }
286 #endif
287
288 /* This function should be called after the pipeline goes PAUSED or higher
289 state. */
290 gboolean
291 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
292 {
293         static gboolean has_duration = FALSE;
294         static gboolean has_video_attrs = FALSE;
295         static gboolean has_audio_attrs = FALSE;
296         static gboolean has_bitrate = FALSE;
297         gboolean missing_only = FALSE;
298         gboolean all = FALSE;
299         gint64 dur_nsec = 0;
300         GstStructure* p = NULL;
301         MMHandleType attrs = 0;
302         gchar *path = NULL;
303         MMStreamingType stream_service_type = STREAMING_SERVICE_NONE;
304         struct stat sb;
305
306         MMPLAYER_FENTER();
307
308         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
309
310         /* check player state here */
311         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
312                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
313                 /* give warning now only */
314                 LOGW("be careful. content attributes may not available in this state ");
315         }
316
317         /* get content attribute first */
318         attrs = MMPLAYER_GET_ATTRS(player);
319         if (!attrs) {
320                 LOGE("cannot get content attribute");
321                 return FALSE;
322         }
323
324         /* get update flag */
325
326         if (flag & ATTR_MISSING_ONLY) {
327                 missing_only = TRUE;
328                 LOGD("updating missed attr only");
329         }
330
331         if (flag & ATTR_ALL) {
332                 all = TRUE;
333                 has_duration = FALSE;
334                 has_video_attrs = FALSE;
335                 has_audio_attrs = FALSE;
336                 has_bitrate = FALSE;
337
338                 LOGD("updating all attrs");
339         }
340
341         if (missing_only && all) {
342                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
343                 missing_only = FALSE;
344         }
345
346         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
347                 LOGD("try to update duration");
348                 has_duration = FALSE;
349
350                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
351                         player->duration = dur_nsec;
352                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
353                 }
354
355                 if (player->duration < 0) {
356                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
357                         player->duration = 0;
358                 }
359
360                 /* try to get streaming service type */
361                 stream_service_type = __mmplayer_get_stream_service_type(player);
362                 if (stream_service_type < STREAMING_SERVICE_NONE)
363                         mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
364
365                 /* check duration is OK */
366                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
367                         /* FIXIT : find another way to get duration here. */
368                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
369                 } else {
370                         /*update duration */
371                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
372                         has_duration = TRUE;
373                 }
374         }
375
376         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
377                 /* update audio params
378                 NOTE : We need original audio params and it can be only obtained from src pad of audio
379                 decoder. Below code only valid when we are not using 'resampler' just before
380                 'audioconverter'. */
381
382                 LOGD("try to update audio attrs");
383                 has_audio_attrs = FALSE;
384
385                 if (player->pipeline->audiobin &&
386                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
387                         GstCaps *caps_a = NULL;
388                         GstPad* pad = NULL;
389                         gint samplerate = 0, channels = 0;
390
391                         pad = gst_element_get_static_pad(
392                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
393
394                         if (pad) {
395                                 caps_a = gst_pad_get_current_caps(pad);
396
397                                 if (caps_a) {
398                                         p = gst_caps_get_structure(caps_a, 0);
399
400                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
401
402                                         gst_structure_get_int(p, "rate", &samplerate);
403                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
404
405                                         gst_structure_get_int(p, "channels", &channels);
406                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
407
408                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
409
410                                         gst_caps_unref(caps_a);
411                                         caps_a = NULL;
412
413                                         has_audio_attrs = TRUE;
414                                 } else
415                                         LOGW("not ready to get audio caps");
416
417                                 gst_object_unref(pad);
418                         } else
419                                 LOGW("failed to get pad from audiosink");
420                 }
421         }
422
423         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
424                 LOGD("try to update video attrs");
425                 has_video_attrs = FALSE;
426
427                 if (player->pipeline->videobin &&
428                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
429                         GstCaps *caps_v = NULL;
430                         GstPad* pad = NULL;
431                         gint tmpNu, tmpDe;
432                         gint width, height;
433
434                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
435                         if (pad) {
436                                 caps_v = gst_pad_get_current_caps(pad);
437
438                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
439                                 if (!caps_v && player->v_stream_caps) {
440                                         caps_v = player->v_stream_caps;
441                                         gst_caps_ref(caps_v);
442                                 }
443
444                                 if (caps_v) {
445                                         p = gst_caps_get_structure(caps_v, 0);
446                                         gst_structure_get_int(p, "width", &width);
447                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
448
449                                         gst_structure_get_int(p, "height", &height);
450                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
451
452                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
453
454                                         SECURE_LOGD("width : %d     height : %d", width, height);
455
456                                         gst_caps_unref(caps_v);
457                                         caps_v = NULL;
458
459                                         if (tmpDe > 0) {
460                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
461                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
462                                         }
463
464                                         has_video_attrs = TRUE;
465                                 } else
466                                         LOGD("no negitiated caps from videosink");
467                                 gst_object_unref(pad);
468                                 pad = NULL;
469                         } else
470                                 LOGD("no videosink sink pad");
471                 }
472         }
473
474
475         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
476                 has_bitrate = FALSE;
477
478                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
479                 if (player->duration) {
480                         guint64 data_size = 0;
481
482                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
483                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
484
485                                 if (stat(path, &sb) == 0)
486                                         data_size = (guint64)sb.st_size;
487                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
488                                 data_size = player->http_content_size;
489                         }
490                         LOGD("try to update bitrate : data_size = %lld", data_size);
491
492                         if (data_size) {
493                                 guint64 bitrate = 0;
494                                 guint64 msec_dur = 0;
495
496                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
497                                 if (msec_dur > 0) {
498                                         bitrate = data_size * 8 * 1000 / msec_dur;
499                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
500                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
501
502                                         has_bitrate = TRUE;
503                                 } else {
504                                         LOGD("player duration is less than 0");
505                                 }
506                         }
507
508                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
509                                 if (player->total_bitrate) {
510                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
511                                         has_bitrate = TRUE;
512                                 }
513                         }
514                 }
515         }
516
517         /* validate all */
518         if (mmf_attrs_commit(attrs)) {
519                 LOGE("failed to update attributes\n");
520                 return FALSE;
521         }
522
523         MMPLAYER_FLEAVE();
524
525         return TRUE;
526 }
527
528 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
529 {
530         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
531
532         MMPLAYER_FENTER();
533
534         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
535                         player->pipeline &&
536                         player->pipeline->mainbin &&
537                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
538                         STREAMING_SERVICE_NONE);
539
540         /* streaming service type if streaming */
541         if (!MMPLAYER_IS_STREAMING(player))
542                 return STREAMING_SERVICE_NONE;
543
544         if (MMPLAYER_IS_HTTP_STREAMING(player))
545                 streaming_type = (player->duration == 0) ?
546                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
547
548         switch (streaming_type) {
549         case STREAMING_SERVICE_LIVE:
550                 LOGD("it's live streaming");
551                 break;
552         case STREAMING_SERVICE_VOD:
553                 LOGD("it's vod streaming");
554                 break;
555         default:
556                 LOGE("should not get here");
557         }
558
559         player->streaming_type = streaming_type;
560         MMPLAYER_FLEAVE();
561
562         return streaming_type;
563 }
564
565
566 /* this function sets the player state and also report
567  * it to applicaton by calling callback function
568  */
569 int
570 __mmplayer_set_state(mm_player_t* player, int state)
571 {
572         MMMessageParamType msg = {0, };
573         int sound_result = MM_ERROR_NONE;
574         gboolean post_bos = FALSE;
575         gboolean interrupted_by_focus = FALSE;
576
577         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
578
579         if (MMPLAYER_CURRENT_STATE(player) == state) {
580                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
581                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
582                 return MM_ERROR_NONE;
583         }
584
585         /* update player states */
586         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
587         MMPLAYER_CURRENT_STATE(player) = state;
588
589         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
590                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
591
592         /* print state */
593         MMPLAYER_PRINT_STATE(player);
594
595         /* do some FSM stuffs before posting new state to application  */
596         interrupted_by_focus = player->sound_focus.by_asm_cb;
597
598         switch (MMPLAYER_CURRENT_STATE(player)) {
599         case MM_PLAYER_STATE_NULL:
600         case MM_PLAYER_STATE_READY:
601                 {
602                         if (player->cmd == MMPLAYER_COMMAND_STOP) {
603                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
604                                 if (sound_result != MM_ERROR_NONE) {
605                                         LOGE("failed to release sound focus\n");
606                                         return MM_ERROR_POLICY_INTERNAL;
607                                 }
608                         }
609                 }
610                 break;
611
612         case MM_PLAYER_STATE_PAUSED:
613                 {
614                          if (!player->sent_bos) {
615                                 int found = 0;
616                                 #define MMPLAYER_MAX_SOUND_PRIORITY     3
617
618                                 /* rtsp case, get content attrs by GstMessage */
619                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
620                                         /* it's first time to update all content attrs. */
621                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
622                                 }
623
624                                 /* set max sound priority to keep own sound and not to mute other's one */
625                                 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
626                                 if (found) {
627                                         mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
628                                         if (found) {
629                                                 LOGD("set max audio priority");
630                                                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
631                                         }
632                                 }
633
634                          }
635
636                         /* add audio callback probe if condition is satisfied */
637                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
638                                 __mmplayer_configure_audio_callback(player);
639                                 /* FIXIT : handle return value */
640
641                         if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
642                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
643                                 if (sound_result != MM_ERROR_NONE) {
644                                         LOGE("failed to release sound focus\n");
645                                         return MM_ERROR_POLICY_INTERNAL;
646                                 }
647                         }
648                 }
649                 break;
650
651         case MM_PLAYER_STATE_PLAYING:
652                 {
653                         /* try to get content metadata */
654                         if (!player->sent_bos) {
655                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
656                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
657                                  * legacy mmfw-player api */
658                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
659                         }
660
661                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
662                                 if (!player->sent_bos)
663                                         __mmplayer_handle_missed_plugin(player);
664                                 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
665                                 if (sound_result != MM_ERROR_NONE) {
666                                         // FIXME : need to check history
667                                         if (player->pipeline->videobin) {
668                                                 MMMessageParamType msg = {0, };
669
670                                                 LOGE("failed to go ahead because of video conflict\n");
671
672                                                 msg.union_type = MM_MSG_UNION_CODE;
673                                                 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
674                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
675
676                                                 _mmplayer_unrealize((MMHandleType)player);
677                                         } else {
678                                                 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
679                                                 _mmplayer_pause((MMHandleType)player);
680                                         }
681
682                                         return MM_ERROR_POLICY_INTERNAL;
683                                 }
684                         }
685
686                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
687                                 /* initialize because auto resume is done well. */
688                                 player->resumed_by_rewind = FALSE;
689                                 player->playback_rate = 1.0;
690                         }
691
692                         if (!player->sent_bos) {
693                                 /* check audio codec field is set or not
694                                  * we can get it from typefinder or codec's caps.
695                                  */
696                                 gchar *audio_codec = NULL;
697                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
698
699                                 /* The codec format can't be sent for audio only case like amr, mid etc.
700                                  * Because, parser don't make related TAG.
701                                  * So, if it's not set yet, fill it with found data.
702                                  */
703                                 if (!audio_codec) {
704                                         if (g_strrstr(player->type, "audio/midi"))
705                                                 audio_codec = g_strdup("MIDI");
706                                         else if (g_strrstr(player->type, "audio/x-amr"))
707                                                 audio_codec = g_strdup("AMR");
708                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
709                                                 audio_codec = g_strdup("AAC");
710                                         else
711                                                 audio_codec = g_strdup("unknown");
712                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
713
714                                         MMPLAYER_FREEIF(audio_codec);
715                                         if (mmf_attrs_commit(player->attrs))
716                                                 LOGE("failed to update attributes\n");
717
718                                         LOGD("set audio codec type with caps\n");
719                                 }
720
721                                 post_bos = TRUE;
722                         }
723                 }
724                 break;
725
726         case MM_PLAYER_STATE_NONE:
727         default:
728                 LOGW("invalid target state, there is nothing to do.\n");
729                 break;
730         }
731
732
733         /* post message to application */
734         if (MMPLAYER_TARGET_STATE(player) == state) {
735                 /* fill the message with state of player */
736                 msg.union_type = MM_MSG_UNION_STATE;
737                 msg.state.previous = MMPLAYER_PREV_STATE(player);
738                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
739
740                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
741
742                 /* state changed by focus or resource callback */
743                 if (interrupted_by_focus || player->interrupted_by_resource) {
744                         if (interrupted_by_focus)
745                                 msg.state.code = player->sound_focus.focus_changed_msg;
746                         else if (player->interrupted_by_resource)
747                                 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
748                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
749                 } else { /* state changed by usecase */
750                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
751                 }
752         } else {
753                 LOGD("intermediate state, do nothing.\n");
754                 MMPLAYER_PRINT_STATE(player);
755                 return MM_ERROR_NONE;
756         }
757
758         if (post_bos) {
759                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
760                 player->sent_bos = TRUE;
761         }
762
763         return MM_ERROR_NONE;
764 }
765
766 static gpointer __mmplayer_next_play_thread(gpointer data)
767 {
768         mm_player_t* player = (mm_player_t*) data;
769         MMPlayerGstElement *mainbin = NULL;
770
771         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
772
773         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
774         while (!player->next_play_thread_exit) {
775                 LOGD("next play thread started. waiting for signal.\n");
776                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
777
778                 LOGD("reconfigure pipeline for gapless play.\n");
779
780                 if (player->next_play_thread_exit) {
781                         if (player->gapless.reconfigure) {
782                                 player->gapless.reconfigure = false;
783                                 MMPLAYER_PLAYBACK_UNLOCK(player);
784                         }
785                         LOGD("exiting gapless play thread\n");
786                         break;
787                 }
788
789                 mainbin = player->pipeline->mainbin;
790
791                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
792                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
793                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
794                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
795                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
796
797                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
798         }
799         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
800
801         return NULL;
802 }
803
804 static gpointer __mmplayer_repeat_thread(gpointer data)
805 {
806         mm_player_t* player = (mm_player_t*) data;
807         gboolean ret_value = FALSE;
808         MMHandleType attrs = 0;
809         gint count = 0;
810
811         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
812
813         MMPLAYER_REPEAT_THREAD_LOCK(player);
814         while (!player->repeat_thread_exit) {
815                 LOGD("repeat thread started. waiting for signal.\n");
816                 MMPLAYER_REPEAT_THREAD_WAIT(player);
817
818                 if (player->repeat_thread_exit) {
819                         LOGD("exiting repeat thread\n");
820                         break;
821                 }
822
823
824                 /* lock */
825                 MMPLAYER_CMD_LOCK(player);
826
827                 attrs = MMPLAYER_GET_ATTRS(player);
828
829                 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
830                         LOGE("can not get play count\n");
831                         MMPLAYER_CMD_UNLOCK(player);
832                         break;
833                 }
834
835                 if (player->section_repeat) {
836                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
837                 } else {
838                         if (player->playback_rate < 0.0) {
839                                 player->resumed_by_rewind = TRUE;
840                                 _mmplayer_set_mute((MMHandleType)player, 0);
841                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
842                         }
843
844                         ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
845                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
846                                 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
847
848                         /* initialize */
849                         player->sent_bos = FALSE;
850                 }
851
852                 if (!ret_value) {
853                         LOGE("failed to set position to zero for rewind\n");
854                         MMPLAYER_CMD_UNLOCK(player);
855                         continue;
856                 }
857
858                 /* decrease play count */
859                 if (count > 1) {
860                         /* we successeded to rewind. update play count and then wait for next EOS */
861                         count--;
862
863                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
864
865                         /* commit attribute */
866                         if (mmf_attrs_commit(attrs))
867                                 LOGE("failed to commit attribute\n");
868                 }
869
870                 /* unlock */
871                 MMPLAYER_CMD_UNLOCK(player);
872         }
873
874         MMPLAYER_REPEAT_THREAD_UNLOCK(player);
875         return NULL;
876 }
877
878 static void
879 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
880 {
881         MMHandleType attrs = 0;
882         guint64 data_size = 0;
883         gchar* path = NULL;
884         unsigned long pos_msec = 0;
885         struct stat sb;
886
887         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
888
889         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
890
891         attrs = MMPLAYER_GET_ATTRS(player);
892         if (!attrs) {
893                 LOGE("fail to get attributes.\n");
894                 return;
895         }
896
897         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
898                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
899
900                 if (stat(path, &sb) == 0)
901                         data_size = (guint64)sb.st_size;
902         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
903                 data_size = player->http_content_size;
904
905         __mm_player_streaming_buffering(player->streamer,
906                                                                                 buffering_msg,
907                                                                                 data_size,
908                                                                                 player->last_position,
909                                                                                 player->duration);
910
911         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
912
913         return;
914 }
915
916 static int
917 __mmplayer_handle_buffering_message(mm_player_t* player)
918 {
919         int ret = MM_ERROR_NONE;
920         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
921         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
922         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
923         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
924
925         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
926                 LOGW("do nothing for buffering msg\n");
927                 ret = MM_ERROR_PLAYER_INVALID_STATE;
928                 goto exit;
929         }
930
931         prev_state = MMPLAYER_PREV_STATE(player);
932         current_state = MMPLAYER_CURRENT_STATE(player);
933         target_state = MMPLAYER_TARGET_STATE(player);
934         pending_state = MMPLAYER_PENDING_STATE(player);
935
936         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
937                 MMPLAYER_STATE_GET_NAME(prev_state),
938                 MMPLAYER_STATE_GET_NAME(current_state),
939                 MMPLAYER_STATE_GET_NAME(pending_state),
940                 MMPLAYER_STATE_GET_NAME(target_state),
941                 player->streamer->is_buffering);
942
943         if (!player->streamer->is_buffering) {
944                 /* NOTE : if buffering has done, player has to go to target state. */
945                 switch (target_state) {
946                 case MM_PLAYER_STATE_PAUSED:
947                         {
948                                 switch (pending_state) {
949                                 case MM_PLAYER_STATE_PLAYING:
950                                         __gst_pause(player, TRUE);
951                                         break;
952
953                                 case MM_PLAYER_STATE_PAUSED:
954                                         LOGD("player is already going to paused state, there is nothing to do.\n");
955                                         break;
956
957                                 case MM_PLAYER_STATE_NONE:
958                                 case MM_PLAYER_STATE_NULL:
959                                 case MM_PLAYER_STATE_READY:
960                                 default:
961                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
962                                         break;
963                                 }
964                         }
965                         break;
966
967                 case MM_PLAYER_STATE_PLAYING:
968                         {
969                                 switch (pending_state) {
970                                 case MM_PLAYER_STATE_NONE:
971                                         {
972                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
973                                                         __gst_resume(player, TRUE);
974                                         }
975                                         break;
976
977                                 case MM_PLAYER_STATE_PAUSED:
978                                         /* NOTE: It should be worked as asynchronously.
979                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
980                                          */
981                                         __gst_resume(player, TRUE);
982                                         break;
983
984                                 case MM_PLAYER_STATE_PLAYING:
985                                         LOGD("player is already going to playing state, there is nothing to do.\n");
986                                         break;
987
988                                 case MM_PLAYER_STATE_NULL:
989                                 case MM_PLAYER_STATE_READY:
990                                 default:
991                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
992                                         break;
993                                 }
994                         }
995                         break;
996
997                 case MM_PLAYER_STATE_NULL:
998                 case MM_PLAYER_STATE_READY:
999                 case MM_PLAYER_STATE_NONE:
1000                 default:
1001                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1002                         break;
1003                 }
1004         } else {
1005                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1006                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1007                  */
1008                 switch (pending_state) {
1009                 case MM_PLAYER_STATE_NONE:
1010                         {
1011                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1012                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1013                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1014                                                 LOGD("set pause state during buffering\n");
1015                                                 __gst_pause(player, TRUE);
1016                                         }
1017                                 }
1018                         }
1019                         break;
1020
1021                 case MM_PLAYER_STATE_PLAYING:
1022                         /* rtsp streaming pause makes rtsp server stop sending data. */
1023                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1024                                 __gst_pause(player, TRUE);
1025                         break;
1026
1027                 case MM_PLAYER_STATE_PAUSED:
1028                         break;
1029
1030                 case MM_PLAYER_STATE_NULL:
1031                 case MM_PLAYER_STATE_READY:
1032                 default:
1033                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1034                         break;
1035                 }
1036         }
1037
1038 exit:
1039         return ret;
1040 }
1041
1042 static void
1043 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1044 {
1045         MMPlayerGstElement *textbin;
1046         MMPLAYER_FENTER();
1047
1048         MMPLAYER_RETURN_IF_FAIL(player &&
1049                                         player->pipeline &&
1050                                         player->pipeline->textbin);
1051
1052         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1053
1054         textbin = player->pipeline->textbin;
1055
1056         if (is_drop) {
1057                 LOGD("Drop subtitle text after getting EOS\n");
1058
1059                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1060                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1061
1062                 player->is_subtitle_force_drop = TRUE;
1063         } else {
1064                 if (player->is_subtitle_force_drop == TRUE) {
1065                         LOGD("Enable subtitle data path without drop\n");
1066
1067                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1068                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1069
1070                         LOGD("non-connected with external display");
1071
1072                         player->is_subtitle_force_drop = FALSE;
1073                 }
1074         }
1075 }
1076
1077 static VariantData *
1078 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1079 {
1080         VariantData *var_info = NULL;
1081         g_return_val_if_fail(self != NULL, NULL);
1082
1083         var_info = g_new0(VariantData, 1);
1084         if (!var_info) return NULL;
1085         var_info->bandwidth = self->bandwidth;
1086         var_info->width = self->width;
1087         var_info->height = self->height;
1088         return var_info;
1089 }
1090
1091 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
1092 {
1093         mm_player_t* player = (mm_player_t*)hplayer;
1094
1095         MMPLAYER_FENTER();
1096         MMPLAYER_RETURN_IF_FAIL(player);
1097
1098         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1099
1100         /* destroy the gst bus msg thread */
1101         if (player->bus_msg_thread) {
1102                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1103                 player->bus_msg_thread_exit = TRUE;
1104                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1105                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1106
1107                 LOGD("gst bus msg thread exit.");
1108                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
1109                 player->bus_msg_thread = NULL;
1110
1111                 g_mutex_clear(&player->bus_msg_thread_mutex);
1112                 g_cond_clear(&player->bus_msg_thread_cond);
1113         }
1114
1115         MMPLAYER_FLEAVE();
1116 }
1117
1118 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1119 {
1120         mm_player_t *player = (mm_player_t*)(data);
1121         GstMessage *msg = NULL;
1122         GstBus *bus = NULL;
1123
1124         MMPLAYER_FENTER();
1125         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1126                                                 player->pipeline &&
1127                                                 player->pipeline->mainbin &&
1128                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1129                                                 NULL);
1130
1131         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1132         if (!bus) {
1133                 LOGE("cannot get BUS from the pipeline");
1134                 return NULL;
1135         }
1136
1137         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1138
1139         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1140         while (!player->bus_msg_thread_exit) {
1141                 msg = gst_bus_pop(bus);
1142                 if (msg == NULL) {
1143                         int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1144                         MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1145                         continue;
1146                 }
1147
1148                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1149                 /* handle the gst msg */
1150                 __mmplayer_gst_callback(msg, player);
1151                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1152                 gst_message_unref(msg);
1153         }
1154
1155         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1156         gst_object_unref(GST_OBJECT(bus));
1157
1158         MMPLAYER_FLEAVE();
1159         return NULL;
1160 }
1161
1162 static void
1163 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1164 {
1165         mm_player_t* player = (mm_player_t*)(data);
1166         static gboolean async_done = FALSE;
1167
1168         MMPLAYER_RETURN_IF_FAIL(player);
1169         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1170
1171         switch (GST_MESSAGE_TYPE(msg)) {
1172         case GST_MESSAGE_UNKNOWN:
1173                 LOGD("unknown message received\n");
1174                 break;
1175
1176         case GST_MESSAGE_EOS:
1177                 {
1178                         MMHandleType attrs = 0;
1179                         gint count = 0;
1180
1181                         LOGD("GST_MESSAGE_EOS received\n");
1182
1183                         /* NOTE : EOS event is comming multiple time. watch out it */
1184                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1185                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1186                                 LOGD("EOS received on non-playing state. ignoring it\n");
1187                                 break;
1188                         }
1189
1190                         if (player->pipeline) {
1191                                 if (player->pipeline->textbin)
1192                                         __mmplayer_drop_subtitle(player, TRUE);
1193
1194                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1195                                         GstPad *pad = NULL;
1196
1197                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1198
1199                                         LOGD("release audio callback\n");
1200
1201                                         /* release audio callback */
1202                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1203                                         player->audio_cb_probe_id = 0;
1204                                         /* audio callback should be free because it can be called even though probe remove.*/
1205                                         player->audio_stream_cb = NULL;
1206                                         player->audio_stream_cb_user_param = NULL;
1207
1208                                 }
1209                         }
1210                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1211                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1212
1213                         /* rewind if repeat count is greater then zero */
1214                         /* get play count */
1215                         attrs = MMPLAYER_GET_ATTRS(player);
1216
1217                         if (attrs) {
1218                                 gboolean smooth_repeat = FALSE;
1219
1220                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1221                                 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1222
1223                                 player->play_count = count;
1224
1225                                 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1226
1227                                 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1228                                         if (smooth_repeat) {
1229                                                 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1230
1231                                                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1232
1233                                                 break;
1234                                         } else {
1235                                                 gint ret_value = 0;
1236
1237                                                 if (player->section_repeat) {
1238                                                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1239                                                 } else {
1240                                                         if (player->playback_rate < 0.0) {
1241                                                                 player->resumed_by_rewind = TRUE;
1242                                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1243                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1244                                                         }
1245
1246                                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1247
1248                                                         /* initialize */
1249                                                         player->sent_bos = FALSE;
1250                                                 }
1251
1252                                                 if (MM_ERROR_NONE != ret_value)
1253                                                         LOGE("failed to set position to zero for rewind\n");
1254
1255                                                 /* not posting eos when repeating */
1256                                                 break;
1257                                         }
1258                                 }
1259                         }
1260
1261                         if (player->pipeline)
1262                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1263
1264                         /* post eos message to application */
1265                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1266
1267                         /* reset last position */
1268                         player->last_position = 0;
1269                 }
1270                 break;
1271
1272         case GST_MESSAGE_ERROR:
1273                 {
1274                         GError *error = NULL;
1275                         gchar* debug = NULL;
1276
1277                         /* generating debug info before returning error */
1278                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1279
1280                         /* get error code */
1281                         gst_message_parse_error(msg, &error, &debug);
1282
1283                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1284                                 /* Note : the streaming error from the streaming source is handled
1285                                  *   using __mmplayer_handle_streaming_error.
1286                                  */
1287                                 __mmplayer_handle_streaming_error(player, msg);
1288
1289                                 /* dump state of all element */
1290                                 __mmplayer_dump_pipeline_state(player);
1291                         } else {
1292                                 /* traslate gst error code to msl error code. then post it
1293                                  * to application if needed
1294                                  */
1295                                 __mmplayer_handle_gst_error(player, msg, error);
1296
1297                                 if (debug)
1298                                         LOGE("error debug : %s", debug);
1299                         }
1300
1301                         if (MMPLAYER_IS_HTTP_PD(player))
1302                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1303
1304                         MMPLAYER_FREEIF(debug);
1305                         g_error_free(error);
1306                 }
1307                 break;
1308
1309         case GST_MESSAGE_WARNING:
1310                 {
1311                         char* debug = NULL;
1312                         GError* error = NULL;
1313
1314                         gst_message_parse_warning(msg, &error, &debug);
1315
1316                         LOGD("warning : %s\n", error->message);
1317                         LOGD("debug : %s\n", debug);
1318
1319                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1320
1321                         MMPLAYER_FREEIF(debug);
1322                         g_error_free(error);
1323                 }
1324                 break;
1325
1326         case GST_MESSAGE_TAG:
1327                 {
1328                         LOGD("GST_MESSAGE_TAG\n");
1329                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1330                                 LOGW("failed to extract tags from gstmessage\n");
1331                 }
1332                 break;
1333
1334         case GST_MESSAGE_BUFFERING:
1335                 {
1336                         MMMessageParamType msg_param = {0, };
1337                         int bRet = MM_ERROR_NONE;
1338
1339                         if (!(player->pipeline && player->pipeline->mainbin)) {
1340                                 LOGE("player pipeline handle is null");
1341                                 break;
1342                         }
1343
1344                         if (!MMPLAYER_IS_STREAMING(player))
1345                                 break;
1346
1347                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1348                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1349                                         /* skip the playback control by buffering msg while user request is handled. */
1350                                         gint per = 0;
1351
1352                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1353
1354                                         gst_message_parse_buffering(msg, &per);
1355                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1356
1357                                         msg_param.connection.buffering = per;
1358                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1359                                         break;
1360                                 }
1361                         } else {
1362                                 MMPLAYER_CMD_LOCK(player);
1363                         }
1364
1365                         /* ignore the prev buffering message */
1366                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1367                                 && (player->streamer->is_buffering_done == TRUE)) {
1368                                 gint buffer_percent = 0;
1369
1370                                 gst_message_parse_buffering(msg, &buffer_percent);
1371
1372                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1373                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1374                                         player->streamer->is_buffering_done = FALSE;
1375                                 }
1376                                 MMPLAYER_CMD_UNLOCK(player);
1377                                 break;
1378                         }
1379
1380                         __mmplayer_update_buffer_setting(player, msg);
1381
1382                         bRet = __mmplayer_handle_buffering_message(player);
1383
1384                         if (bRet == MM_ERROR_NONE) {
1385                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1386                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1387
1388                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1389                                         player->pending_resume &&
1390                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1391
1392                                         player->is_external_subtitle_added_now = FALSE;
1393                                         player->pending_resume = FALSE;
1394                                         _mmplayer_resume((MMHandleType)player);
1395                                 }
1396
1397                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1398                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1399
1400                                         if (player->doing_seek) {
1401                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1402                                                         player->doing_seek = FALSE;
1403                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1404                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1405                                                         async_done = TRUE;
1406                                                 }
1407                                         }
1408                                 }
1409                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1410                                 if (!player->streamer) {
1411                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1412                                         MMPLAYER_CMD_UNLOCK(player);
1413                                         break;
1414                                 }
1415
1416                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1417
1418                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1419                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1420
1421                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1422                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1423                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1424                                         } else {
1425                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1426                                         }
1427                                 } else {
1428                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1429                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1430                                 }
1431                         }
1432                         MMPLAYER_CMD_UNLOCK(player);
1433                 }
1434                 break;
1435
1436         case GST_MESSAGE_STATE_CHANGED:
1437                 {
1438                         MMPlayerGstElement *mainbin;
1439                         const GValue *voldstate, *vnewstate, *vpending;
1440                         GstState oldstate = GST_STATE_NULL;
1441                         GstState newstate = GST_STATE_NULL;
1442                         GstState pending = GST_STATE_NULL;
1443
1444                         if (!(player->pipeline && player->pipeline->mainbin)) {
1445                                 LOGE("player pipeline handle is null");
1446                                 break;
1447                         }
1448
1449                         mainbin = player->pipeline->mainbin;
1450
1451                         /* we only handle messages from pipeline */
1452                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1453                                 break;
1454
1455                         /* get state info from msg */
1456                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1457                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1458                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1459
1460                         if (!voldstate || !vnewstate) {
1461                                 LOGE("received msg has wrong format.");
1462                                 break;
1463                         }
1464
1465                         oldstate = (GstState)voldstate->data[0].v_int;
1466                         newstate = (GstState)vnewstate->data[0].v_int;
1467                         if (vpending)
1468                                 pending = (GstState)vpending->data[0].v_int;
1469
1470                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1471                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1472                                 gst_element_state_get_name((GstState)oldstate),
1473                                 gst_element_state_get_name((GstState)newstate),
1474                                 gst_element_state_get_name((GstState)pending));
1475
1476                         if (newstate == GST_STATE_PLAYING) {
1477                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1478
1479                                         int retVal = MM_ERROR_NONE;
1480                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1481
1482                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1483
1484                                         if (MM_ERROR_NONE != retVal)
1485                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1486
1487                                         player->pending_seek.is_pending = FALSE;
1488                                 }
1489                         }
1490
1491                         if (oldstate == newstate) {
1492                                 LOGD("pipeline reports state transition to old state");
1493                                 break;
1494                         }
1495
1496                         switch (newstate) {
1497                         case GST_STATE_VOID_PENDING:
1498                                 break;
1499
1500                         case GST_STATE_NULL:
1501                                 break;
1502
1503                         case GST_STATE_READY:
1504                                 break;
1505
1506                         case GST_STATE_PAUSED:
1507                                 {
1508                                         gboolean prepare_async = FALSE;
1509                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1510
1511                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1512                                                 __mmplayer_configure_audio_callback(player);
1513
1514                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1515                                                 // managed prepare async case
1516                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1517                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1518                                         }
1519
1520                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1521                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1522
1523                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1524                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1525                                                                 player->total_maximum_bitrate, player->total_bitrate);
1526
1527                                                 if (player->pending_seek.is_pending) {
1528                                                         LOGW("trying to do pending seek");
1529                                                         MMPLAYER_CMD_LOCK(player);
1530                                                         __gst_pending_seek(player);
1531                                                         MMPLAYER_CMD_UNLOCK(player);
1532                                                 }
1533                                         }
1534                                 }
1535                                 break;
1536
1537                         case GST_STATE_PLAYING:
1538                                 {
1539                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1540
1541                                         if (MMPLAYER_IS_STREAMING(player)) {
1542                                                 // managed prepare async case when buffering is completed
1543                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1544                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1545                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1546                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1547
1548                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1549
1550                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1551                                                         if (player->streamer->buffering_percent < 100) {
1552
1553                                                                 MMMessageParamType msg_param = {0, };
1554                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1555
1556                                                                 msg_param.connection.buffering = 100;
1557                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1558                                                         }
1559                                                 }
1560                                         }
1561
1562                                         if (player->gapless.stream_changed) {
1563                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1564                                                 player->gapless.stream_changed = FALSE;
1565                                         }
1566
1567                                         if (player->doing_seek && async_done) {
1568                                                 player->doing_seek = FALSE;
1569                                                 async_done = FALSE;
1570                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1571                                         }
1572                                 }
1573                                 break;
1574
1575                         default:
1576                                 break;
1577                         }
1578                 }
1579                 break;
1580
1581         case GST_MESSAGE_CLOCK_LOST:
1582                         {
1583                                 GstClock *clock = NULL;
1584                                 gboolean need_new_clock = FALSE;
1585
1586                                 gst_message_parse_clock_lost(msg, &clock);
1587                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1588
1589                                 if (!player->videodec_linked)
1590                                         need_new_clock = TRUE;
1591                                 else if (!player->ini.use_system_clock)
1592                                         need_new_clock = TRUE;
1593
1594                                 if (need_new_clock) {
1595                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1596                                         __gst_pause(player, FALSE);
1597                                         __gst_resume(player, FALSE);
1598                                 }
1599                         }
1600                         break;
1601
1602         case GST_MESSAGE_NEW_CLOCK:
1603                         {
1604                                 GstClock *clock = NULL;
1605                                 gst_message_parse_new_clock(msg, &clock);
1606                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1607                         }
1608                         break;
1609
1610         case GST_MESSAGE_ELEMENT:
1611                         {
1612                                 const gchar *structure_name;
1613                                 gint count = 0, idx = 0;
1614                                 MMHandleType attrs = 0;
1615
1616                                 attrs = MMPLAYER_GET_ATTRS(player);
1617                                 if (!attrs) {
1618                                         LOGE("cannot get content attribute");
1619                                         break;
1620                                 }
1621
1622                                 if (gst_message_get_structure(msg) == NULL)
1623                                         break;
1624
1625                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1626                                 if (!structure_name)
1627                                         break;
1628
1629                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1630
1631                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1632                                         const GValue *var_info = NULL;
1633
1634                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1635                                         if (var_info != NULL) {
1636                                                 if (player->adaptive_info.var_list)
1637                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1638
1639                                                 /* share addr or copy the list */
1640                                                 player->adaptive_info.var_list =
1641                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1642
1643                                                 count = g_list_length(player->adaptive_info.var_list);
1644                                                 if (count > 0) {
1645                                                         VariantData *temp = NULL;
1646
1647                                                         /* print out for debug */
1648                                                         LOGD("num of variant_info %d", count);
1649                                                         for (idx = 0; idx < count; idx++) {
1650                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1651                                                                 if (temp)
1652                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1653                                                         }
1654                                                 }
1655                                         }
1656                                 }
1657
1658                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1659                                         gint num_buffers = 0;
1660                                         gint extra_num_buffers = 0;
1661
1662                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1663                                                 player->video_num_buffers = num_buffers;
1664                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1665                                         }
1666
1667                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1668                                                 player->video_extra_num_buffers = extra_num_buffers;
1669                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1670                                         }
1671                                         break;
1672                                 }
1673
1674                                 if (!strcmp(structure_name, "Language_list")) {
1675                                         const GValue *lang_list = NULL;
1676                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1677                                         if (lang_list != NULL) {
1678                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1679                                                 if (count > 1)
1680                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1681                                         }
1682                                 }
1683
1684                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1685                                         const GValue *lang_list = NULL;
1686                                         MMPlayerLangStruct *temp = NULL;
1687
1688                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1689                                         if (lang_list != NULL) {
1690                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1691                                                 if (count) {
1692                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1693                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1694                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1695                                                         if (mmf_attrs_commit(attrs))
1696                                                                 LOGE("failed to commit.\n");
1697                                                         LOGD("Total subtitle tracks = %d \n", count);
1698
1699                                                         while (count) {
1700                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1701                                                                 if (temp)
1702                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1703                                                                                                 temp->language_key, temp->language_code);
1704                                                                 count--;
1705                                                         }
1706                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1707                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1708                                                 }
1709                                         }
1710                                 }
1711
1712                                 /* custom message */
1713                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1714                                         MMMessageParamType msg_param = {0,};
1715                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1716                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1717                                 }
1718
1719                                 /* custom message for RTSP attribute :
1720                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1721                                     sdp which has contents info is received when rtsp connection is opened.
1722                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1723                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1724
1725                                         gchar *audio_codec = NULL;
1726                                         gchar *video_codec = NULL;
1727                                         gchar *video_frame_size = NULL;
1728
1729                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1730                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1731                                         __mmplayer_get_stream_service_type(player);
1732                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1733
1734                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1735                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1736                                         if (audio_codec)
1737                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1738
1739                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1740                                         LOGD("rtsp_video_codec : %s", video_codec);
1741                                         if (video_codec)
1742                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1743
1744                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1745                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1746                                         if (video_frame_size) {
1747
1748                                                 char *seperator = strchr(video_frame_size, '-');
1749                                                 if (seperator) {
1750
1751                                                         char video_width[10] = {0,};
1752                                                         int frame_size_len = strlen(video_frame_size);
1753                                                         int separtor_len = strlen(seperator);
1754
1755                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1756                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1757
1758                                                         seperator++;
1759                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1760                                                 }
1761                                         }
1762
1763                                         if (mmf_attrs_commit(attrs))
1764                                                 LOGE("failed to commit.\n");
1765                                 }
1766                         }
1767                         break;
1768
1769         case GST_MESSAGE_DURATION_CHANGED:
1770                 {
1771                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1772                         if (!__mmplayer_gst_handle_duration(player, msg))
1773                                 LOGW("failed to update duration");
1774                 }
1775
1776                 break;
1777
1778         case GST_MESSAGE_ASYNC_START:
1779                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1780                 break;
1781
1782         case GST_MESSAGE_ASYNC_DONE:
1783                 {
1784                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1785
1786                         /* we only handle messages from pipeline */
1787                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1788                                 break;
1789
1790                         if (player->doing_seek) {
1791                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1792                                         player->doing_seek = FALSE;
1793                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1794                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1795                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1796                                                 (player->streamer) &&
1797                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1798                                                 (player->streamer->is_buffering == FALSE)) {
1799                                                 GstQuery *query = NULL;
1800                                                 gboolean busy = FALSE;
1801                                                 gint percent = 0;
1802
1803                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1804                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1805                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1806                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1807                                                         gst_query_unref(query);
1808
1809                                                         LOGD("buffered percent(%s): %d\n",
1810                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1811                                                 }
1812
1813                                                 if (percent >= 100) {
1814                                                         player->streamer->is_buffering = FALSE;
1815                                                         __mmplayer_handle_buffering_message(player);
1816                                                 }
1817                                         }
1818
1819                                         async_done = TRUE;
1820                                 }
1821                         }
1822                 }
1823                 break;
1824
1825         #if 0 /* delete unnecessary logs */
1826         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1827         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1828         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1829         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1830         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1831         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1832         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1833         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1834         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1835         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1836         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1837         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1838         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1839         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1840         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1841         #endif
1842
1843         default:
1844                 break;
1845         }
1846
1847         /* should not call 'gst_message_unref(msg)' */
1848         return;
1849 }
1850
1851 static gboolean
1852 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1853 {
1854         gint64 bytes = 0;
1855
1856         MMPLAYER_FENTER();
1857
1858         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1859         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1860
1861         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1862                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1863                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1864
1865                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1866                         LOGD("data total size of http content: %lld", bytes);
1867                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1868                 }
1869         } else
1870                 /* handling audio clip which has vbr. means duration is keep changing */
1871                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1872
1873         MMPLAYER_FLEAVE();
1874
1875         return TRUE;
1876 }
1877
1878 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1879                 mm_player_spherical_metadata_t *metadata) {
1880         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1881         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1882         gst_tag_list_get_string(tags, "stitching_software",
1883                         &metadata->stitching_software);
1884         gst_tag_list_get_string(tags, "projection_type",
1885                         &metadata->projection_type_string);
1886         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1887         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1888         gst_tag_list_get_int(tags, "init_view_heading",
1889                         &metadata->init_view_heading);
1890         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1891         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1892         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1893         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1894                         &metadata->full_pano_width_pixels);
1895         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1896                         &metadata->full_pano_height_pixels);
1897         gst_tag_list_get_int(tags, "cropped_area_image_width",
1898                         &metadata->cropped_area_image_width);
1899         gst_tag_list_get_int(tags, "cropped_area_image_height",
1900                         &metadata->cropped_area_image_height);
1901         gst_tag_list_get_int(tags, "cropped_area_left",
1902                         &metadata->cropped_area_left);
1903         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1904         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1905         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1906         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1907 }
1908
1909 static gboolean
1910 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1911 {
1912
1913 /* macro for better code readability */
1914 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1915 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1916         if (string != NULL) { \
1917                 SECURE_LOGD("update tag string : %s\n", string); \
1918                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1919                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1920                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1921                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1922                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1923                         g_free(new_string); \
1924                         new_string = NULL; \
1925                 } else { \
1926                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1927                 } \
1928                 g_free(string); \
1929                 string = NULL; \
1930         } \
1931 }
1932
1933 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1934 do {    \
1935         GstSample *sample = NULL;\
1936         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1937                 GstMapInfo info = GST_MAP_INFO_INIT;\
1938                 buffer = gst_sample_get_buffer(sample);\
1939                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1940                         LOGD("failed to get image data from tag");\
1941                         gst_sample_unref(sample);\
1942                         return FALSE;\
1943                 } \
1944                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1945                 MMPLAYER_FREEIF(player->album_art);\
1946                 player->album_art = (gchar *)g_malloc(info.size);\
1947                 if (player->album_art) {\
1948                         memcpy(player->album_art, info.data, info.size);\
1949                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1950                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1951                                 msg_param.data = (void *)player->album_art;\
1952                                 msg_param.size = info.size;\
1953                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1954                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1955                         } \
1956                 } \
1957                 gst_buffer_unmap(buffer, &info);\
1958                 gst_sample_unref(sample);\
1959         }       \
1960 } while (0)
1961
1962 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1963 do {    \
1964         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1965                 if (v_uint) { \
1966                         int i = 0; \
1967                         gchar *tag_list_str = NULL; \
1968                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1969                         tag_list_str = gst_tag_list_to_string(tag_list); \
1970                         if (tag_list_str && strstr(tag_list_str, "audio")) \
1971                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1972                         else if (tag_list_str && strstr(tag_list_str, "video")) \
1973                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1974                         else \
1975                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1976                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1977                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1978                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1979                                 player->bitrate[track_type] = v_uint; \
1980                                 player->total_bitrate = 0; \
1981                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1982                                         player->total_bitrate += player->bitrate[i]; \
1983                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1984                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1985                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1986                                 player->maximum_bitrate[track_type] = v_uint; \
1987                                 player->total_maximum_bitrate = 0; \
1988                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1989                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1990                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1991                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1992                         } else { \
1993                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1994                         } \
1995                         v_uint = 0;\
1996                         g_free(tag_list_str); \
1997                 } \
1998         } \
1999 } while (0)
2000
2001 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
2002 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
2003         if (date != NULL) {\
2004                 string = g_strdup_printf("%d", g_date_get_year(date));\
2005                 mm_attrs_set_string_by_name(attribute, playertag, string);\
2006                 SECURE_LOGD("metainfo year : %s\n", string);\
2007                 MMPLAYER_FREEIF(string);\
2008                 g_date_free(date);\
2009         } \
2010 }
2011
2012 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
2013 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
2014         if (datetime != NULL) {\
2015                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
2016                 mm_attrs_set_string_by_name(attribute, playertag, string);\
2017                 SECURE_LOGD("metainfo year : %s\n", string);\
2018                 MMPLAYER_FREEIF(string);\
2019                 gst_date_time_unref(datetime);\
2020         } \
2021 }
2022
2023 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2024 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
2025         if (v_uint64) {\
2026                 /* FIXIT : don't know how to store date */\
2027                 g_assert(1);\
2028                 v_uint64 = 0;\
2029         } \
2030 }
2031
2032 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2033 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
2034         if (v_double) {\
2035                 /* FIXIT : don't know how to store date */\
2036                 g_assert(1);\
2037                 v_double = 0;\
2038         } \
2039 }
2040
2041         /* function start */
2042         GstTagList* tag_list = NULL;
2043
2044         MMHandleType attrs = 0;
2045
2046         char *string = NULL;
2047         guint v_uint = 0;
2048         GDate *date = NULL;
2049         GstDateTime *datetime = NULL;
2050         /* album cover */
2051         GstBuffer *buffer = NULL;
2052         gint index = 0;
2053         MMMessageParamType msg_param = {0, };
2054
2055         /* currently not used. but those are needed for above macro */
2056         //guint64 v_uint64 = 0;
2057         //gdouble v_double = 0;
2058
2059         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
2060
2061         attrs = MMPLAYER_GET_ATTRS(player);
2062
2063         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
2064
2065         /* get tag list from gst message */
2066         gst_message_parse_tag(msg, &tag_list);
2067
2068         /* store tags to player attributes */
2069         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2070         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2071         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2072         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2073         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2074         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2075         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2076         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2077         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
2078         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2079         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2080         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2081         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2082         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2083         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2084         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2085         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2086         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2087         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2088         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2089         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2090         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2091         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2092         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2093         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2094         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2095         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2096         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2097         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2098         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2099         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2100         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2101         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2102         MMPLAYER_UPDATE_TAG_LOCK(player);
2103         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2104         MMPLAYER_UPDATE_TAG_UNLOCK(player);
2105         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2106         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2107         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2108         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2109         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2110         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2111         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2112         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2113         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2114         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2115         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2116         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2117         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2118
2119         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2120                 if (player->video360_metadata.is_spherical == -1) {
2121                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2122                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2123                                         player->video360_metadata.is_spherical);
2124                         if (player->video360_metadata.is_spherical == 1) {
2125                                 LOGD("This is spherical content for 360 playback.");
2126                                 player->is_content_spherical = TRUE;
2127                         } else {
2128                                 LOGD("This is not spherical content");
2129                                 player->is_content_spherical = FALSE;
2130                         }
2131
2132                         if (player->video360_metadata.projection_type_string) {
2133                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2134                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2135                                 } else {
2136                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2137                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2138                                 }
2139                         }
2140
2141                         if (player->video360_metadata.stereo_mode_string) {
2142                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2143                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2144                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2145                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2146                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2147                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2148                                 } else {
2149                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2150                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2151                                 }
2152                         }
2153                 }
2154         }
2155
2156         if (mmf_attrs_commit(attrs))
2157                 LOGE("failed to commit.\n");
2158
2159         gst_tag_list_free(tag_list);
2160
2161         return TRUE;
2162 }
2163
2164 static void
2165 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2166 {
2167         mm_player_t* player = (mm_player_t*) data;
2168
2169         MMPLAYER_FENTER();
2170
2171         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2172           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2173           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2174           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2175
2176           * [1] audio and video will be dumped with filesink.
2177           * [2] autoplugging is done by just using pad caps.
2178           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2179           * and the video will be dumped via filesink.
2180           */
2181         if (player->num_dynamic_pad == 0) {
2182                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2183
2184                 if (!__mmplayer_gst_remove_fakesink(player,
2185                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2186                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2187                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2188                          * source element are not same. To overcome this situation, this function will called
2189                          * several places and several times. Therefore, this is not an error case.
2190                          */
2191                         return;
2192         }
2193
2194         /* create dot before error-return. for debugging */
2195         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2196
2197         player->no_more_pad = TRUE;
2198
2199         MMPLAYER_FLEAVE();
2200 }
2201
2202 static gboolean
2203 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2204 {
2205         GstElement* parent = NULL;
2206
2207         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2208
2209         /* if we have no fakesink. this meas we are using decodebin which doesn'
2210         t need to add extra fakesink */
2211         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2212
2213         /* lock */
2214         MMPLAYER_FSINK_LOCK(player);
2215
2216         if (!fakesink->gst)
2217                 goto ERROR;
2218
2219         /* get parent of fakesink */
2220         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2221         if (!parent) {
2222                 LOGD("fakesink already removed\n");
2223                 goto ERROR;
2224         }
2225
2226         gst_element_set_locked_state(fakesink->gst, TRUE);
2227
2228         /* setting the state to NULL never returns async
2229          * so no need to wait for completion of state transiton
2230          */
2231         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2232                 LOGE("fakesink state change failure!\n");
2233                 /* FIXIT : should I return here? or try to proceed to next? */
2234                 /* return FALSE; */
2235
2236         /* remove fakesink from it's parent */
2237         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2238                 LOGE("failed to remove fakesink\n");
2239
2240                 gst_object_unref(parent);
2241
2242                 goto ERROR;
2243         }
2244
2245         gst_object_unref(parent);
2246
2247         LOGD("state-holder removed\n");
2248
2249         gst_element_set_locked_state(fakesink->gst, FALSE);
2250
2251         MMPLAYER_FSINK_UNLOCK(player);
2252         return TRUE;
2253
2254 ERROR:
2255         if (fakesink->gst)
2256                 gst_element_set_locked_state(fakesink->gst, FALSE);
2257
2258         MMPLAYER_FSINK_UNLOCK(player);
2259         return FALSE;
2260 }
2261
2262
2263 static void
2264 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2265 {
2266         GstPad *sinkpad = NULL;
2267         GstCaps* caps = NULL;
2268         GstElement* new_element = NULL;
2269         GstStructure* str = NULL;
2270         const gchar* name = NULL;
2271
2272         mm_player_t* player = (mm_player_t*) data;
2273
2274         MMPLAYER_FENTER();
2275
2276         MMPLAYER_RETURN_IF_FAIL(element && pad);
2277         MMPLAYER_RETURN_IF_FAIL(player &&
2278                                         player->pipeline &&
2279                                         player->pipeline->mainbin);
2280
2281
2282         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2283          * num_dynamic_pad will decreased after creating a sinkbin.
2284          */
2285         player->num_dynamic_pad++;
2286         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2287
2288         caps = gst_pad_query_caps(pad, NULL);
2289
2290         MMPLAYER_CHECK_NULL(caps);
2291
2292         /* clear  previous result*/
2293         player->have_dynamic_pad = FALSE;
2294
2295         str = gst_caps_get_structure(caps, 0);
2296
2297         if (!str) {
2298                 LOGE("cannot get structure from caps.\n");
2299                 goto ERROR;
2300         }
2301
2302         name = gst_structure_get_name(str);
2303         if (!name) {
2304                 LOGE("cannot get mimetype from structure.\n");
2305                 goto ERROR;
2306         }
2307
2308         if (strstr(name, "video")) {
2309                 gint stype = 0;
2310                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2311
2312                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2313                         if (player->v_stream_caps) {
2314                                 gst_caps_unref(player->v_stream_caps);
2315                                 player->v_stream_caps = NULL;
2316                         }
2317
2318                         new_element = gst_element_factory_make("fakesink", NULL);
2319                         player->num_dynamic_pad--;
2320                         goto NEW_ELEMENT;
2321                 }
2322         }
2323
2324         /* clear  previous result*/
2325         player->have_dynamic_pad = FALSE;
2326
2327         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2328                 LOGE("failed to autoplug for caps");
2329                 goto ERROR;
2330         }
2331
2332         /* check if there's dynamic pad*/
2333         if (player->have_dynamic_pad) {
2334                 LOGE("using pad caps assums there's no dynamic pad !\n");
2335                 goto ERROR;
2336         }
2337
2338         gst_caps_unref(caps);
2339         caps = NULL;
2340
2341 NEW_ELEMENT:
2342
2343         /* excute new_element if created*/
2344         if (new_element) {
2345                 LOGD("adding new element to pipeline\n");
2346
2347                 /* set state to READY before add to bin */
2348                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2349
2350                 /* add new element to the pipeline */
2351                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2352                         LOGE("failed to add autoplug element to bin\n");
2353                         goto ERROR;
2354                 }
2355
2356                 /* get pad from element */
2357                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2358                 if (!sinkpad) {
2359                         LOGE("failed to get sinkpad from autoplug element\n");
2360                         goto ERROR;
2361                 }
2362
2363                 /* link it */
2364                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2365                         LOGE("failed to link autoplug element\n");
2366                         goto ERROR;
2367                 }
2368
2369                 gst_object_unref(sinkpad);
2370                 sinkpad = NULL;
2371
2372                 /* run. setting PLAYING here since streamming source is live source */
2373                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2374         }
2375
2376         if (caps)
2377                 gst_caps_unref(caps);
2378
2379         MMPLAYER_FLEAVE();
2380
2381         return;
2382
2383 STATE_CHANGE_FAILED:
2384 ERROR:
2385         /* FIXIT : take care if new_element has already added to pipeline */
2386         if (new_element)
2387                 gst_object_unref(GST_OBJECT(new_element));
2388
2389         if (sinkpad)
2390                 gst_object_unref(GST_OBJECT(sinkpad));
2391
2392         if (caps)
2393                 gst_caps_unref(caps);
2394
2395         /* FIXIT : how to inform this error to MSL ????? */
2396         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2397          * then post an error to application
2398          */
2399 }
2400
2401 static GstPadProbeReturn
2402 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2403 {
2404         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2405         return GST_PAD_PROBE_OK;
2406 }
2407
2408 static GstPadProbeReturn
2409 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2410 {
2411         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2412         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2413         mm_player_t* player = (mm_player_t*)data;
2414         GstCaps* caps = NULL;
2415         GstStructure* str = NULL;
2416         const gchar* name = NULL;
2417         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2418
2419
2420         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2421                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2422                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2423                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2424                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2425                         return ret;
2426         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2427                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2428                         return ret;
2429         }
2430
2431         caps = gst_pad_query_caps(pad, NULL);
2432         if (!caps) {
2433                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2434                 return ret;
2435         }
2436
2437         str = gst_caps_get_structure(caps, 0);
2438         if (!str) {
2439                 LOGE("failed to get structure from caps");
2440                 goto ERROR;
2441         }
2442
2443         name = gst_structure_get_name(str);
2444         if (!name) {
2445                 LOGE("failed to get name from str");
2446                 goto ERROR;
2447         }
2448
2449         if (strstr(name, "audio")) {
2450                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2451         } else if (strstr(name, "video")) {
2452                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2453         } else {
2454                 /* text track is not supportable */
2455                 LOGE("invalid name %s", name);
2456                 goto ERROR;
2457         }
2458
2459         switch (GST_EVENT_TYPE(event)) {
2460         case GST_EVENT_EOS:
2461                 {
2462                         /* in case of gapless, drop eos event not to send it to sink */
2463                         if (player->gapless.reconfigure && !player->msg_posted) {
2464                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2465                                 ret = GST_PAD_PROBE_DROP;
2466                         }
2467                         break;
2468                 }
2469         case GST_EVENT_STREAM_START:
2470                 {
2471                         gint64 stop_running_time = 0;
2472                         gint64 position_running_time = 0;
2473                         gint64 position = 0;
2474                         gint idx = 0;
2475
2476                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2477                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2478                                         !(player->selector[idx].event_probe_id)) {
2479                                         /* LOGW("[%d] skip", idx); */
2480                                         continue;
2481                                 }
2482
2483                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2484                                         stop_running_time =
2485                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2486                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2487                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2488                                         stop_running_time =
2489                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2490                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2491                                 } else {
2492                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2493                                         stop_running_time =
2494                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2495                                                                 GST_FORMAT_TIME, player->duration);
2496                                 }
2497
2498                                 position_running_time =
2499                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2500                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2501
2502                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2503                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2504                                         idx,
2505                                         GST_TIME_ARGS(stop_running_time),
2506                                         GST_TIME_ARGS(position_running_time),
2507                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2508                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2509
2510                                 position_running_time = MAX(position_running_time, stop_running_time);
2511                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2512                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2513                                 position_running_time = MAX(0, position_running_time);
2514                                 position = MAX(position, position_running_time);
2515                         }
2516
2517                         if (position != 0) {
2518                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2519                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2520                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2521
2522                                 player->gapless.start_time[stream_type] += position;
2523                         }
2524                         break;
2525                 }
2526         case GST_EVENT_FLUSH_STOP:
2527                 {
2528                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2529                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2530                         player->gapless.start_time[stream_type] = 0;
2531                         break;
2532                 }
2533         case GST_EVENT_SEGMENT:
2534                 {
2535                         GstSegment segment;
2536                         GstEvent *tmpev;
2537
2538                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2539                         gst_event_copy_segment(event, &segment);
2540
2541                         if (segment.format == GST_FORMAT_TIME) {
2542                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2543                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2544                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2545                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2546                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2547                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2548
2549                                 /* keep the all the segment ev to cover the seeking */
2550                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2551                                 player->gapless.update_segment[stream_type] = TRUE;
2552
2553                                 if (!player->gapless.running)
2554                                         break;
2555
2556                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2557
2558                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2559
2560                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2561                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2562                                 gst_event_unref(event);
2563                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2564                         }
2565                         break;
2566                 }
2567         case GST_EVENT_QOS:
2568                 {
2569                         gdouble proportion = 0.0;
2570                         GstClockTimeDiff diff = 0;
2571                         GstClockTime timestamp = 0;
2572                         gint64 running_time_diff = -1;
2573                         GstQOSType type = 0;
2574                         GstEvent *tmpev = NULL;
2575
2576                         running_time_diff = player->gapless.segment[stream_type].base;
2577
2578                         if (running_time_diff <= 0) /* don't need to adjust */
2579                                 break;
2580
2581                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2582                         gst_event_unref(event);
2583
2584                         if (timestamp < running_time_diff) {
2585                                 LOGW("QOS event from previous group");
2586                                 ret = GST_PAD_PROBE_DROP;
2587                                 break;
2588                         }
2589
2590                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2591                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2592                                                 stream_type, GST_TIME_ARGS(timestamp),
2593                                                 GST_TIME_ARGS(running_time_diff),
2594                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2595
2596                         timestamp -= running_time_diff;
2597
2598                         /* That case is invalid for QoS events */
2599                         if (diff < 0 && -diff > timestamp) {
2600                                 LOGW("QOS event from previous group");
2601                                 ret = GST_PAD_PROBE_DROP;
2602                                 break;
2603                         }
2604
2605                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2606                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2607
2608                         break;
2609                 }
2610         default:
2611                 break;
2612         }
2613
2614 ERROR:
2615         if (caps)
2616                 gst_caps_unref(caps);
2617         return ret;
2618 }
2619
2620 static void
2621 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2622 {
2623         mm_player_t* player = NULL;
2624         GstElement* pipeline = NULL;
2625         GstElement* selector = NULL;
2626         GstElement* fakesink = NULL;
2627         GstCaps* caps = NULL;
2628         GstStructure* str = NULL;
2629         const gchar* name = NULL;
2630         GstPad* sinkpad = NULL;
2631         GstPad* srcpad = NULL;
2632         gboolean first_track = FALSE;
2633
2634         enum MainElementID elemId = MMPLAYER_M_NUM;
2635         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2636
2637         /* check handles */
2638         player = (mm_player_t*)data;
2639
2640         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2641         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2642
2643         //LOGD("pad-added signal handling\n");
2644
2645         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2646
2647         /* get mimetype from caps */
2648         caps = gst_pad_query_caps(pad, NULL);
2649         if (!caps) {
2650                 LOGE("cannot get caps from pad.\n");
2651                 goto ERROR;
2652         }
2653
2654         str = gst_caps_get_structure(caps, 0);
2655         if (!str) {
2656                 LOGE("cannot get structure from caps.\n");
2657                 goto ERROR;
2658         }
2659
2660         name = gst_structure_get_name(str);
2661         if (!name) {
2662                 LOGE("cannot get mimetype from structure.\n");
2663                 goto ERROR;
2664         }
2665
2666         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2667         //LOGD("detected mimetype : %s\n", name);
2668
2669         if (strstr(name, "video")) {
2670                 gint stype = 0;
2671
2672                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2673                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2674
2675                 /* don't make video because of not required, and not support multiple track */
2676                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2677                         LOGD("no video sink by null surface");
2678
2679                         gchar *caps_str = gst_caps_to_string(caps);
2680                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2681                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2682                                 player->set_mode.video_zc = TRUE;
2683
2684                         MMPLAYER_FREEIF(caps_str);
2685
2686                         if (player->v_stream_caps) {
2687                                 gst_caps_unref(player->v_stream_caps);
2688                                 player->v_stream_caps = NULL;
2689                         }
2690
2691                         LOGD("create fakesink instead of videobin");
2692
2693                         /* fake sink */
2694                         fakesink = gst_element_factory_make("fakesink", NULL);
2695                         if (fakesink == NULL) {
2696                                 LOGE("ERROR : fakesink create error\n");
2697                                 goto ERROR;
2698                         }
2699
2700                         if (player->ini.set_dump_element_flag)
2701                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2702
2703                         player->video_fakesink = fakesink;
2704
2705                         /* store it as it's sink element */
2706                         __mmplayer_add_sink(player, player->video_fakesink);
2707
2708                         gst_bin_add(GST_BIN(pipeline), fakesink);
2709
2710                         // link
2711                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2712
2713                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2714                                 LOGW("failed to link fakesink\n");
2715                                 gst_object_unref(GST_OBJECT(fakesink));
2716                                 goto ERROR;
2717                         }
2718
2719                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2720                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2721                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2722                         }
2723
2724                         if (player->set_mode.media_packet_video_stream) {
2725                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2726
2727                                 MMPLAYER_SIGNAL_CONNECT(player,
2728                                                                                 G_OBJECT(fakesink),
2729                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2730                                                                                 "handoff",
2731                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2732                                                                                 (gpointer)player);
2733
2734                                 MMPLAYER_SIGNAL_CONNECT(player,
2735                                                                                 G_OBJECT(fakesink),
2736                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2737                                                                                 "preroll-handoff",
2738                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2739                                                                                 (gpointer)player);
2740                         }
2741
2742                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2743                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2744                         goto DONE;
2745                 }
2746
2747                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2748                         __mmplayer_gst_decode_callback(elem, pad, player);
2749                         goto DONE;
2750                 }
2751
2752                 LOGD("video selector \n");
2753                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2754                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2755         } else {
2756                 if (strstr(name, "audio")) {
2757                         gint samplerate = 0;
2758                         gint channels = 0;
2759
2760                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2761                                 __mmplayer_gst_decode_callback(elem, pad, player);
2762                                 goto DONE;
2763                         }
2764
2765                         LOGD("audio selector \n");
2766                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2767                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2768
2769                         gst_structure_get_int(str, "rate", &samplerate);
2770                         gst_structure_get_int(str, "channels", &channels);
2771
2772                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2773                                 /* fake sink */
2774                                 fakesink = gst_element_factory_make("fakesink", NULL);
2775                                 if (fakesink == NULL) {
2776                                         LOGE("ERROR : fakesink create error\n");
2777                                         goto ERROR;
2778                                 }
2779
2780                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2781
2782                                 /* link */
2783                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2784
2785                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2786                                         LOGW("failed to link fakesink\n");
2787                                         gst_object_unref(GST_OBJECT(fakesink));
2788                                         goto ERROR;
2789                                 }
2790
2791                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2792                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2793                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2794
2795                                 goto DONE;
2796                         }
2797                 } else if (strstr(name, "text")) {
2798                         LOGD("text selector \n");
2799                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2800                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2801                 } else {
2802                         LOGE("wrong elem id \n");
2803                         goto ERROR;
2804                 }
2805         }
2806
2807         selector = player->pipeline->mainbin[elemId].gst;
2808         if (selector == NULL) {
2809                 selector = gst_element_factory_make("input-selector", NULL);
2810                 LOGD("Creating input-selector\n");
2811                 if (selector == NULL) {
2812                         LOGE("ERROR : input-selector create error\n");
2813                         goto ERROR;
2814                 }
2815                 g_object_set(selector, "sync-streams", TRUE, NULL);
2816
2817                 player->pipeline->mainbin[elemId].id = elemId;
2818                 player->pipeline->mainbin[elemId].gst = selector;
2819
2820                 first_track = TRUE;
2821                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2822
2823                 srcpad = gst_element_get_static_pad(selector, "src");
2824
2825                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2826                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2827                         __mmplayer_gst_selector_blocked, NULL, NULL);
2828                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2829                         __mmplayer_gst_selector_event_probe, player, NULL);
2830
2831                 gst_element_set_state(selector, GST_STATE_PAUSED);
2832                 gst_bin_add(GST_BIN(pipeline), selector);
2833         } else
2834                 LOGD("input-selector is already created.\n");
2835
2836         // link
2837         LOGD("Calling request pad with selector %p \n", selector);
2838         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2839
2840         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2841
2842         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2843                 LOGW("failed to link selector\n");
2844                 gst_object_unref(GST_OBJECT(selector));
2845                 goto ERROR;
2846         }
2847
2848         if (first_track) {
2849                 LOGD("this is first track --> active track \n");
2850                 g_object_set(selector, "active-pad", sinkpad, NULL);
2851         }
2852
2853         _mmplayer_track_update_info(player, stream_type, sinkpad);
2854
2855
2856 DONE:
2857 ERROR:
2858
2859         if (caps)
2860                 gst_caps_unref(caps);
2861
2862         if (sinkpad) {
2863                 gst_object_unref(GST_OBJECT(sinkpad));
2864                 sinkpad = NULL;
2865         }
2866
2867         if (srcpad) {
2868                 gst_object_unref(GST_OBJECT(srcpad));
2869                 srcpad = NULL;
2870         }
2871
2872         return;
2873 }
2874
2875 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2876 {
2877         GstPad* srcpad = NULL;
2878         MMHandleType attrs = 0;
2879         gint active_index = 0;
2880
2881         // [link] input-selector :: textbin
2882         srcpad = gst_element_get_static_pad(text_selector, "src");
2883         if (!srcpad) {
2884                 LOGE("failed to get srcpad from selector\n");
2885                 return;
2886         }
2887
2888         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2889
2890         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2891         if ((active_index != DEFAULT_TRACK) &&
2892                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2893                 LOGW("failed to change text track\n");
2894                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2895         }
2896
2897         player->no_more_pad = TRUE;
2898         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2899
2900         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2901         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2902                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2903                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2904         }
2905
2906         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2907
2908         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2909                 player->has_closed_caption = TRUE;
2910
2911         attrs = MMPLAYER_GET_ATTRS(player);
2912         if (attrs) {
2913                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2914                 if (mmf_attrs_commit(attrs))
2915                         LOGE("failed to commit.\n");
2916         } else
2917                 LOGE("cannot get content attribute");
2918
2919         if (srcpad) {
2920                 gst_object_unref(GST_OBJECT(srcpad));
2921                 srcpad = NULL;
2922         }
2923 }
2924
2925 static void
2926 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2927 {
2928         mm_player_t* player = (mm_player_t*)data;
2929         GstElement* selector = NULL;
2930         GstElement* queue = NULL;
2931
2932         GstPad* srcpad = NULL;
2933         GstPad* sinkpad = NULL;
2934         GstCaps* caps = NULL;
2935         gchar* caps_str = NULL;
2936
2937         MMPLAYER_FENTER();
2938         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2939
2940         caps = gst_pad_get_current_caps(pad);
2941         caps_str = gst_caps_to_string(caps);
2942         LOGD("deinterleave new caps : %s\n", caps_str);
2943         MMPLAYER_FREEIF(caps_str);
2944         gst_caps_unref(caps);
2945
2946         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2947                 LOGE("ERROR : queue create error\n");
2948                 goto ERROR;
2949         }
2950
2951         g_object_set(G_OBJECT(queue),
2952                                 "max-size-buffers", 10,
2953                                 "max-size-bytes", 0,
2954                                 "max-size-time", (guint64)0,
2955                                 NULL);
2956
2957         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2958
2959         if (!selector) {
2960                 LOGE("there is no audio channel selector.\n");
2961                 goto ERROR;
2962         }
2963
2964         srcpad = gst_element_get_static_pad(queue, "src");
2965         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2966
2967         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2968
2969         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2970                 LOGW("failed to link deinterleave - selector\n");
2971                 goto ERROR;
2972         }
2973
2974         gst_element_set_state(queue, GST_STATE_PAUSED);
2975         player->audio_mode.total_track_num++;
2976
2977 ERROR:
2978
2979         if (srcpad) {
2980                 gst_object_unref(GST_OBJECT(srcpad));
2981                 srcpad = NULL;
2982         }
2983
2984         if (sinkpad) {
2985                 gst_object_unref(GST_OBJECT(sinkpad));
2986                 sinkpad = NULL;
2987         }
2988
2989         MMPLAYER_FLEAVE();
2990         return;
2991 }
2992
2993 static void
2994 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2995 {
2996         mm_player_t* player = NULL;
2997         GstElement* selector = NULL;
2998         GstPad* sinkpad = NULL;
2999         gint active_index = 0;
3000         gchar* change_pad_name = NULL;
3001         GstCaps* caps = NULL;   // no need to unref
3002         gint default_audio_ch = 0;
3003
3004         MMPLAYER_FENTER();
3005         player = (mm_player_t*) data;
3006
3007         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3008
3009         if (!selector) {
3010                 LOGE("there is no audio channel selector.\n");
3011                 goto ERROR;
3012         }
3013
3014         active_index = player->audio_mode.active_pad_index;
3015
3016         if (active_index != default_audio_ch) {
3017                 gint audio_ch = default_audio_ch;
3018
3019                 /*To get the new pad from the selector*/
3020                 change_pad_name = g_strdup_printf("sink%d", active_index);
3021                 if (change_pad_name != NULL) {
3022                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3023                         if (sinkpad != NULL) {
3024                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3025                                 g_object_set(selector, "active-pad", sinkpad, NULL);
3026
3027                                 audio_ch = active_index;
3028
3029                                 caps = gst_pad_get_current_caps(sinkpad);
3030                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3031
3032                                 __mmplayer_set_audio_attrs(player, caps);
3033                                 gst_caps_unref(caps);
3034                         }
3035                         MMPLAYER_FREEIF(change_pad_name);
3036                 }
3037
3038                 player->audio_mode.active_pad_index = audio_ch;
3039                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3040         }
3041
3042 ERROR:
3043
3044         if (sinkpad)
3045                 gst_object_unref(sinkpad);
3046
3047         MMPLAYER_FLEAVE();
3048         return;
3049 }
3050
3051 static void
3052 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3053 {
3054         mm_player_t* player = NULL;
3055         MMPlayerGstElement *mainbin = NULL;
3056
3057         GstElement* tee = NULL;
3058         GstElement* stereo_queue = NULL;
3059         GstElement* mono_queue = NULL;
3060         GstElement* conv = NULL;
3061         GstElement* filter = NULL;
3062         GstElement* deinterleave = NULL;
3063         GstElement* selector = NULL;
3064
3065         GstPad* srcpad = NULL;
3066         GstPad* selector_srcpad = NULL;
3067         GstPad* sinkpad = NULL;
3068         GstCaps* caps = NULL;
3069         gulong block_id = 0;
3070
3071         MMPLAYER_FENTER();
3072
3073         /* check handles */
3074         player = (mm_player_t*) data;
3075
3076         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3077         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3078
3079         mainbin = player->pipeline->mainbin;
3080
3081         /* tee */
3082         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3083                 LOGE("ERROR : tee create error\n");
3084                 goto ERROR;
3085         }
3086
3087         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3088         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3089
3090         gst_element_set_state(tee, GST_STATE_PAUSED);
3091
3092         /* queue */
3093         srcpad = gst_element_get_request_pad(tee, "src_%u");
3094         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3095                 LOGE("ERROR : stereo queue create error\n");
3096                 goto ERROR;
3097         }
3098
3099         g_object_set(G_OBJECT(stereo_queue),
3100                                 "max-size-buffers", 10,
3101                                 "max-size-bytes", 0,
3102                                 "max-size-time", (guint64)0,
3103                                 NULL);
3104
3105         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3106         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3107
3108         if (srcpad) {
3109                 gst_object_unref(GST_OBJECT(srcpad));
3110                 srcpad = NULL;
3111         }
3112
3113         srcpad = gst_element_get_request_pad(tee, "src_%u");
3114
3115         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3116                 LOGE("ERROR : mono queue create error\n");
3117                 goto ERROR;
3118         }
3119
3120         g_object_set(G_OBJECT(mono_queue),
3121                                 "max-size-buffers", 10,
3122                                 "max-size-bytes", 0,
3123                                 "max-size-time", (guint64)0,
3124                                 NULL);
3125
3126         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3127         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3128
3129         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3130         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3131
3132         /* audioconvert */
3133         srcpad = gst_element_get_static_pad(mono_queue, "src");
3134         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3135                 LOGE("ERROR : audioconvert create error\n");
3136                 goto ERROR;
3137         }
3138
3139         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3140         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3141
3142         /* caps filter */
3143         if (srcpad) {
3144                 gst_object_unref(GST_OBJECT(srcpad));
3145                 srcpad = NULL;
3146         }
3147         srcpad = gst_element_get_static_pad(conv, "src");
3148
3149         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3150                 LOGE("ERROR : capsfilter create error\n");
3151                 goto ERROR;
3152         }
3153
3154         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3155         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3156
3157         caps = gst_caps_from_string("audio/x-raw-int, "
3158                                 "width = (int) 16, "
3159                                 "depth = (int) 16, "
3160                                 "channels = (int) 2");
3161
3162         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3163         gst_caps_unref(caps);
3164
3165         gst_element_set_state(conv, GST_STATE_PAUSED);
3166         gst_element_set_state(filter, GST_STATE_PAUSED);
3167
3168         /* deinterleave */
3169         if (srcpad) {
3170                 gst_object_unref(GST_OBJECT(srcpad));
3171                 srcpad = NULL;
3172         }
3173         srcpad = gst_element_get_static_pad(filter, "src");
3174
3175         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3176                 LOGE("ERROR : deinterleave create error\n");
3177                 goto ERROR;
3178         }
3179
3180         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3181
3182         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3183                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3184
3185         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3186                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3187
3188         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3189         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3190
3191         /* selector */
3192         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3193         if (selector == NULL) {
3194                 LOGE("ERROR : audio-selector create error\n");
3195                 goto ERROR;
3196         }
3197
3198         g_object_set(selector, "sync-streams", TRUE, NULL);
3199         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3200
3201         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3202         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3203
3204         selector_srcpad = gst_element_get_static_pad(selector, "src");
3205
3206         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3207         block_id =
3208                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3209                         __mmplayer_gst_selector_blocked, NULL, NULL);
3210
3211         if (srcpad) {
3212                 gst_object_unref(GST_OBJECT(srcpad));
3213                 srcpad = NULL;
3214         }
3215
3216         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3217         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3218
3219         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3220                 LOGW("failed to link queue_stereo - selector\n");
3221                 goto ERROR;
3222         }
3223
3224         player->audio_mode.total_track_num++;
3225
3226         g_object_set(selector, "active-pad", sinkpad, NULL);
3227         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3228         gst_element_set_state(selector, GST_STATE_PAUSED);
3229
3230         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3231
3232 ERROR:
3233
3234         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3235         if (block_id != 0) {
3236                 gst_pad_remove_probe(selector_srcpad, block_id);
3237                 block_id = 0;
3238         }
3239
3240         if (sinkpad) {
3241                 gst_object_unref(GST_OBJECT(sinkpad));
3242                 sinkpad = NULL;
3243         }
3244
3245         if (srcpad) {
3246                 gst_object_unref(GST_OBJECT(srcpad));
3247                 srcpad = NULL;
3248         }
3249
3250         if (selector_srcpad) {
3251                 gst_object_unref(GST_OBJECT(selector_srcpad));
3252                 selector_srcpad = NULL;
3253         }
3254
3255         MMPLAYER_FLEAVE();
3256         return;
3257 }
3258
3259 static void
3260 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3261 {
3262         mm_player_t* player = NULL;
3263         GstPad* srcpad = NULL;
3264         GstElement* video_selector = NULL;
3265         GstElement* audio_selector = NULL;
3266         GstElement* text_selector = NULL;
3267         MMHandleType attrs = 0;
3268         gint active_index = 0;
3269         gint64 dur_bytes = 0L;
3270
3271         player = (mm_player_t*) data;
3272
3273         LOGD("no-more-pad signal handling\n");
3274
3275         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3276                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3277                 LOGW("no need to go more");
3278
3279                 if (player->gapless.reconfigure) {
3280                         player->gapless.reconfigure = FALSE;
3281                         MMPLAYER_PLAYBACK_UNLOCK(player);
3282                 }
3283
3284                 return;
3285         }
3286
3287         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3288                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3289                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3290                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3291                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3292
3293                 if (NULL == player->streamer) {
3294                         LOGW("invalid state for buffering");
3295                         goto ERROR;
3296                 }
3297
3298                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3299                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3300
3301                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3302                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3303
3304                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3305
3306                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3307                         LOGE("fail to get duration.\n");
3308
3309                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3310                 // use file information was already set on Q2 when it was created.
3311                 __mm_player_streaming_set_queue2(player->streamer,
3312                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3313                                                 TRUE,                                                           // use_buffering
3314                                                 buffer_bytes,
3315                                                 init_buffering_time,
3316                                                 1.0,                                                            // low percent
3317                                                 player->ini.http_buffering_limit,       // high percent
3318                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3319                                                 NULL,
3320                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3321         }
3322
3323         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3324         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3325         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3326         if (video_selector) {
3327                 // [link] input-selector :: videobin
3328                 srcpad = gst_element_get_static_pad(video_selector, "src");
3329                 if (!srcpad) {
3330                         LOGE("failed to get srcpad from video selector\n");
3331                         goto ERROR;
3332                 }
3333
3334                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3335                 if (!text_selector && !audio_selector)
3336                         player->no_more_pad = TRUE;
3337
3338                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3339
3340                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3341                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3342                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3343                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3344                 }
3345         }
3346
3347         if (audio_selector) {
3348                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3349                 if ((active_index != DEFAULT_TRACK) &&
3350                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3351                         LOGW("failed to change audio track\n");
3352                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3353                 }
3354
3355                 // [link] input-selector :: audiobin
3356                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3357                 if (!srcpad) {
3358                         LOGE("failed to get srcpad from selector\n");
3359                         goto ERROR;
3360                 }
3361
3362                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3363                 if (!text_selector)
3364                         player->no_more_pad = TRUE;
3365
3366                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3367                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3368                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3369                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3370                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3371                         }
3372
3373                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3374                 } else {
3375                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3376
3377                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3378                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3379                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3380                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3381                         }
3382                 }
3383
3384                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3385
3386                 attrs = MMPLAYER_GET_ATTRS(player);
3387                 if (attrs) {
3388                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3389                         if (mmf_attrs_commit(attrs))
3390                                 LOGE("failed to commit.\n");
3391                 } else
3392                         LOGE("cannot get content attribute");
3393         } else {
3394                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3395                         LOGD("There is no audio track : remove audiobin");
3396
3397                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3398                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3399
3400                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3401                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3402                 }
3403
3404                 if (player->num_dynamic_pad == 0)
3405                         __mmplayer_pipeline_complete(NULL, player);
3406         }
3407
3408         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3409                 if (text_selector)
3410                         __mmplayer_handle_text_decode_path(player, text_selector);
3411         }
3412
3413         MMPLAYER_FLEAVE();
3414
3415 ERROR:
3416         if (srcpad) {
3417                 gst_object_unref(GST_OBJECT(srcpad));
3418                 srcpad = NULL;
3419         }
3420
3421         if (player->gapless.reconfigure) {
3422                 player->gapless.reconfigure = FALSE;
3423                 MMPLAYER_PLAYBACK_UNLOCK(player);
3424         }
3425 }
3426
3427 static void
3428 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3429 {
3430         mm_player_t* player = NULL;
3431         MMHandleType attrs = 0;
3432         GstElement* pipeline = NULL;
3433         GstCaps* caps = NULL;
3434         gchar* caps_str = NULL;
3435         GstStructure* str = NULL;
3436         const gchar* name = NULL;
3437         GstPad* sinkpad = NULL;
3438         GstElement* sinkbin = NULL;
3439         gboolean reusing = FALSE;
3440         GstElement *text_selector = NULL;
3441
3442         /* check handles */
3443         player = (mm_player_t*) data;
3444
3445         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3446         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3447
3448         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3449
3450         attrs = MMPLAYER_GET_ATTRS(player);
3451         if (!attrs) {
3452                 LOGE("cannot get content attribute\n");
3453                 goto ERROR;
3454         }
3455
3456         /* get mimetype from caps */
3457         caps = gst_pad_query_caps(pad, NULL);
3458         if (!caps) {
3459                 LOGE("cannot get caps from pad.\n");
3460                 goto ERROR;
3461         }
3462         caps_str = gst_caps_to_string(caps);
3463
3464         str = gst_caps_get_structure(caps, 0);
3465         if (!str) {
3466                 LOGE("cannot get structure from caps.\n");
3467                 goto ERROR;
3468         }
3469
3470         name = gst_structure_get_name(str);
3471         if (!name) {
3472                 LOGE("cannot get mimetype from structure.\n");
3473                 goto ERROR;
3474         }
3475
3476         //LOGD("detected mimetype : %s\n", name);
3477
3478         if (strstr(name, "audio")) {
3479                 if (player->pipeline->audiobin == NULL) {
3480                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3481                                 LOGE("failed to create audiobin. continuing without audio\n");
3482                                 goto ERROR;
3483                         }
3484
3485                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3486                         LOGD("creating audiosink bin success\n");
3487                 } else {
3488                         reusing = TRUE;
3489                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3490                         LOGD("reusing audiobin\n");
3491                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3492                 }
3493
3494                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3495                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3496
3497                 player->audiosink_linked  = 1;
3498
3499                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3500                 if (!sinkpad) {
3501                         LOGE("failed to get pad from sinkbin\n");
3502                         goto ERROR;
3503                 }
3504         } else if (strstr(name, "video")) {
3505                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3506                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3507                         player->set_mode.video_zc = TRUE;
3508
3509                 if (player->pipeline->videobin == NULL) {
3510                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3511                         /* get video surface type */
3512                         int surface_type = 0;
3513                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3514                         LOGD("display_surface_type(%d)\n", surface_type);
3515
3516                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3517                                 LOGD("not make videobin because it dose not want\n");
3518                                 goto ERROR;
3519                         }
3520
3521                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3522                                 /* mark video overlay for acquire */
3523                                 if (player->video_overlay_resource == NULL) {
3524                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3525                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3526                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3527                                                         &player->video_overlay_resource)
3528                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3529                                                 LOGE("could not mark video_overlay resource for acquire\n");
3530                                                 goto ERROR;
3531                                         }
3532                                 }
3533                         }
3534
3535                         player->interrupted_by_resource = FALSE;
3536                         /* acquire resources for video overlay */
3537                         if (mm_resource_manager_commit(player->resource_manager) !=
3538                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3539                                 LOGE("could not acquire resources for video playing\n");
3540                                 goto ERROR;
3541                         }
3542
3543                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3544                                 LOGE("failed to create videobin. continuing without video\n");
3545                                 goto ERROR;
3546                         }
3547
3548                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3549                         LOGD("creating videosink bin success\n");
3550                 } else {
3551                         reusing = TRUE;
3552                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3553                         LOGD("re-using videobin\n");
3554                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3555                 }
3556
3557                 /* FIXIT : track number shouldn't be hardcoded */
3558                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3559                 player->videosink_linked  = 1;
3560
3561                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3562                 if (!sinkpad) {
3563                         LOGE("failed to get pad from sinkbin\n");
3564                         goto ERROR;
3565                 }
3566         } else if (strstr(name, "text")) {
3567                 if (player->pipeline->textbin == NULL) {
3568                         MMPlayerGstElement* mainbin = NULL;
3569
3570                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3571                                 LOGE("failed to create text sink bin. continuing without text\n");
3572                                 goto ERROR;
3573                         }
3574
3575                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3576                         LOGD("creating textsink bin success\n");
3577
3578                         /* FIXIT : track number shouldn't be hardcoded */
3579                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3580
3581                         player->textsink_linked  = 1;
3582                         LOGI("player->textsink_linked set to 1\n");
3583
3584                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3585                         if (!sinkpad) {
3586                                 LOGE("failed to get pad from sinkbin\n");
3587                                 goto ERROR;
3588                         }
3589
3590                         mainbin = player->pipeline->mainbin;
3591
3592                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3593                                 /* input selector */
3594                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3595                                 if (!text_selector) {
3596                                         LOGE("failed to create subtitle input selector element\n");
3597                                         goto ERROR;
3598                                 }
3599                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3600
3601                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3602                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3603
3604                                 /* warm up */
3605                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3606                                         LOGE("failed to set state(READY) to sinkbin\n");
3607                                         goto ERROR;
3608                                 }
3609
3610                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3611                                         LOGW("failed to add subtitle input selector\n");
3612                                         goto ERROR;
3613                                 }
3614
3615                                 LOGD("created element input-selector");
3616
3617                         } else {
3618                                 LOGD("already having subtitle input selector");
3619                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3620                         }
3621                 } else {
3622                         if (!player->textsink_linked) {
3623                                 LOGD("re-using textbin\n");
3624
3625                                 reusing = TRUE;
3626                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3627
3628                                 player->textsink_linked  = 1;
3629                                 LOGI("player->textsink_linked set to 1\n");
3630                         } else
3631                                 LOGD("ignoring internal subtutle since external subtitle is available");
3632                 }
3633         } else {
3634                 LOGW("unknown type of elementary stream!ignoring it...\n");
3635                 goto ERROR;
3636         }
3637
3638         if (sinkbin) {
3639                 if (!reusing) {
3640                         /* warm up */
3641                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3642                                 LOGE("failed to set state(READY) to sinkbin\n");
3643                                 goto ERROR;
3644                         }
3645
3646                         /* Added for multi audio support to avoid adding audio bin again*/
3647                         /* add */
3648                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3649                                 LOGE("failed to add sinkbin to pipeline\n");
3650                                 goto ERROR;
3651                         }
3652                 }
3653
3654                 /* link */
3655                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3656                         LOGE("failed to get pad from sinkbin\n");
3657                         goto ERROR;
3658                 }
3659
3660                 if (!reusing) {
3661                         /* run */
3662                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3663                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3664                                 goto ERROR;
3665                         }
3666
3667                         if (text_selector) {
3668                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3669                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3670                                         goto ERROR;
3671                                 }
3672                         }
3673                 }
3674
3675                 gst_object_unref(sinkpad);
3676                 sinkpad = NULL;
3677         }
3678
3679         LOGD("[handle: %p] linking sink bin success", player);
3680
3681         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3682          * streaming task. if the task blocked, then buffer will not flow to the next element
3683          *(autoplugging element). so this is special hack for streaming. please try to remove it
3684          */
3685         /* dec stream count. we can remove fakesink if it's zero */
3686         if (player->num_dynamic_pad)
3687                 player->num_dynamic_pad--;
3688
3689         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3690
3691         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3692                 __mmplayer_pipeline_complete(NULL, player);
3693
3694 ERROR:
3695
3696         MMPLAYER_FREEIF(caps_str);
3697
3698         if (caps)
3699                 gst_caps_unref(caps);
3700
3701         if (sinkpad)
3702                 gst_object_unref(GST_OBJECT(sinkpad));
3703
3704         /* flusing out new attributes */
3705         if (mmf_attrs_commit(attrs))
3706                 LOGE("failed to comit attributes\n");
3707
3708         return;
3709 }
3710
3711 static gboolean
3712 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3713 {
3714         int pro_value = 0; // in the case of expection, default will be returned.
3715         int dest_angle = rotation_angle;
3716         int rotation_type = -1;
3717
3718         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3719         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3720         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3721
3722         if (rotation_angle >= 360)
3723                 dest_angle = rotation_angle - 360;
3724
3725         /* chech if supported or not */
3726         if (dest_angle % 90) {
3727                 LOGD("not supported rotation angle = %d", rotation_angle);
3728                 return FALSE;
3729         }
3730
3731         /*
3732           * tizenwlsink (A)
3733           * custom_convert - none (B)
3734           * videoflip - none (C)
3735           */
3736         if (player->set_mode.video_zc) {
3737                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3738                         rotation_type = ROTATION_USING_CUSTOM;
3739                 else // A
3740                         rotation_type = ROTATION_USING_SINK;
3741         } else {
3742                 int surface_type = 0;
3743                 rotation_type = ROTATION_USING_FLIP;
3744
3745                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3746                 LOGD("check display surface type attribute: %d", surface_type);
3747
3748                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3749                         rotation_type = ROTATION_USING_SINK;
3750                 else
3751                         rotation_type = ROTATION_USING_FLIP; //C
3752
3753                 LOGD("using %d type for rotation", rotation_type);
3754         }
3755
3756         /* get property value for setting */
3757         switch (rotation_type) {
3758         case ROTATION_USING_SINK: // tizenwlsink
3759                 {
3760                         switch (dest_angle) {
3761                         case 0:
3762                                 break;
3763                         case 90:
3764                                 pro_value = 3; // clockwise 90
3765                                 break;
3766                         case 180:
3767                                 pro_value = 2;
3768                                 break;
3769                         case 270:
3770                                 pro_value = 1; // counter-clockwise 90
3771                                 break;
3772                         }
3773                 }
3774                 break;
3775         case ROTATION_USING_CUSTOM:
3776                 {
3777                         gchar *ename = NULL;
3778                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3779
3780                         if (g_strrstr(ename, "fimcconvert")) {
3781                                 switch (dest_angle) {
3782                                 case 0:
3783                                         break;
3784                                 case 90:
3785                                         pro_value = 90; // clockwise 90
3786                                         break;
3787                                 case 180:
3788                                         pro_value = 180;
3789                                         break;
3790                                 case 270:
3791                                         pro_value = 270; // counter-clockwise 90
3792                                         break;
3793                                 }
3794                         }
3795                 }
3796                 break;
3797         case ROTATION_USING_FLIP: // videoflip
3798                 {
3799                                 switch (dest_angle) {
3800                                 case 0:
3801                                         break;
3802                                 case 90:
3803                                         pro_value = 1; // clockwise 90
3804                                         break;
3805                                 case 180:
3806                                         pro_value = 2;
3807                                         break;
3808                                 case 270:
3809                                         pro_value = 3; // counter-clockwise 90
3810                                         break;
3811                                 }
3812                 }
3813                 break;
3814         }
3815
3816         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3817
3818         *value = pro_value;
3819
3820         return TRUE;
3821 }
3822
3823 int
3824 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3825 {
3826         /* check video sinkbin is created */
3827         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3828                 player->pipeline &&
3829                 player->pipeline->videobin &&
3830                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3831                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3832                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3833
3834         return MM_ERROR_NONE;
3835 }
3836
3837 void
3838 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3839 {
3840         int rotation_value = 0;
3841         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3842         int user_angle = 0;
3843         MMPLAYER_FENTER();
3844
3845         /* check video sinkbin is created */
3846         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3847                 return;
3848
3849         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3850
3851         /* get rotation value to set */
3852         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3853         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3854         LOGD("set video param : rotate %d", rotation_value);
3855 }
3856
3857 void
3858 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3859 {
3860         MMHandleType attrs = 0;
3861         int visible = 0;
3862         MMPLAYER_FENTER();
3863
3864         /* check video sinkbin is created */
3865         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3866                 return;
3867
3868         attrs = MMPLAYER_GET_ATTRS(player);
3869         MMPLAYER_RETURN_IF_FAIL(attrs);
3870
3871         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3872         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3873         LOGD("set video param : visible %d", visible);
3874 }
3875
3876 void
3877 __mmplayer_video_param_set_display_method(mm_player_t* player)
3878 {
3879         MMHandleType attrs = 0;
3880         int display_method = 0;
3881         MMPLAYER_FENTER();
3882
3883         /* check video sinkbin is created */
3884         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3885                 return;
3886
3887         attrs = MMPLAYER_GET_ATTRS(player);
3888         MMPLAYER_RETURN_IF_FAIL(attrs);
3889
3890         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3891         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3892         LOGD("set video param : method %d", display_method);
3893 }
3894
3895 int
3896 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3897 {
3898         MMHandleType attrs = 0;
3899         void *handle = NULL;
3900         /*set wl_display*/
3901         int wl_window_x = 0;
3902         int wl_window_y = 0;
3903         int wl_window_width = 0;
3904         int wl_window_height = 0;
3905         MMPLAYER_FENTER();
3906
3907         /* check video sinkbin is created */
3908         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3909                 return MM_ERROR_PLAYER_INTERNAL;
3910
3911         attrs = MMPLAYER_GET_ATTRS(player);
3912         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3913
3914         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3915
3916         if (handle) {
3917                 /*It should be set after setting window*/
3918                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3919                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3920                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3921                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3922
3923                 /* After setting window handle, set render      rectangle */
3924                 gst_video_overlay_set_render_rectangle(
3925                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3926                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3927                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3928                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3929         } else {
3930                 return MM_ERROR_PLAYER_INTERNAL;
3931         }
3932         return MM_ERROR_NONE;
3933 }
3934 void
3935 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3936 {
3937         MMHandleType attrs = 0;
3938         void *handle = NULL;
3939
3940         /* check video sinkbin is created */
3941         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3942                 return;
3943
3944         attrs = MMPLAYER_GET_ATTRS(player);
3945         MMPLAYER_RETURN_IF_FAIL(attrs);
3946
3947         /* common case if using overlay surface */
3948         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3949
3950         if (handle) {
3951                 /* default is using wl_surface_id */
3952                 unsigned int wl_surface_id      = 0;
3953                 wl_surface_id = *(int*)handle;
3954                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3955                 gst_video_overlay_set_wl_window_wl_surface_id(
3956                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3957                                 *(int*)handle);
3958         } else
3959                 /* FIXIT : is it error case? */
3960                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3961 }
3962
3963
3964 int
3965 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3966 {
3967         bool update_all_param = FALSE;
3968         MMHandleType attrs = 0;
3969         int display_method = 0;
3970         MMPLAYER_FENTER();
3971
3972         /* check video sinkbin is created */
3973         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3974                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3975
3976         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3977                 LOGE("can not find tizenwlsink");
3978                 return MM_ERROR_PLAYER_INTERNAL;
3979         }
3980
3981         LOGD("param_name : %s", param_name);
3982         if (!g_strcmp0(param_name, "update_all_param"))
3983                 update_all_param = TRUE;
3984
3985         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3986                 __mmplayer_video_param_set_display_overlay(player);
3987         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3988                 __mmplayer_video_param_set_display_method(player);
3989         /* check roi mode is set */
3990         attrs = MMPLAYER_GET_ATTRS(player);
3991         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3992         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3993         if ((display_method == PLAYER_DISPLAY_MODE_DST_ROI) && (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))) {
3994                 if (MM_ERROR_NONE != __mmplayer_video_param_set_render_rectangle(player))
3995                         return MM_ERROR_PLAYER_INTERNAL;
3996         }
3997         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3998                 __mmplayer_video_param_set_display_visible(player);
3999         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4000                 __mmplayer_video_param_set_display_rotation(player);
4001
4002         return MM_ERROR_NONE;
4003 }
4004
4005 int
4006 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
4007 {
4008         MMHandleType attrs = 0;
4009         int surface_type = 0;
4010         int ret = MM_ERROR_NONE;
4011
4012         MMPLAYER_FENTER();
4013
4014         /* check video sinkbin is created */
4015         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4016                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4017
4018         attrs = MMPLAYER_GET_ATTRS(player);
4019         if (!attrs) {
4020                 LOGE("cannot get content attribute");
4021                 return MM_ERROR_PLAYER_INTERNAL;
4022         }
4023         LOGD("param_name : %s", param_name);
4024
4025         /* update display surface */
4026         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4027         LOGD("check display surface type attribute: %d", surface_type);
4028
4029         /* configuring display */
4030         switch (surface_type) {
4031         case MM_DISPLAY_SURFACE_OVERLAY:
4032                 {
4033                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4034                         if (ret != MM_ERROR_NONE)
4035                                 return ret;
4036                 }
4037                 break;
4038         }
4039
4040         MMPLAYER_FLEAVE();
4041
4042         return MM_ERROR_NONE;
4043 }
4044
4045 int
4046 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
4047 {
4048         gboolean disable_overlay = FALSE;
4049         mm_player_t* player = (mm_player_t*) hplayer;
4050         int ret = MM_ERROR_NONE;
4051
4052         MMPLAYER_FENTER();
4053         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4054         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4055                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4056                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4057
4058         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4059                 LOGW("Display control is not supported");
4060                 return MM_ERROR_PLAYER_INTERNAL;
4061         }
4062
4063         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4064
4065         if (audio_only == (bool)disable_overlay) {
4066                 LOGE("It's the same with current setting: (%d)", audio_only);
4067                 return MM_ERROR_NONE;
4068         }
4069
4070         if (audio_only) {
4071                 LOGE("disable overlay");
4072                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
4073
4074                 /* release overlay resource */
4075                 if (player->video_overlay_resource != NULL) {
4076                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
4077                                         player->video_overlay_resource);
4078                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4079                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4080                                 goto ERROR;
4081                         }
4082                         player->video_overlay_resource = NULL;
4083                 }
4084
4085                 ret = mm_resource_manager_commit(player->resource_manager);
4086                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4087                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
4088                         goto ERROR;
4089                 }
4090         } else {
4091                 /* mark video overlay for acquire */
4092                 if (player->video_overlay_resource == NULL) {
4093                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
4094                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
4095                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
4096                                         &player->video_overlay_resource);
4097                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4098                                 LOGE("could not prepare for video_overlay resource\n");
4099                                 goto ERROR;
4100                         }
4101                 }
4102
4103                 player->interrupted_by_resource = FALSE;
4104                 /* acquire resources for video overlay */
4105                 ret = mm_resource_manager_commit(player->resource_manager);
4106                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4107                         LOGE("could not acquire resources for video playing\n");
4108                         goto ERROR;
4109                 }
4110
4111                 LOGD("enable overlay");
4112                 __mmplayer_video_param_set_display_overlay(player);
4113                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4114         }
4115
4116 ERROR:
4117         MMPLAYER_FLEAVE();
4118         return MM_ERROR_NONE;
4119 }
4120
4121 int
4122 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4123 {
4124         mm_player_t* player = (mm_player_t*) hplayer;
4125         gboolean disable_overlay = FALSE;
4126
4127         MMPLAYER_FENTER();
4128
4129         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4130         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4131         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4132                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4133                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4134
4135         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4136                 LOGW("Display control is not supported");
4137                 return MM_ERROR_PLAYER_INTERNAL;
4138         }
4139
4140         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4141
4142         *paudio_only = (bool)(disable_overlay);
4143
4144         LOGD("audio_only : %d", *paudio_only);
4145
4146         MMPLAYER_FLEAVE();
4147
4148         return MM_ERROR_NONE;
4149 }
4150
4151 static int
4152 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4153 {
4154         GList* bucket = element_bucket;
4155         MMPlayerGstElement* element = NULL;
4156         MMPlayerGstElement* prv_element = NULL;
4157         gint successful_link_count = 0;
4158
4159         MMPLAYER_FENTER();
4160
4161         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4162
4163         prv_element = (MMPlayerGstElement*)bucket->data;
4164         bucket = bucket->next;
4165
4166         for (; bucket; bucket = bucket->next) {
4167                 element = (MMPlayerGstElement*)bucket->data;
4168
4169                 if (element && element->gst) {
4170                         /* If next element is audio appsrc then make a separate audio pipeline */
4171                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4172                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4173                                 prv_element = element;
4174                                 continue;
4175                         }
4176
4177                         if (prv_element && prv_element->gst) {
4178                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4179                                         LOGD("linking [%s] to [%s] success\n",
4180                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4181                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4182                                         successful_link_count++;
4183                                 } else {
4184                                         LOGD("linking [%s] to [%s] failed\n",
4185                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4186                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4187                                         return -1;
4188                                 }
4189                         }
4190                 }
4191
4192                 prv_element = element;
4193         }
4194
4195         MMPLAYER_FLEAVE();
4196
4197         return successful_link_count;
4198 }
4199
4200 static int
4201 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4202 {
4203         GList* bucket = element_bucket;
4204         MMPlayerGstElement* element = NULL;
4205         int successful_add_count = 0;
4206
4207         MMPLAYER_FENTER();
4208
4209         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4210         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4211
4212         for (; bucket; bucket = bucket->next) {
4213                 element = (MMPlayerGstElement*)bucket->data;
4214
4215                 if (element && element->gst) {
4216                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4217                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4218                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4219                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4220                                 return 0;
4221                         }
4222                         successful_add_count++;
4223                 }
4224         }
4225
4226         MMPLAYER_FLEAVE();
4227
4228         return successful_add_count;
4229 }
4230
4231 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4232 {
4233         mm_player_t* player = (mm_player_t*) data;
4234         GstCaps *caps = NULL;
4235         GstStructure *str = NULL;
4236         const char *name;
4237
4238         MMPLAYER_FENTER();
4239
4240         MMPLAYER_RETURN_IF_FAIL(pad)
4241         MMPLAYER_RETURN_IF_FAIL(unused)
4242         MMPLAYER_RETURN_IF_FAIL(data)
4243
4244         caps = gst_pad_get_current_caps(pad);
4245         if (!caps)
4246                 return;
4247
4248         str = gst_caps_get_structure(caps, 0);
4249         if (!str)
4250                 goto ERROR;
4251
4252         name = gst_structure_get_name(str);
4253         if (!name)
4254                 goto ERROR;
4255
4256         LOGD("name = %s\n", name);
4257
4258         if (strstr(name, "audio")) {
4259                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4260
4261                 if (player->audio_stream_changed_cb) {
4262                         LOGE("call the audio stream changed cb\n");
4263                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4264                 }
4265         } else if (strstr(name, "video")) {
4266                 if ((name = gst_structure_get_string(str, "format")))
4267                         player->set_mode.video_zc = name[0] == 'S';
4268
4269                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4270
4271                 if (player->video_stream_changed_cb) {
4272                         LOGE("call the video stream changed cb\n");
4273                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4274                 }
4275         } else
4276                 goto ERROR;
4277
4278 ERROR:
4279
4280         gst_caps_unref(caps);
4281
4282         MMPLAYER_FLEAVE();
4283
4284         return;
4285 }
4286
4287
4288
4289 /**
4290  * This function is to create audio pipeline for playing.
4291  *
4292  * @param       player          [in]    handle of player
4293  *
4294  * @return      This function returns zero on success.
4295  * @remark
4296  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4297  */
4298 /* macro for code readability. just for sinkbin-creation functions */
4299 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4300 do {\
4301         x_bin[x_id].id = x_id;\
4302         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4303         if (!x_bin[x_id].gst) {\
4304                 LOGE("failed to create %s \n", x_factory);\
4305                 goto ERROR;\
4306         } else {\
4307                 if (x_player->ini.set_dump_element_flag)\
4308                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4309         } \
4310         if (x_add_bucket)\
4311                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4312 } while (0);
4313
4314 static void
4315 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4316 {
4317         GList *l = NULL;
4318
4319         MMPLAYER_FENTER();
4320         MMPLAYER_RETURN_IF_FAIL(player);
4321
4322         if (player->audio_stream_buff_list) {
4323                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4324                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4325                         if (tmp) {
4326                                 if (send_all) {
4327                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4328                                         __mmplayer_audio_stream_send_data(player, tmp);
4329                                 }
4330                                 if (tmp->pcm_data)
4331                                         g_free(tmp->pcm_data);
4332                                 g_free(tmp);
4333                         }
4334                 }
4335                 g_list_free(player->audio_stream_buff_list);
4336                 player->audio_stream_buff_list = NULL;
4337         }
4338
4339         MMPLAYER_FLEAVE();
4340 }
4341
4342 static void
4343 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4344 {
4345         MMPlayerAudioStreamDataType audio_stream = { 0, };
4346
4347         MMPLAYER_FENTER();
4348         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4349
4350         audio_stream.bitrate = a_buffer->bitrate;
4351         audio_stream.channel = a_buffer->channel;
4352         audio_stream.depth = a_buffer->depth;
4353         audio_stream.is_little_endian = a_buffer->is_little_endian;
4354         audio_stream.channel_mask = a_buffer->channel_mask;
4355         audio_stream.data_size = a_buffer->data_size;
4356         audio_stream.data = a_buffer->pcm_data;
4357
4358         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4359         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4360
4361         MMPLAYER_FLEAVE();
4362 }
4363
4364 static void
4365 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4366 {
4367         mm_player_t* player = (mm_player_t*) data;
4368
4369         gint channel = 0;
4370         gint rate = 0;
4371         gint depth = 0;
4372         gint endianness = 0;
4373         guint64 channel_mask = 0;
4374         void *a_data = NULL;
4375         gint a_size = 0;
4376         mm_player_audio_stream_buff_t *a_buffer = NULL;
4377         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4378         GList *l = NULL;
4379
4380         MMPLAYER_FENTER();
4381         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4382
4383         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4384         a_data = mapinfo.data;
4385         a_size = mapinfo.size;
4386
4387         GstCaps *caps = gst_pad_get_current_caps(pad);
4388         GstStructure *structure = gst_caps_get_structure(caps, 0);
4389
4390         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4391         gst_structure_get_int(structure, "rate", &rate);
4392         gst_structure_get_int(structure, "channels", &channel);
4393         gst_structure_get_int(structure, "depth", &depth);
4394         gst_structure_get_int(structure, "endianness", &endianness);
4395         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4396         gst_caps_unref(GST_CAPS(caps));
4397
4398         /* In case of the sync is false, use buffer list.              *
4399          * The num of buffer list depends on the num of audio channels */
4400         if (player->audio_stream_buff_list) {
4401                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4402                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4403                         if (tmp) {
4404                                 if (channel_mask == tmp->channel_mask) {
4405                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4406                                         if (tmp->data_size + a_size < tmp->buff_size) {
4407                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4408                                                 tmp->data_size += a_size;
4409                                         } else {
4410                                                 /* send data to client */
4411                                                 __mmplayer_audio_stream_send_data(player, tmp);
4412
4413                                                 if (a_size > tmp->buff_size) {
4414                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4415                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4416                                                         if (tmp->pcm_data == NULL) {
4417                                                                 LOGE("failed to realloc data.");
4418                                                                 goto DONE;
4419                                                         }
4420                                                         tmp->buff_size = a_size;
4421                                                 }
4422                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4423                                                 memcpy(tmp->pcm_data, a_data, a_size);
4424                                                 tmp->data_size = a_size;
4425                                         }
4426                                         goto DONE;
4427                                 }
4428                         } else {
4429                                 LOGE("data is empty in list.");
4430                                 goto DONE;
4431                         }
4432                 }
4433         }
4434
4435         /* create new audio stream data */
4436         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4437         if (a_buffer == NULL) {
4438                 LOGE("failed to alloc data.");
4439                 goto DONE;
4440         }
4441         a_buffer->bitrate = rate;
4442         a_buffer->channel = channel;
4443         a_buffer->depth = depth;
4444         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4445         a_buffer->channel_mask = channel_mask;
4446         a_buffer->data_size = a_size;
4447
4448         if (!player->audio_stream_sink_sync) {
4449                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4450                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4451                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4452                 if (a_buffer->pcm_data == NULL) {
4453                         LOGE("failed to alloc data.");
4454                         g_free(a_buffer);
4455                         goto DONE;
4456                 }
4457                 memcpy(a_buffer->pcm_data, a_data, a_size);
4458                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4459                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4460         } else {
4461                 /* If sync is TRUE, send data directly. */
4462                 a_buffer->pcm_data = a_data;
4463                 __mmplayer_audio_stream_send_data(player, a_buffer);
4464                 g_free(a_buffer);
4465         }
4466
4467 DONE:
4468         gst_buffer_unmap(buffer, &mapinfo);
4469         MMPLAYER_FLEAVE();
4470 }
4471
4472 static void
4473 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4474 {
4475         mm_player_t* player = (mm_player_t*)data;
4476         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4477         GstPad* sinkpad = NULL;
4478         GstElement *queue = NULL, *sink = NULL;
4479
4480         MMPLAYER_FENTER();
4481         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4482
4483         queue = gst_element_factory_make("queue", NULL);
4484         if (queue == NULL) {
4485                 LOGD("fail make queue\n");
4486                 goto ERROR;
4487         }
4488
4489         sink = gst_element_factory_make("fakesink", NULL);
4490         if (sink == NULL) {
4491                 LOGD("fail make fakesink\n");
4492                 goto ERROR;
4493         }
4494
4495         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4496
4497         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4498                 LOGW("failed to link queue & sink\n");
4499                 goto ERROR;
4500         }
4501
4502         sinkpad = gst_element_get_static_pad(queue, "sink");
4503
4504         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4505                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4506                 goto ERROR;
4507         }
4508
4509         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4510
4511         gst_object_unref(sinkpad);
4512         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4513         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4514
4515         gst_element_set_state(sink, GST_STATE_PAUSED);
4516         gst_element_set_state(queue, GST_STATE_PAUSED);
4517
4518         MMPLAYER_SIGNAL_CONNECT(player,
4519                 G_OBJECT(sink),
4520                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4521                 "handoff",
4522                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4523                 (gpointer)player);
4524
4525         MMPLAYER_FLEAVE();
4526         return;
4527
4528 ERROR:
4529         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4530         if (queue) {
4531                 gst_object_unref(GST_OBJECT(queue));
4532                 queue = NULL;
4533         }
4534         if (sink) {
4535                 gst_object_unref(GST_OBJECT(sink));
4536                 sink = NULL;
4537         }
4538         if (sinkpad) {
4539                 gst_object_unref(GST_OBJECT(sinkpad));
4540                 sinkpad = NULL;
4541         }
4542
4543         return;
4544 }
4545
4546 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4547 {
4548         #define MAX_PROPS_LEN 128
4549         gint latency_mode = 0;
4550         gchar *stream_type = NULL;
4551         gchar *latency = NULL;
4552         gint stream_id = 0;
4553         gchar stream_props[MAX_PROPS_LEN] = {0,};
4554         GstStructure *props = NULL;
4555
4556         /* set volume table
4557          * It should be set after player creation through attribute.
4558          * But, it can not be changed during playing.
4559          */
4560         MMPLAYER_FENTER();
4561         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4562         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4563
4564         if (!stream_type) {
4565                 LOGE("stream_type is null.\n");
4566         } else {
4567                 if (player->sound_focus.focus_id)
4568                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d, mused.client_pid=%d",
4569                                         stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid);
4570                 else
4571                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, mused.client_pid=%d",
4572                                         stream_type, stream_id, player->sound_focus.pid);
4573                 props = gst_structure_from_string(stream_props, NULL);
4574                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4575                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], client_pid[%d], result[%s].\n",
4576                         stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid, stream_props);
4577                 gst_structure_free(props);
4578         }
4579
4580         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4581
4582         switch (latency_mode) {
4583         case AUDIO_LATENCY_MODE_LOW:
4584                 latency = g_strndup("low", 3);
4585                 break;
4586         case AUDIO_LATENCY_MODE_MID:
4587                 latency = g_strndup("mid", 3);
4588                 break;
4589         case AUDIO_LATENCY_MODE_HIGH:
4590                 latency = g_strndup("high", 4);
4591                 break;
4592         };
4593
4594 #if 0 //need to check
4595         if (player->sound_focus.user_route_policy != 0)
4596                 route_path = player->sound_focus.user_route_policy;
4597
4598         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4599                         "latency", latency_mode,
4600                         NULL);
4601
4602         LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4603                 volume_type, route_path, latency_mode);
4604         MMPLAYER_FLEAVE();
4605
4606 #endif
4607
4608         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4609                         "latency", latency,
4610                         NULL);
4611
4612         LOGD("audiosink property - latency=%s \n", latency);
4613
4614         g_free(latency);
4615
4616         MMPLAYER_FLEAVE();
4617 }
4618
4619 static int
4620 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4621 {
4622         MMPlayerGstElement* first_element = NULL;
4623         MMPlayerGstElement* audiobin = NULL;
4624         MMHandleType attrs = 0;
4625         GstPad *pad = NULL;
4626         GstPad *ghostpad = NULL;
4627         GList* element_bucket = NULL;
4628         gboolean link_audio_sink_now = TRUE;
4629         int i = 0;
4630         GstCaps *acaps;
4631
4632         MMPLAYER_FENTER();
4633
4634         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4635
4636         /* alloc handles */
4637         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4638         if (!audiobin) {
4639                 LOGE("failed to allocate memory for audiobin\n");
4640                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4641         }
4642
4643         attrs = MMPLAYER_GET_ATTRS(player);
4644
4645         /* create bin */
4646         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4647         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4648         if (!audiobin[MMPLAYER_A_BIN].gst) {
4649                 LOGE("failed to create audiobin\n");
4650                 goto ERROR;
4651         }
4652
4653         /* take it */
4654         player->pipeline->audiobin = audiobin;
4655
4656         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4657
4658         /* Adding audiotp plugin for reverse trickplay feature */
4659 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4660
4661         /* converter */
4662         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4663
4664         /* resampler */
4665         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4666
4667         if (player->set_mode.pcm_extraction) {
4668                 // pcm extraction only and no sound output
4669                 if (player->audio_stream_render_cb_ex) {
4670                         char *caps_str = NULL;
4671                         GstCaps* caps = NULL;
4672                         gchar *format = NULL;
4673
4674                         /* capsfilter */
4675                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4676
4677                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4678
4679                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4680
4681                         caps = gst_caps_new_simple("audio/x-raw",
4682                                         "format", G_TYPE_STRING, format,
4683                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4684                                         "channels", G_TYPE_INT, player->pcm_channel,
4685                                         NULL);
4686                         caps_str = gst_caps_to_string(caps);
4687                         LOGD("new caps : %s\n", caps_str);
4688
4689                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4690
4691                         /* clean */
4692                         gst_caps_unref(caps);
4693                         MMPLAYER_FREEIF(caps_str);
4694
4695                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4696
4697                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4698                         /* raw pad handling signal */
4699                         MMPLAYER_SIGNAL_CONNECT(player,
4700                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4701                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4702                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4703                 } else {
4704                         int dst_samplerate = 0;
4705                         int dst_channels = 0;
4706                         int dst_depth = 0;
4707                         char *caps_str = NULL;
4708                         GstCaps* caps = NULL;
4709
4710                         /* get conf. values */
4711                         mm_attrs_multiple_get(player->attrs,
4712                                                 NULL,
4713                                                 "pcm_extraction_samplerate", &dst_samplerate,
4714                                                 "pcm_extraction_channels", &dst_channels,
4715                                                 "pcm_extraction_depth", &dst_depth,
4716                                                 NULL);
4717
4718                         /* capsfilter */
4719                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4720                         caps = gst_caps_new_simple("audio/x-raw",
4721                                         "rate", G_TYPE_INT, dst_samplerate,
4722                                         "channels", G_TYPE_INT, dst_channels,
4723                                         "depth", G_TYPE_INT, dst_depth,
4724                                         NULL);
4725                         caps_str = gst_caps_to_string(caps);
4726                         LOGD("new caps : %s\n", caps_str);
4727
4728                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4729
4730                         /* clean */
4731                         gst_caps_unref(caps);
4732                         MMPLAYER_FREEIF(caps_str);
4733
4734                         /* fake sink */
4735                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4736
4737                         /* set sync */
4738                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4739                 }
4740         } else {
4741                 // normal playback
4742                 //GstCaps* caps = NULL;
4743                 gint channels = 0;
4744
4745                 /* for logical volume control */
4746                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4747                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4748
4749                 if (player->sound.mute) {
4750                         LOGD("mute enabled\n");
4751                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4752                 }
4753
4754 #if 0
4755                 /*capsfilter */
4756                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4757                 caps = gst_caps_from_string("audio/x-raw-int, "
4758                                         "endianness = (int) LITTLE_ENDIAN, "
4759                                         "signed = (boolean) true, "
4760                                         "width = (int) 16, "
4761                                         "depth = (int) 16");
4762                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4763                 gst_caps_unref(caps);
4764 #endif
4765
4766                 /* check if multi-channels */
4767                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4768                         GstPad *srcpad = NULL;
4769                         GstCaps *caps = NULL;
4770
4771                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4772                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4773                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4774                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4775                                         if (str)
4776                                                 gst_structure_get_int(str, "channels", &channels);
4777                                         gst_caps_unref(caps);
4778                                 }
4779                                 gst_object_unref(srcpad);
4780                         }
4781                 }
4782
4783                 /* audio effect element. if audio effect is enabled */
4784                 if ((strcmp(player->ini.audioeffect_element, ""))
4785                         && (channels <= 2)
4786                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4787                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4788
4789                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4790
4791                         if ((!player->bypass_audio_effect)
4792                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4793                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4794                                         if (!_mmplayer_audio_effect_custom_apply(player))
4795                                                 LOGI("apply audio effect(custom) setting success\n");
4796                                 }
4797                         }
4798
4799                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4800                                 && (player->set_mode.rich_audio))
4801                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4802                 }
4803
4804                 /* create audio sink */
4805                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4806                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4807                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4808
4809                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4810                 if (player->is_content_spherical &&
4811                                 channels == 4 &&
4812                                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4813                                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4814                                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4815
4816                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4817
4818                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4819
4820                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4821                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4822                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4823                         gst_caps_unref(acaps);
4824
4825                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4826                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4827                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4828                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4829
4830                         player->is_openal_plugin_used = TRUE;
4831
4832                         if (player->video360_yaw_radians <= M_PI &&
4833                                         player->video360_yaw_radians >= -M_PI &&
4834                                         player->video360_pitch_radians <= M_PI_2 &&
4835                                         player->video360_pitch_radians >= -M_PI_2) {
4836                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4837                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4838                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4839                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4840                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4841                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4842                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4843                         }
4844                 } else {
4845                         if (player->is_content_spherical)
4846                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4847                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4848                 }
4849
4850                 /* qos on */
4851                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4852                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4853
4854
4855                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4856                         (player->videodec_linked && player->ini.use_system_clock)) {
4857                         LOGD("system clock will be used.\n");
4858                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4859                 }
4860
4861                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4862                         __mmplayer_gst_set_audiosink_property(player, attrs);
4863         }
4864
4865         if (audiobin[MMPLAYER_A_SINK].gst) {
4866                 GstPad *sink_pad = NULL;
4867                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4868                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4869                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4870                 gst_object_unref(GST_OBJECT(sink_pad));
4871         }
4872
4873         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4874
4875         /* adding created elements to bin */
4876         LOGD("adding created elements to bin\n");
4877         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4878                 LOGE("failed to add elements\n");
4879                 goto ERROR;
4880         }
4881
4882         /* linking elements in the bucket by added order. */
4883         LOGD("Linking elements in the bucket by added order.\n");
4884         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4885                 LOGE("failed to link elements\n");
4886                 goto ERROR;
4887         }
4888
4889         /* get first element's sinkpad for creating ghostpad */
4890         first_element = (MMPlayerGstElement *)element_bucket->data;
4891         if (!first_element) {
4892                 LOGE("failed to get first elem\n");
4893                 goto ERROR;
4894         }
4895
4896         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4897         if (!pad) {
4898                 LOGE("failed to get pad from first element of audiobin\n");
4899                 goto ERROR;
4900         }
4901
4902         ghostpad = gst_ghost_pad_new("sink", pad);
4903         if (!ghostpad) {
4904                 LOGE("failed to create ghostpad\n");
4905                 goto ERROR;
4906         }
4907
4908         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4909                 LOGE("failed to add ghostpad to audiobin\n");
4910                 goto ERROR;
4911         }
4912
4913         gst_object_unref(pad);
4914
4915         g_list_free(element_bucket);
4916
4917         mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4918
4919         MMPLAYER_FLEAVE();
4920
4921         return MM_ERROR_NONE;
4922
4923 ERROR:
4924
4925         LOGD("ERROR : releasing audiobin\n");
4926
4927         if (pad)
4928                 gst_object_unref(GST_OBJECT(pad));
4929
4930         if (ghostpad)
4931                 gst_object_unref(GST_OBJECT(ghostpad));
4932
4933         if (element_bucket)
4934                 g_list_free(element_bucket);
4935
4936         /* release element which are not added to bin */
4937         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4938                 /* NOTE : skip bin */
4939                 if (audiobin[i].gst) {
4940                         GstObject* parent = NULL;
4941                         parent = gst_element_get_parent(audiobin[i].gst);
4942
4943                         if (!parent) {
4944                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4945                                 audiobin[i].gst = NULL;
4946                         } else
4947                                 gst_object_unref(GST_OBJECT(parent));
4948                 }
4949         }
4950
4951         /* release audiobin with it's childs */
4952         if (audiobin[MMPLAYER_A_BIN].gst)
4953                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4954
4955         MMPLAYER_FREEIF(audiobin);
4956
4957         player->pipeline->audiobin = NULL;
4958
4959         return MM_ERROR_PLAYER_INTERNAL;
4960 }
4961
4962 static GstPadProbeReturn
4963 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4964 {
4965         mm_player_t* player = (mm_player_t*) u_data;
4966         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4967         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4968
4969         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4970
4971         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4972                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4973
4974         return GST_PAD_PROBE_OK;
4975 }
4976
4977 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4978 {
4979         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4980 }
4981
4982 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4983 {
4984         int ret = MM_ERROR_NONE;
4985         GList *l = NULL;
4986         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4988
4989         MMPLAYER_VIDEO_BO_LOCK(player);
4990
4991         if (player->video_bo_list) {
4992                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4993                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4994                         if (tmp && tmp->bo == bo) {
4995                                 tmp->using = FALSE;
4996                                 LOGD("release bo %p", bo);
4997                                 tbm_bo_unref(tmp->bo);
4998                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4999                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
5000                                 return ret;
5001                         }
5002                 }
5003         } else {
5004                 /* hw codec is running or the list was reset for DRC. */
5005                 LOGW("there is no bo list.");
5006         }
5007         MMPLAYER_VIDEO_BO_UNLOCK(player);
5008
5009         LOGW("failed to find bo %p", bo);
5010         return ret;
5011 }
5012
5013 static void
5014 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
5015 {
5016         GList *l = NULL;
5017
5018         MMPLAYER_FENTER();
5019         MMPLAYER_RETURN_IF_FAIL(player);
5020
5021         MMPLAYER_VIDEO_BO_LOCK(player);
5022         if (player->video_bo_list) {
5023                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
5024                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5025                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5026                         if (tmp) {
5027                                 if (tmp->bo)
5028                                         tbm_bo_unref(tmp->bo);
5029                                 g_free(tmp);
5030                         }
5031                 }
5032                 g_list_free(player->video_bo_list);
5033                 player->video_bo_list = NULL;
5034         }
5035         player->video_bo_size = 0;
5036         MMPLAYER_VIDEO_BO_UNLOCK(player);
5037
5038         MMPLAYER_FLEAVE();
5039         return;
5040 }
5041
5042 static void*
5043 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
5044 {
5045         GList *l = NULL;
5046         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
5047         gboolean ret = TRUE;
5048
5049         /* check DRC, if it is, destroy the prev bo list to create again */
5050         if (player->video_bo_size != size) {
5051                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
5052                 __mmplayer_video_stream_destroy_bo_list(player);
5053                 player->video_bo_size = size;
5054         }
5055
5056         MMPLAYER_VIDEO_BO_LOCK(player);
5057
5058         if ((!player->video_bo_list) ||
5059                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
5060
5061                 /* create bo list */
5062                 int idx = 0;
5063                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5064
5065                 if (player->video_bo_list) {
5066                         /* if bo list did not created all, try it again. */
5067                         idx = g_list_length(player->video_bo_list);
5068                         LOGD("bo list exist(len: %d)", idx);
5069                 }
5070
5071                 for (; idx < player->ini.num_of_video_bo; idx++) {
5072                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5073                         if (!bo_info) {
5074                                 LOGE("Fail to alloc bo_info.");
5075                                 break;
5076                         }
5077                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5078                         if (!bo_info->bo) {
5079                                 LOGE("Fail to tbm_bo_alloc.");
5080                                 g_free(bo_info);
5081                                 break;
5082                         }
5083                         bo_info->using = FALSE;
5084                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5085                 }
5086
5087                 /* update video num buffers */
5088                 player->video_num_buffers = idx;
5089                 if (idx == player->ini.num_of_video_bo)
5090                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5091
5092                 if (idx == 0) {
5093                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5094                         return NULL;
5095                 }
5096
5097                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5098         }
5099
5100         while (TRUE) {
5101                 /* get bo from list*/
5102                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5103                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5104                         if (tmp && (tmp->using == FALSE)) {
5105                                 LOGD("found bo %p to use", tmp->bo);
5106                                 tmp->using = TRUE;
5107                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5108                                 return tbm_bo_ref(tmp->bo);
5109                         }
5110                 }
5111                 if (!ret) {
5112                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5113                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5114                         return NULL;
5115                 }
5116
5117                 if (player->ini.video_bo_timeout <= 0) {
5118                         MMPLAYER_VIDEO_BO_WAIT(player);
5119                 } else {
5120                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5121                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5122                 }
5123                 continue;
5124         }
5125 }
5126
5127 static void
5128 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5129 {
5130         mm_player_t* player = (mm_player_t*)data;
5131         MMPLAYER_FENTER();
5132         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5133
5134         /* send prerolled pkt */
5135         player->video_stream_prerolled = FALSE;
5136
5137         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5138
5139         /* not to send prerolled pkt again */
5140         player->video_stream_prerolled = TRUE;
5141 }
5142
5143 static void
5144 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5145 {
5146         mm_player_t* player = (mm_player_t*)data;
5147         GstCaps *caps = NULL;
5148         MMPlayerVideoStreamDataType *stream = NULL;
5149         MMVideoBuffer *video_buffer = NULL;
5150         GstMemory *dataBlock = NULL;
5151         GstMemory *metaBlock = NULL;
5152         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5153         GstStructure *structure = NULL;
5154         const gchar *string_format = NULL;
5155         unsigned int fourcc = 0;
5156
5157         MMPLAYER_FENTER();
5158         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5159
5160         if (player->video_stream_prerolled) {
5161                 player->video_stream_prerolled = FALSE;
5162                 LOGD("skip the prerolled pkt not to send it again");
5163                 return;
5164         }
5165
5166         caps = gst_pad_get_current_caps(pad);
5167         if (caps == NULL) {
5168                 LOGE("Caps is NULL.");
5169                 return;
5170         }
5171
5172         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5173
5174         /* clear stream data structure */
5175         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5176         if (!stream) {
5177                 LOGE("failed to alloc mem for video data");
5178                 return;
5179         }
5180
5181         structure = gst_caps_get_structure(caps, 0);
5182         gst_structure_get_int(structure, "width", &(stream->width));
5183         gst_structure_get_int(structure, "height", &(stream->height));
5184         string_format = gst_structure_get_string(structure, "format");
5185         if (string_format)
5186                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5187         stream->format = util_get_pixtype(fourcc);
5188         gst_caps_unref(caps);
5189         caps = NULL;
5190
5191     /*
5192         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5193                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5194     */
5195
5196         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5197                 LOGE("Wrong condition!!");
5198                 goto ERROR;
5199         }
5200
5201         /* set size and timestamp */
5202         dataBlock = gst_buffer_peek_memory(buffer, 0);
5203         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5204         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5205
5206         /* check zero-copy */
5207         if (player->set_mode.video_zc &&
5208                 player->set_mode.media_packet_video_stream &&
5209                 gst_buffer_n_memory(buffer) > 1) {
5210                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5211                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5212                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5213         }
5214
5215         if (video_buffer) { /* hw codec */
5216                 /* set tbm bo */
5217                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5218                         int i = 0;
5219
5220                         /* copy pointer of tbm bo, stride, elevation */
5221                         while (video_buffer->handle.bo[i] && i < MM_VIDEO_BUFFER_PLANE_MAX) {
5222                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5223                                 i++;
5224                         }
5225                 } else {
5226                         LOGE("Not support video buffer format");
5227                         goto ERROR;
5228                 }
5229                 memcpy(stream->stride, video_buffer->stride_width,
5230                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5231                 memcpy(stream->elevation, video_buffer->stride_height,
5232                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5233
5234                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5235                 stream->internal_buffer = gst_buffer_ref(buffer);
5236         } else { /* sw codec */
5237                 int i = 0;
5238                 int j = 0;
5239                 int k = 0;
5240                 int ret = TBM_SURFACE_ERROR_NONE;
5241                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5242                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5243                 int size = 0;
5244                 unsigned char *src = NULL;
5245                 unsigned char *dest = NULL;
5246                 tbm_bo_handle thandle;
5247                 tbm_surface_h surface;
5248                 tbm_surface_info_s info;
5249                 gboolean gst_ret;
5250
5251                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5252                 if (!gst_ret) {
5253                         LOGE("fail to gst_memory_map");
5254                         return;
5255                 }
5256
5257
5258                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5259                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5260
5261                         ret = tbm_surface_get_info(surface, &info);
5262
5263                         if (ret != TBM_SURFACE_ERROR_NONE) {
5264                                 tbm_surface_destroy(surface);
5265                                 goto ERROR;
5266                         }
5267                         tbm_surface_destroy(surface);
5268
5269                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5270                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5271                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5272                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5273                         stream->stride[0] = info.planes[0].stride;
5274                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5275                         stream->stride[1] = info.planes[1].stride;
5276                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5277                         stream->stride[2] = info.planes[2].stride;
5278                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5279                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5280                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5281                         stream->stride[0] = stream->width * 4;
5282                         stream->elevation[0] = stream->height;
5283                         size = stream->stride[0] * stream->height;
5284                 } else {
5285                         LOGE("Not support format %d", stream->format);
5286                         goto ERROR;
5287                 }
5288
5289                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5290                 if (!stream->bo[0]) {
5291                         LOGE("Fail to tbm_bo_alloc!!");
5292                         goto ERROR;
5293                 }
5294
5295                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5296                 if (thandle.ptr && mapinfo.data) {
5297                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5298                                 for (i = 0; i < 3; i++) {
5299                                         src = mapinfo.data + src_offset[i];
5300                                         dest = thandle.ptr + info.planes[i].offset;
5301
5302                                         if (i > 0) k = 1;
5303                                         for (j = 0; j < stream->height>>k; j++) {
5304                                                 memcpy(dest, src, stream->width>>k);
5305                                                 src += src_stride[i];
5306                                                 dest += stream->stride[i];
5307                                         }
5308                                 }
5309                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5310                                 memcpy(thandle.ptr, mapinfo.data, size);
5311                         } else {
5312                                 LOGE("Not support format %d", stream->format);
5313                                 goto ERROR;
5314                         }
5315                 } else {
5316                         LOGE("data pointer is wrong. dest : %p, src : %p",
5317                                         thandle.ptr, mapinfo.data);
5318                         goto ERROR;
5319                 }
5320                 tbm_bo_unmap(stream->bo[0]);
5321         }
5322
5323         if (player->video_stream_cb) { /* This has been already checked at the entry */
5324                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5325                         LOGE("failed to send video stream data.");
5326                         goto ERROR;
5327                 }
5328         }
5329
5330         if (metaBlock)
5331                 gst_memory_unmap(metaBlock, &mapinfo);
5332         else
5333                 gst_memory_unmap(dataBlock, &mapinfo);
5334
5335         return;
5336
5337 ERROR:
5338         LOGE("release video stream resource.");
5339         if (metaBlock) {
5340                 int i = 0;
5341                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5342                         if (stream->bo[i])
5343                                 tbm_bo_unref(stream->bo[i]);
5344                 }
5345                 gst_memory_unmap(metaBlock, &mapinfo);
5346
5347                 /* unref gst buffer */
5348                 if (stream->internal_buffer)
5349                         gst_buffer_unref(stream->internal_buffer);
5350         } else if (dataBlock) {
5351                 if (stream->bo[0])
5352                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5353                 gst_memory_unmap(dataBlock, &mapinfo);
5354         }
5355
5356         g_free(stream);
5357         return;
5358 }
5359
5360 static int
5361 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5362 {
5363         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5364         GList* element_bucket = *bucket;
5365
5366         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5367
5368         MMPLAYER_FENTER();
5369
5370         if (player->set_mode.video_zc || player->is_content_spherical) {
5371                 LOGD("do not need to add video filters.");
5372                 return MM_ERROR_NONE;
5373         }
5374
5375         /* in case of sw codec except 360 playback,
5376          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5377         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5378         LOGD("using video converter: %s", video_csc);
5379
5380         /* set video rotator */
5381         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5382
5383         *bucket = element_bucket;
5384         MMPLAYER_FLEAVE();
5385         return MM_ERROR_NONE;
5386
5387 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5388         *bucket = NULL;
5389         MMPLAYER_FLEAVE();
5390         return MM_ERROR_PLAYER_INTERNAL;
5391 }
5392
5393 /**
5394  * This function is to create video pipeline.
5395  *
5396  * @param       player          [in]    handle of player
5397  *              caps            [in]    src caps of decoder
5398  *              surface_type    [in]    surface type for video rendering
5399  *
5400  * @return      This function returns zero on success.
5401  * @remark
5402  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5403  */
5404 /**
5405   * VIDEO PIPELINE
5406   * - video overlay surface(arm/x86) : tizenwlsink
5407   */
5408 static int
5409 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5410 {
5411         GstPad *pad = NULL;
5412         MMHandleType attrs;
5413         GList*element_bucket = NULL;
5414         MMPlayerGstElement* first_element = NULL;
5415         MMPlayerGstElement* videobin = NULL;
5416         gchar *videosink_element = NULL;
5417
5418         MMPLAYER_FENTER();
5419
5420         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421
5422         /* alloc handles */
5423         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5424         if (!videobin)
5425                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5426
5427         player->pipeline->videobin = videobin;
5428
5429         attrs = MMPLAYER_GET_ATTRS(player);
5430         if (!attrs) {
5431                 LOGE("cannot get content attribute");
5432                 return MM_ERROR_PLAYER_INTERNAL;
5433         }
5434
5435         /* create bin */
5436         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5437         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5438         if (!videobin[MMPLAYER_V_BIN].gst) {
5439                 LOGE("failed to create videobin");
5440                 goto ERROR;
5441         }
5442
5443         int enable_video_decoded_cb = 0;
5444         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5445
5446         if (player->is_content_spherical) {
5447                 LOGD("video360 elem will be added.");
5448
5449                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5450                                 "video-360", TRUE, player);
5451
5452                 /* Set spatial media metadata and/or user settings to the element.
5453                  * */
5454                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5455                                 "projection-type", player->video360_metadata.projection_type, NULL);
5456
5457                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5458                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5459
5460                 if (player->video360_metadata.full_pano_width_pixels &&
5461                                 player->video360_metadata.full_pano_height_pixels &&
5462                                 player->video360_metadata.cropped_area_image_width &&
5463                                 player->video360_metadata.cropped_area_image_height) {
5464                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5465                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5466                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5467                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5468                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5469                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5470                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5471                                         NULL);
5472                 }
5473
5474                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5475                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5476                                         "horizontal-fov", player->video360_horizontal_fov,
5477                                         "vertical-fov", player->video360_vertical_fov, NULL);
5478                 }
5479
5480                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5481                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5482                                         "zoom", 1.0f / player->video360_zoom, NULL);
5483                 }
5484
5485                 if (player->video360_yaw_radians <= M_PI &&
5486                                 player->video360_yaw_radians >= -M_PI &&
5487                                 player->video360_pitch_radians <= M_PI_2 &&
5488                                 player->video360_pitch_radians >= -M_PI_2) {
5489                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5490                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5491                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5492                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5493                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5494                                         "pose-yaw", player->video360_metadata.init_view_heading,
5495                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5496                 }
5497
5498                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5499                                 "passthrough", !player->is_video360_enabled, NULL);
5500         }
5501
5502         /* set video sink */
5503         switch (surface_type) {
5504         case MM_DISPLAY_SURFACE_OVERLAY:
5505                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5506                         goto ERROR;
5507                 if (strlen(player->ini.videosink_element_overlay) > 0)
5508                         videosink_element = player->ini.videosink_element_overlay;
5509                 else
5510                         goto ERROR;
5511                 break;
5512         case MM_DISPLAY_SURFACE_NULL:
5513                 if (strlen(player->ini.videosink_element_fake) > 0)
5514                         videosink_element = player->ini.videosink_element_fake;
5515                 else
5516                         goto ERROR;
5517                 break;
5518         case MM_DISPLAY_SURFACE_REMOTE:
5519                 if (strlen(player->ini.videosink_element_fake) > 0)
5520                         videosink_element = player->ini.videosink_element_fake;
5521                 else
5522                         goto ERROR;
5523                 break;
5524         default:
5525                 LOGE("unidentified surface type");
5526                 goto ERROR;
5527         }
5528         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5529
5530         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5531
5532         /* additional setting for sink plug-in */
5533         switch (surface_type) {
5534         case MM_DISPLAY_SURFACE_OVERLAY:
5535         {
5536                 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5537                 if (!use_tbm) {
5538                         LOGD("selected videosink name: %s", videosink_element);
5539
5540                         /* support shard memory with S/W codec on HawkP */
5541                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5542                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5543                                         "use-tbm", use_tbm, NULL);
5544                         }
5545                 } else {
5546                         if (attrs) {
5547                                 int gapless = 0;
5548
5549                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5550
5551                                 if (gapless > 0) {
5552                                         LOGD("disable last-sample");
5553                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5554                                 }
5555                         }
5556                 }
5557                 if (player->set_mode.media_packet_video_stream) {
5558                         int enable = 0;
5559                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5560                         if (enable)
5561                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5562
5563                         MMPLAYER_SIGNAL_CONNECT(player,
5564                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5565                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5566                                                                         "handoff",
5567                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5568                                                                         (gpointer)player);
5569
5570                         MMPLAYER_SIGNAL_CONNECT(player,
5571                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5572                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5573                                                                         "preroll-handoff",
5574                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5575                                                                         (gpointer)player);
5576                 }
5577                 break;
5578         }
5579         case MM_DISPLAY_SURFACE_REMOTE:
5580         {
5581                 if (player->set_mode.media_packet_video_stream) {
5582                         LOGE("add data probe at videosink");
5583                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5584                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5585
5586                         MMPLAYER_SIGNAL_CONNECT(player,
5587                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5588                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5589                                                                         "handoff",
5590                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5591                                                                         (gpointer)player);
5592
5593                         MMPLAYER_SIGNAL_CONNECT(player,
5594                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5595                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5596                                                                         "preroll-handoff",
5597                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5598                                                                         (gpointer)player);
5599                         if (attrs) {
5600                                 int gapless = 0;
5601
5602                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5603
5604                                 if (gapless > 0) {
5605                                         LOGD("disable last-sample");
5606                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5607                                 }
5608                         }
5609                 }
5610                 break;
5611         }
5612         default:
5613                 break;
5614         }
5615
5616         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5617                 goto ERROR;
5618
5619         if (videobin[MMPLAYER_V_SINK].gst) {
5620                 GstPad *sink_pad = NULL;
5621                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5622                 if (sink_pad) {
5623                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5624                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5625                         gst_object_unref(GST_OBJECT(sink_pad));
5626                 } else
5627                         LOGW("failed to get sink pad from videosink\n");
5628         }
5629
5630         /* store it as it's sink element */
5631         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5632
5633         /* adding created elements to bin */
5634         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5635                 LOGE("failed to add elements\n");
5636                 goto ERROR;
5637         }
5638
5639         /* Linking elements in the bucket by added order */
5640         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5641                 LOGE("failed to link elements\n");
5642                 goto ERROR;
5643         }
5644
5645         /* get first element's sinkpad for creating ghostpad */
5646         if (element_bucket)
5647                 first_element = (MMPlayerGstElement *)element_bucket->data;
5648         if (!first_element) {
5649                 LOGE("failed to get first element from bucket\n");
5650                 goto ERROR;
5651         }
5652
5653         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5654         if (!pad) {
5655                 LOGE("failed to get pad from first element\n");
5656                 goto ERROR;
5657         }
5658
5659         /* create ghostpad */
5660         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5661         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5662                 LOGE("failed to add ghostpad to videobin\n");
5663                 goto ERROR;
5664         }
5665         gst_object_unref(pad);
5666
5667         /* done. free allocated variables */
5668         if (element_bucket)
5669                 g_list_free(element_bucket);
5670
5671         MMPLAYER_FLEAVE();
5672
5673         return MM_ERROR_NONE;
5674
5675 ERROR:
5676         LOGE("ERROR : releasing videobin\n");
5677
5678         g_list_free(element_bucket);
5679
5680         if (pad)
5681                 gst_object_unref(GST_OBJECT(pad));
5682
5683         /* release videobin with it's childs */
5684         if (videobin[MMPLAYER_V_BIN].gst)
5685                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5686
5687
5688         MMPLAYER_FREEIF(videobin);
5689
5690         player->pipeline->videobin = NULL;
5691
5692         return MM_ERROR_PLAYER_INTERNAL;
5693 }
5694
5695 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5696 {
5697         GList *element_bucket = NULL;
5698         MMPlayerGstElement *textbin = player->pipeline->textbin;
5699
5700         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5701         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5702         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5703                                                         "signal-handoffs", FALSE,
5704                                                         NULL);
5705
5706         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5707         MMPLAYER_SIGNAL_CONNECT(player,
5708                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5709                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5710                                                         "handoff",
5711                                                         G_CALLBACK(__mmplayer_update_subtitle),
5712                                                         (gpointer)player);
5713
5714         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5715         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5716         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5717
5718         if (!player->play_subtitle) {
5719                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5720                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5721         }
5722
5723         /* adding created elements to bin */
5724         LOGD("adding created elements to bin\n");
5725         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5726                 LOGE("failed to add elements\n");
5727                 goto ERROR;
5728         }
5729
5730         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5731         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5732         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5733
5734         /* linking elements in the bucket by added order. */
5735         LOGD("Linking elements in the bucket by added order.\n");
5736         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5737                 LOGE("failed to link elements\n");
5738                 goto ERROR;
5739         }
5740
5741         /* done. free allocated variables */
5742         g_list_free(element_bucket);
5743
5744         if (textbin[MMPLAYER_T_QUEUE].gst) {
5745                 GstPad *pad = NULL;
5746                 GstPad *ghostpad = NULL;
5747
5748                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5749                 if (!pad) {
5750                         LOGE("failed to get sink pad of text queue");
5751                         goto ERROR;
5752                 }
5753
5754                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5755                 gst_object_unref(pad);
5756
5757                 if (!ghostpad) {
5758                         LOGE("failed to create ghostpad of textbin\n");
5759                         goto ERROR;
5760                 }
5761
5762                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5763                         LOGE("failed to add ghostpad to textbin\n");
5764                         gst_object_unref(ghostpad);
5765                         goto ERROR;
5766                 }
5767         }
5768
5769         return MM_ERROR_NONE;
5770
5771 ERROR:
5772         g_list_free(element_bucket);
5773
5774         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5775                 LOGE("remove textbin sink from sink list");
5776                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5777         }
5778
5779         /* release element at __mmplayer_gst_create_text_sink_bin */
5780         return MM_ERROR_PLAYER_INTERNAL;
5781 }
5782
5783 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5784 {
5785         MMPlayerGstElement *textbin = NULL;
5786         GList *element_bucket = NULL;
5787         int surface_type = 0;
5788         gint i = 0;
5789
5790         MMPLAYER_FENTER();
5791
5792         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793
5794         /* alloc handles */
5795         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5796         if (!textbin) {
5797                 LOGE("failed to allocate memory for textbin\n");
5798                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5799         }
5800
5801         /* create bin */
5802         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5803         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5804         if (!textbin[MMPLAYER_T_BIN].gst) {
5805                 LOGE("failed to create textbin\n");
5806                 goto ERROR;
5807         }
5808
5809         /* take it */
5810         player->pipeline->textbin = textbin;
5811
5812         /* fakesink */
5813         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5814         LOGD("surface type for subtitle : %d", surface_type);
5815         switch (surface_type) {
5816         case MM_DISPLAY_SURFACE_OVERLAY:
5817         case MM_DISPLAY_SURFACE_NULL:
5818         case MM_DISPLAY_SURFACE_REMOTE:
5819                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5820                         LOGE("failed to make plain text elements\n");
5821                         goto ERROR;
5822                 }
5823                 break;
5824         default:
5825                 goto ERROR;
5826                 break;
5827         }
5828
5829         MMPLAYER_FLEAVE();
5830
5831         return MM_ERROR_NONE;
5832
5833 ERROR:
5834
5835         LOGD("ERROR : releasing textbin\n");
5836
5837         g_list_free(element_bucket);
5838
5839         /* release signal */
5840         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5841
5842         /* release element which are not added to bin */
5843         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5844                 /* NOTE : skip bin */
5845                 if (textbin[i].gst) {
5846                         GstObject* parent = NULL;
5847                         parent = gst_element_get_parent(textbin[i].gst);
5848
5849                         if (!parent) {
5850                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5851                                 textbin[i].gst = NULL;
5852                         } else {
5853                                 gst_object_unref(GST_OBJECT(parent));
5854                         }
5855                 }
5856         }
5857
5858         /* release textbin with it's childs */
5859         if (textbin[MMPLAYER_T_BIN].gst)
5860                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5861
5862         MMPLAYER_FREEIF(player->pipeline->textbin);
5863         player->pipeline->textbin = NULL;
5864
5865         MMPLAYER_FLEAVE();
5866         return MM_ERROR_PLAYER_INTERNAL;
5867 }
5868
5869
5870 static int
5871 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5872 {
5873         MMPlayerGstElement* mainbin = NULL;
5874         MMPlayerGstElement* textbin = NULL;
5875         MMHandleType attrs = 0;
5876         GstElement *subsrc = NULL;
5877         GstElement *subparse = NULL;
5878         gchar *subtitle_uri = NULL;
5879         const gchar *charset = NULL;
5880         GstPad *pad = NULL;
5881
5882         MMPLAYER_FENTER();
5883
5884         /* get mainbin */
5885         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5886                                                                 player->pipeline &&
5887                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5888
5889         mainbin = player->pipeline->mainbin;
5890
5891         attrs = MMPLAYER_GET_ATTRS(player);
5892         if (!attrs) {
5893                 LOGE("cannot get content attribute\n");
5894                 return MM_ERROR_PLAYER_INTERNAL;
5895         }
5896
5897         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5898         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5899                 LOGE("subtitle uri is not proper filepath.\n");
5900                 return MM_ERROR_PLAYER_INVALID_URI;
5901         }
5902
5903         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5904                 LOGE("failed to get storage info of subtitle path");
5905                 return MM_ERROR_PLAYER_INVALID_URI;
5906         }
5907
5908         LOGD("subtitle file path is [%s].\n", subtitle_uri);
5909
5910         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5911         player->subtitle_language_list = NULL;
5912         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5913
5914         /* create the subtitle source */
5915         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5916         if (!subsrc) {
5917                 LOGE("failed to create filesrc element\n");
5918                 goto ERROR;
5919         }
5920         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5921
5922         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5923         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5924
5925         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5926                 LOGW("failed to add queue\n");
5927                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5928                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5929                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5930                 goto ERROR;
5931         }
5932
5933         /* subparse */
5934         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5935         if (!subparse) {
5936                 LOGE("failed to create subparse element\n");
5937                 goto ERROR;
5938         }
5939
5940         charset = util_get_charset(subtitle_uri);
5941         if (charset) {
5942                 LOGD("detected charset is %s\n", charset);
5943                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5944         }
5945
5946         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5947         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5948
5949         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5950                 LOGW("failed to add subparse\n");
5951                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5952                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5953                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5954                 goto ERROR;
5955         }
5956
5957         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5958                 LOGW("failed to link subsrc and subparse\n");
5959                 goto ERROR;
5960         }
5961
5962         player->play_subtitle = TRUE;
5963         player->adjust_subtitle_pos = 0;
5964
5965         LOGD("play subtitle using subtitle file\n");
5966
5967         if (player->pipeline->textbin == NULL) {
5968                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5969                         LOGE("failed to create text sink bin. continuing without text\n");
5970                         goto ERROR;
5971                 }
5972
5973                 textbin = player->pipeline->textbin;
5974
5975                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5976                         LOGW("failed to add textbin\n");
5977
5978                         /* release signal */
5979                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5980
5981                         /* release textbin with it's childs */
5982                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5983                         MMPLAYER_FREEIF(player->pipeline->textbin);
5984                         player->pipeline->textbin = textbin = NULL;
5985                         goto ERROR;
5986                 }
5987
5988                 LOGD("link text input selector and textbin ghost pad");
5989
5990                 player->textsink_linked = 1;
5991                 player->external_text_idx = 0;
5992                 LOGI("player->textsink_linked set to 1\n");
5993         } else {
5994                 textbin = player->pipeline->textbin;
5995                 LOGD("text bin has been created. reuse it.");
5996                 player->external_text_idx = 1;
5997         }
5998
5999         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
6000                 LOGW("failed to link subparse and textbin\n");
6001                 goto ERROR;
6002         }
6003
6004         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
6005         if (!pad) {
6006                 LOGE("failed to get sink pad from textsink to probe data");
6007                 goto ERROR;
6008         }
6009
6010         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
6011                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
6012
6013         gst_object_unref(pad);
6014         pad = NULL;
6015
6016         /* create dot. for debugging */
6017         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
6018         MMPLAYER_FLEAVE();
6019
6020         return MM_ERROR_NONE;
6021
6022 ERROR:
6023         /* release text pipeline resource */
6024         player->textsink_linked = 0;
6025
6026         /* release signal */
6027         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
6028
6029         if (player->pipeline->textbin) {
6030                 LOGE("remove textbin");
6031
6032                 /* release textbin with it's childs */
6033                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
6034                 MMPLAYER_FREEIF(player->pipeline->textbin);
6035                 player->pipeline->textbin = NULL;
6036
6037         }
6038
6039         /* release subtitle elem */
6040         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
6041         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
6042
6043         return MM_ERROR_PLAYER_INTERNAL;
6044 }
6045
6046 gboolean
6047 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
6048 {
6049         mm_player_t* player = (mm_player_t*) data;
6050         MMMessageParamType msg = {0, };
6051         GstClockTime duration = 0;
6052         gpointer text = NULL;
6053         guint text_size = 0;
6054         gboolean ret = TRUE;
6055         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
6056
6057         MMPLAYER_FENTER();
6058
6059         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6060         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
6061
6062         if (player->is_subtitle_force_drop) {
6063                 LOGW("subtitle is dropped forcedly.");
6064                 return ret;
6065         }
6066
6067         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
6068         text = mapinfo.data;
6069         text_size = mapinfo.size;
6070         duration = GST_BUFFER_DURATION(buffer);
6071
6072         if (player->set_mode.subtitle_off) {
6073                 LOGD("subtitle is OFF.\n");
6074                 return TRUE;
6075         }
6076
6077         if (!text || (text_size == 0)) {
6078                 LOGD("There is no subtitle to be displayed.\n");
6079                 return TRUE;
6080         }
6081
6082         msg.data = (void *) text;
6083         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
6084
6085         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
6086
6087         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
6088         gst_buffer_unmap(buffer, &mapinfo);
6089
6090         MMPLAYER_FLEAVE();
6091
6092         return ret;
6093 }
6094
6095 static GstPadProbeReturn
6096 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
6097
6098 {
6099         mm_player_t *player = (mm_player_t *) u_data;
6100         GstClockTime cur_timestamp = 0;
6101         gint64 adjusted_timestamp = 0;
6102         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
6103
6104         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6105
6106         if (player->set_mode.subtitle_off) {
6107                 LOGD("subtitle is OFF.\n");
6108                 return TRUE;
6109         }
6110
6111         if (player->adjust_subtitle_pos == 0) {
6112                 LOGD("nothing to do");
6113                 return TRUE;
6114         }
6115
6116         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6117         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6118
6119         if (adjusted_timestamp < 0) {
6120                 LOGD("adjusted_timestamp under zero");
6121                 MMPLAYER_FLEAVE();
6122                 return FALSE;
6123         }
6124
6125         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6126         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6127                                 GST_TIME_ARGS(cur_timestamp),
6128                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6129
6130         return GST_PAD_PROBE_OK;
6131 }
6132 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6133 {
6134         MMPLAYER_FENTER();
6135
6136         /* check player and subtitlebin are created */
6137         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6138         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6139
6140         if (position == 0) {
6141                 LOGD("nothing to do\n");
6142                 MMPLAYER_FLEAVE();
6143                 return MM_ERROR_NONE;
6144         }
6145
6146         switch (format) {
6147         case MM_PLAYER_POS_FORMAT_TIME:
6148                 {
6149                         /* check current postion */
6150                         player->adjust_subtitle_pos = position;
6151
6152                         LOGD("save adjust_subtitle_pos in player") ;
6153                 }
6154                 break;
6155
6156         default:
6157                 {
6158                         LOGW("invalid format.\n");
6159                         MMPLAYER_FLEAVE();
6160                         return MM_ERROR_INVALID_ARGUMENT;
6161                 }
6162         }
6163
6164         MMPLAYER_FLEAVE();
6165
6166         return MM_ERROR_NONE;
6167 }
6168 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6169 {
6170         MMPLAYER_FENTER();
6171         LOGD("adjusting video_pos in player") ;
6172         int current_pos = 0;
6173         /* check player and videobin are created */
6174         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6175         if (!player->pipeline->videobin ||
6176                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6177                 LOGD("no video pipeline or sink is there");
6178                 return MM_ERROR_PLAYER_INVALID_STATE ;
6179         }
6180         if (offset == 0) {
6181                 LOGD("nothing to do\n");
6182                 MMPLAYER_FLEAVE();
6183                 return MM_ERROR_NONE;
6184         }
6185         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6186                 LOGD("failed to get current position");
6187                 return MM_ERROR_PLAYER_INTERNAL;
6188         }
6189         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6190                 LOGD("enter video delay is valid");
6191         } else {
6192                 LOGD("enter video delay is crossing content boundary");
6193                 return MM_ERROR_INVALID_ARGUMENT ;
6194         }
6195         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6196         LOGD("video delay has been done");
6197         MMPLAYER_FLEAVE();
6198
6199         return MM_ERROR_NONE;
6200 }
6201
6202 static void
6203 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6204 {
6205         GstElement *appsrc = element;
6206         tBuffer *buf = (tBuffer *)user_data;
6207         GstBuffer *buffer = NULL;
6208         GstFlowReturn ret = GST_FLOW_OK;
6209         gint len = size;
6210
6211         MMPLAYER_RETURN_IF_FAIL(element);
6212         MMPLAYER_RETURN_IF_FAIL(buf);
6213
6214         buffer = gst_buffer_new();
6215
6216         if (buf->offset >= buf->len) {
6217                 LOGD("call eos appsrc\n");
6218                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6219                 return;
6220         }
6221
6222         if (buf->len - buf->offset < size)
6223                 len = buf->len - buf->offset;
6224
6225         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6226         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6227         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6228
6229         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6230         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6231
6232         buf->offset += len;
6233 }
6234
6235 static gboolean
6236 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6237 {
6238         tBuffer *buf = (tBuffer *)user_data;
6239
6240         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6241
6242         buf->offset  = (int)size;
6243
6244         return TRUE;
6245 }
6246
6247 static GstBusSyncReply
6248 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6249 {
6250         mm_player_t *player = (mm_player_t *)data;
6251         GstBusSyncReply reply = GST_BUS_DROP;
6252
6253         if (!(player->pipeline && player->pipeline->mainbin)) {
6254                 LOGE("player pipeline handle is null");
6255                 return GST_BUS_PASS;
6256         }
6257
6258         if (!__mmplayer_check_useful_message(player, message)) {
6259                 gst_message_unref(message);
6260                 return GST_BUS_DROP;
6261         }
6262
6263         switch (GST_MESSAGE_TYPE(message)) {
6264         case GST_MESSAGE_STATE_CHANGED:
6265                 /* post directly for fast launch */
6266                 if (player->sync_handler) {
6267                         __mmplayer_gst_callback(message, player);
6268                         reply = GST_BUS_DROP;
6269                 } else
6270                         reply = GST_BUS_PASS;
6271                 break;
6272         case GST_MESSAGE_TAG:
6273                 __mmplayer_gst_extract_tag_from_msg(player, message);
6274
6275                 #if 0 // debug
6276                 {
6277                         GstTagList *tags = NULL;
6278
6279                         gst_message_parse_tag(message, &tags);
6280                         if (tags) {
6281                                 LOGE("TAGS received from element \"%s\".\n",
6282                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6283
6284                                 gst_tag_list_foreach(tags, print_tag, NULL);
6285                                 gst_tag_list_free(tags);
6286                                 tags = NULL;
6287                         }
6288                         break;
6289                 }
6290                 #endif
6291                 break;
6292
6293         case GST_MESSAGE_DURATION_CHANGED:
6294                 __mmplayer_gst_handle_duration(player, message);
6295                 break;
6296         case GST_MESSAGE_ASYNC_DONE:
6297                 /* NOTE:Don't call gst_callback directly
6298                  * because previous frame can be showed even though this message is received for seek.
6299                  */
6300         default:
6301                 reply = GST_BUS_PASS;
6302                 break;
6303         }
6304
6305         if (reply == GST_BUS_DROP)
6306                 gst_message_unref(message);
6307
6308         return reply;
6309 }
6310
6311 static gboolean
6312 __mmplayer_gst_create_decoder(mm_player_t *player,
6313                                                                 MMPlayerTrackType track,
6314                                                                 GstPad* srcpad,
6315                                                                 enum MainElementID elemId,
6316                                                                 const gchar* name)
6317 {
6318         gboolean ret = TRUE;
6319         GstPad *sinkpad = NULL;
6320
6321         MMPLAYER_FENTER();
6322
6323         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6324                                                 player->pipeline &&
6325                                                 player->pipeline->mainbin, FALSE);
6326         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6327         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6328         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6329
6330         GstElement *decodebin = NULL;
6331         GstCaps *dec_caps = NULL;
6332
6333         /* create decodebin */
6334         decodebin = gst_element_factory_make("decodebin", name);
6335
6336         if (!decodebin) {
6337                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6338                 ret = FALSE;
6339                 goto ERROR;
6340         }
6341
6342         /* raw pad handling signal */
6343         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6344                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6345
6346         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6347         before looking for any elements that can handle that stream.*/
6348         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6349                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6350
6351         /* This signal is emitted when a element is added to the bin.*/
6352         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6353                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6354
6355         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6356                 LOGE("failed to add new decodebin\n");
6357                 ret = FALSE;
6358                 goto ERROR;
6359         }
6360
6361         dec_caps = gst_pad_query_caps(srcpad, NULL);
6362         if (dec_caps) {
6363                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6364                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6365                 gst_caps_unref(dec_caps);
6366         }
6367
6368         player->pipeline->mainbin[elemId].id = elemId;
6369         player->pipeline->mainbin[elemId].gst = decodebin;
6370
6371         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6372
6373         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6374                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6375                 gst_object_unref(GST_OBJECT(decodebin));
6376         }
6377
6378         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6379                 LOGE("failed to sync second level decodebin state with parent\n");
6380
6381         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6382
6383 ERROR:
6384         if (sinkpad) {
6385                 gst_object_unref(GST_OBJECT(sinkpad));
6386                 sinkpad = NULL;
6387         }
6388         MMPLAYER_FLEAVE();
6389
6390         return ret;
6391 }
6392
6393 /**
6394  * This function is to create  audio or video pipeline for playing.
6395  *
6396  * @param       player          [in]    handle of player
6397  *
6398  * @return      This function returns zero on success.
6399  * @remark
6400  * @see
6401  */
6402 static int
6403 __mmplayer_gst_create_pipeline(mm_player_t* player)
6404 {
6405         GstBus  *bus = NULL;
6406         MMPlayerGstElement *mainbin = NULL;
6407         MMHandleType attrs = 0;
6408         GstElement* element = NULL;
6409         GstElement* elem_src_audio = NULL;
6410         GstElement* elem_src_subtitle = NULL;
6411         GstElement* es_video_queue = NULL;
6412         GstElement* es_audio_queue = NULL;
6413         GstElement* es_subtitle_queue = NULL;
6414         GList* element_bucket = NULL;
6415         gboolean need_state_holder = TRUE;
6416         gint i = 0;
6417 #ifdef SW_CODEC_ONLY
6418         int surface_type = 0;
6419 #endif
6420         MMPLAYER_FENTER();
6421
6422         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6423
6424         /* get profile attribute */
6425         attrs = MMPLAYER_GET_ATTRS(player);
6426         if (!attrs) {
6427                 LOGE("cannot get content attribute\n");
6428                 goto INIT_ERROR;
6429         }
6430
6431         /* create pipeline handles */
6432         if (player->pipeline) {
6433                 LOGW("pipeline should be released before create new one\n");
6434                 goto INIT_ERROR;
6435         }
6436
6437         player->video360_metadata.is_spherical = -1;
6438         player->is_openal_plugin_used = FALSE;
6439
6440         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6441         if (player->pipeline == NULL)
6442                 goto INIT_ERROR;
6443
6444         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6445
6446         /* create mainbin */
6447         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6448         if (mainbin == NULL)
6449                 goto INIT_ERROR;
6450
6451         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6452
6453         /* create pipeline */
6454         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6455         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6456         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6457                 LOGE("failed to create pipeline\n");
6458                 goto INIT_ERROR;
6459         }
6460         player->demux_pad_index = 0;
6461         player->subtitle_language_list = NULL;
6462
6463         player->is_subtitle_force_drop = FALSE;
6464         player->last_multiwin_status = FALSE;
6465
6466         _mmplayer_track_initialize(player);
6467         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6468
6469         /* create source element */
6470         switch (player->profile.uri_type) {
6471         /* rtsp streamming */
6472         case MM_PLAYER_URI_TYPE_URL_RTSP:
6473                 {
6474                         gint network_bandwidth;
6475                         gchar *user_agent, *wap_profile;
6476
6477                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6478
6479                         if (!element) {
6480                                 LOGE("failed to create streaming source element\n");
6481                                 break;
6482                         }
6483
6484                         /* make it zero */
6485                         network_bandwidth = 0;
6486                         user_agent = wap_profile = NULL;
6487
6488                         /* get attribute */
6489                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6490                         mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6491                         mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6492
6493                         SECURE_LOGD("user_agent : %s\n", user_agent);
6494                         SECURE_LOGD("wap_profile : %s\n", wap_profile);
6495
6496                         /* setting property to streaming source */
6497                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6498                         if (user_agent)
6499                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6500                         if (wap_profile)
6501                                 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6502
6503                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6504                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6505                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6506                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6507                 }
6508                 break;
6509
6510         /* http streaming*/
6511         case MM_PLAYER_URI_TYPE_URL_HTTP:
6512                 {
6513                         gchar *user_agent, *proxy, *cookies, **cookie_list;
6514                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6515                         user_agent = proxy = cookies = NULL;
6516                         cookie_list = NULL;
6517                         gint mode = MM_PLAYER_PD_MODE_NONE;
6518
6519                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6520
6521                         player->pd_mode = mode;
6522
6523                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6524
6525                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6526                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6527                                 if (!element) {
6528                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6529                                         break;
6530                                 }
6531                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6532
6533                                 /* get attribute */
6534                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6535                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6536                                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6537                                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6538
6539                                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6540                                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6541                                         LOGD("get timeout from ini\n");
6542                                         http_timeout = player->ini.http_timeout;
6543                                 }
6544
6545                                 /* get attribute */
6546                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6547                                 SECURE_LOGD("cookies : %s\n", cookies);
6548                                 SECURE_LOGD("proxy : %s\n", proxy);
6549                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6550                                 LOGD("timeout : %d\n",  http_timeout);
6551
6552                                 /* setting property to streaming source */
6553                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6554                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6555                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6556
6557                                 /* check if proxy is valid or not */
6558                                 if (util_check_valid_url(proxy))
6559                                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6560                                 /* parsing cookies */
6561                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6562                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6563                                         g_strfreev(cookie_list);
6564                                 }
6565                                 if (user_agent)
6566                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6567
6568                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6569                                         LOGW("it's dash. and it's still experimental feature.");
6570                         } else {
6571                                 // progressive download
6572                                 gchar* location = NULL;
6573
6574                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6575                                         gchar *path = NULL;
6576
6577                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6578
6579                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6580
6581                                         LOGD("PD Location : %s\n", path);
6582
6583                                         if (path) {
6584                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6585                                                         LOGE("failed to get storage info");
6586                                                         break;
6587                                                 }
6588                                                 player->pd_file_save_path = g_strdup(path);
6589                                         } else {
6590                                                 LOGE("can't find pd location so, it should be set \n");
6591                                                 break;
6592                                         }
6593                                 }
6594
6595                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6596                                 if (!element) {
6597                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6598                                         break;
6599                                 }
6600
6601                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6602                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6603                                 else
6604                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6605                                 g_object_get(element, "location", &location, NULL);
6606                                 LOGD("PD_LOCATION [%s].\n", location);
6607                                 if (location)
6608                                         g_free(location);
6609                         }
6610                 }
6611                 break;
6612
6613         /* file source */
6614         case MM_PLAYER_URI_TYPE_FILE:
6615                 {
6616                         LOGD("using filesrc for 'file://' handler.\n");
6617                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6618                                 LOGE("failed to get storage info");
6619                                 break;
6620                         }
6621
6622                         element = gst_element_factory_make("filesrc", "source");
6623                         if (!element) {
6624                                 LOGE("failed to create filesrc\n");
6625                                 break;
6626                         }
6627
6628                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6629                 }
6630                 break;
6631
6632         case MM_PLAYER_URI_TYPE_SS:
6633                 {
6634                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6635                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6636                         if (!element) {
6637                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6638                                 break;
6639                         }
6640
6641                         mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6642
6643                         if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6644                                 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6645                                 LOGD("get timeout from ini\n");
6646                                 http_timeout = player->ini.http_timeout;
6647                         }
6648
6649                         /* setting property to streaming source */
6650                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6651                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6652                 }
6653                 break;
6654         case MM_PLAYER_URI_TYPE_MS_BUFF:
6655                 {
6656                         LOGD("MS buff src is selected\n");
6657
6658                         if (player->v_stream_caps) {
6659                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6660                                 if (!element) {
6661                                         LOGF("failed to create video app source element[appsrc].\n");
6662                                         break;
6663                                 }
6664
6665                                 if (player->a_stream_caps) {
6666                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6667                                         if (!elem_src_audio) {
6668                                                 LOGF("failed to create audio app source element[appsrc].\n");
6669                                                 break;
6670                                         }
6671                                 }
6672                         } else if (player->a_stream_caps) {
6673                                 /* no video, only audio pipeline*/
6674                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6675                                 if (!element) {
6676                                         LOGF("failed to create audio app source element[appsrc].\n");
6677                                         break;
6678                                 }
6679                         }
6680
6681                         if (player->s_stream_caps) {
6682                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6683                                 if (!elem_src_subtitle) {
6684                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6685                                         break;
6686                                 }
6687                         }
6688
6689                         LOGD("setting app sources properties.\n");
6690                         LOGD("location : %s\n", player->profile.uri);
6691
6692                         if (player->v_stream_caps && element) {
6693                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6694                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6695                                                                                                 "caps", player->v_stream_caps, NULL);
6696
6697                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6698                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6699                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6700                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6701
6702                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6703                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6704                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6705                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6706
6707                                 if (player->a_stream_caps && elem_src_audio) {
6708                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6709                                                                                                                         "caps", player->a_stream_caps, NULL);
6710
6711                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6712                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6713                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6714                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6715
6716                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6717                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6718                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6719                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6720                                 }
6721                         } else if (player->a_stream_caps && element) {
6722                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6723                                                                                                 "caps", player->a_stream_caps, NULL);
6724
6725                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6726                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6727                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6728                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6729
6730                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6731                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6732                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6733                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6734                         }
6735
6736                         if (player->s_stream_caps && elem_src_subtitle) {
6737                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6738                                                                                                                  "caps", player->s_stream_caps, NULL);
6739
6740                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6741                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6742                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6743                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6744
6745                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6746
6747                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6748                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6749                         }
6750
6751                         if (player->v_stream_caps && element) {
6752                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6753                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6754                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6755                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6756
6757                                 if (player->a_stream_caps && elem_src_audio) {
6758                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6759                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6760                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6761                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6762                                 }
6763                         } else if (player->a_stream_caps && element) {
6764                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6765                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6766                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6767                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6768                         }
6769
6770                         if (player->s_stream_caps && elem_src_subtitle)
6771                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6772                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6773
6774                         need_state_holder = FALSE;
6775
6776                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6777                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6778                                 LOGE("failed to commit\n");
6779                 }
6780                 break;
6781         /* appsrc */
6782         case MM_PLAYER_URI_TYPE_MEM:
6783                 {
6784                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6785
6786                         LOGD("mem src is selected\n");
6787
6788                         element = gst_element_factory_make("appsrc", "mem-source");
6789                         if (!element) {
6790                                 LOGE("failed to create appsrc element\n");
6791                                 break;
6792                         }
6793
6794                         g_object_set(element, "stream-type", stream_type, NULL);
6795                         g_object_set(element, "size", player->mem_buf.len, NULL);
6796                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6797
6798                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6799                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6800                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6801                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6802                 }
6803                 break;
6804         case MM_PLAYER_URI_TYPE_URL:
6805                 break;
6806
6807         case MM_PLAYER_URI_TYPE_TEMP:
6808                 break;
6809
6810         case MM_PLAYER_URI_TYPE_NONE:
6811         default:
6812                 break;
6813         }
6814
6815         /* check source element is OK */
6816         if (!element) {
6817                 LOGE("no source element was created.\n");
6818                 goto INIT_ERROR;
6819         }
6820
6821         /* take source element */
6822         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6823         mainbin[MMPLAYER_M_SRC].gst = element;
6824         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6825
6826         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6827                 player->streamer = __mm_player_streaming_create();
6828                 __mm_player_streaming_initialize(player->streamer);
6829         }
6830
6831         if (MMPLAYER_IS_HTTP_PD(player)) {
6832                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6833
6834                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6835                 element = gst_element_factory_make("queue2", "queue2");
6836                 if (!element) {
6837                         LOGE("failed to create http streaming buffer element\n");
6838                         goto INIT_ERROR;
6839                 }
6840
6841                 /* take it */
6842                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6843                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6844                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6845
6846                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6847
6848                 __mm_player_streaming_set_queue2(player->streamer,
6849                                 element,
6850                                 TRUE,
6851                                 player->ini.http_max_size_bytes,
6852                                 pre_buffering_time,
6853                                 1.0,
6854                                 player->ini.http_buffering_limit,
6855                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6856                                 NULL,
6857                                 0);
6858         }
6859         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6860                 if (player->v_stream_caps) {
6861                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6862                         if (!es_video_queue) {
6863                                 LOGE("create es_video_queue for es player failed\n");
6864                                 goto INIT_ERROR;
6865                         }
6866                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6867                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6868                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6869                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6870
6871                         /* Adding audio appsrc to bucket */
6872                         if (player->a_stream_caps && elem_src_audio) {
6873                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6874                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6875                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6876
6877                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6878                                 if (!es_audio_queue) {
6879                                         LOGE("create es_audio_queue for es player failed\n");
6880                                         goto INIT_ERROR;
6881                                 }
6882                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6883
6884                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6885                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6886                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6887                         }
6888                 } else if (player->a_stream_caps) {
6889                         /* Only audio stream, no video */
6890                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6891                         if (!es_audio_queue) {
6892                                 LOGE("create es_audio_queue for es player failed\n");
6893                                 goto INIT_ERROR;
6894                         }
6895                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6896                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6897                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6898                 }
6899
6900                 if (player->s_stream_caps && elem_src_subtitle) {
6901                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6902                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6903                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6904
6905                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6906                         if (!es_subtitle_queue) {
6907                                 LOGE("create es_subtitle_queue for es player failed\n");
6908                                 goto INIT_ERROR;
6909                         }
6910                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6911                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6912                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6913                 }
6914         }
6915
6916         /* create autoplugging element if src element is not a rtsp src */
6917         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6918                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6919                 element = NULL;
6920                 enum MainElementID elemId = MMPLAYER_M_NUM;
6921
6922                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6923                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6924                         elemId = MMPLAYER_M_AUTOPLUG;
6925                         element = __mmplayer_create_decodebin(player);
6926                         if (element) {
6927                                 /* default size of mq in decodebin is 2M
6928                                  * but it can cause blocking issue during seeking depends on content. */
6929                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6930                         }
6931                         need_state_holder = FALSE;
6932                 } else {
6933                         elemId = MMPLAYER_M_TYPEFIND;
6934                         element = gst_element_factory_make("typefind", "typefinder");
6935                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6936                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6937                 }
6938
6939
6940                 /* check autoplug element is OK */
6941                 if (!element) {
6942                         LOGE("can not create element(%d)\n", elemId);
6943                         goto INIT_ERROR;
6944                 }
6945
6946                 mainbin[elemId].id = elemId;
6947                 mainbin[elemId].gst = element;
6948
6949                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6950         }
6951
6952         /* add elements to pipeline */
6953         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6954                 LOGE("Failed to add elements to pipeline\n");
6955                 goto INIT_ERROR;
6956         }
6957
6958
6959         /* linking elements in the bucket by added order. */
6960         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6961                 LOGE("Failed to link some elements\n");
6962                 goto INIT_ERROR;
6963         }
6964
6965
6966         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6967         if (need_state_holder) {
6968                 /* create */
6969                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6970                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6971
6972                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6973                         LOGE("fakesink element could not be created\n");
6974                         goto INIT_ERROR;
6975                 }
6976                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6977
6978                 /* take ownership of fakesink. we are reusing it */
6979                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6980
6981                 /* add */
6982                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6983                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6984                         LOGE("failed to add fakesink to bin\n");
6985                         goto INIT_ERROR;
6986                 }
6987         }
6988
6989         /* now we have completed mainbin. take it */
6990         player->pipeline->mainbin = mainbin;
6991
6992         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6993                 GstPad *srcpad = NULL;
6994
6995                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6996                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6997                         if (srcpad) {
6998                                 __mmplayer_gst_create_decoder(player,
6999                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
7000                                                                                                 srcpad,
7001                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
7002                                                                                                 "video_decodebin");
7003
7004                                 gst_object_unref(GST_OBJECT(srcpad));
7005                                 srcpad = NULL;
7006                         }
7007                 }
7008
7009                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
7010                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
7011                         if (srcpad) {
7012                                 __mmplayer_gst_create_decoder(player,
7013                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
7014                                                                                                 srcpad,
7015                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
7016                                                                                                 "audio_decodebin");
7017
7018                                 gst_object_unref(GST_OBJECT(srcpad));
7019                                 srcpad = NULL;
7020                         } // else error
7021                 } //  else error
7022
7023                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
7024                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
7025         }
7026
7027         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
7028         if (__mmplayer_check_subtitle(player)) {
7029                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
7030                         LOGE("fail to create text pipeline");
7031         }
7032
7033         /* connect bus callback */
7034         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7035         if (!bus) {
7036                 LOGE("cannot get bus from pipeline.\n");
7037                 goto INIT_ERROR;
7038         }
7039
7040         /* set sync handler to get tag synchronously */
7041         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
7042
7043         /* finished */
7044         gst_object_unref(GST_OBJECT(bus));
7045         g_list_free(element_bucket);
7046
7047         /* create gst bus_msb_cb thread */
7048         g_mutex_init(&player->bus_msg_thread_mutex);
7049         g_cond_init(&player->bus_msg_thread_cond);
7050         player->bus_msg_thread_exit = FALSE;
7051         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
7052         player->bus_msg_thread =
7053                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
7054         if (!player->bus_msg_thread) {
7055                 LOGE("failed to create gst BUS msg thread");
7056                 g_mutex_clear(&player->bus_msg_thread_mutex);
7057                 g_cond_clear(&player->bus_msg_thread_cond);
7058                 goto INIT_ERROR;
7059         }
7060
7061         MMPLAYER_FLEAVE();
7062
7063         return MM_ERROR_NONE;
7064
7065 INIT_ERROR:
7066         __mmplayer_gst_destroy_pipeline(player);
7067         g_list_free(element_bucket);
7068
7069         if (mainbin) {
7070                 /* release element which are not added to bin */
7071                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
7072                         /* NOTE : skip pipeline */
7073                         if (mainbin[i].gst) {
7074                                 GstObject* parent = NULL;
7075                                 parent = gst_element_get_parent(mainbin[i].gst);
7076
7077                                 if (!parent) {
7078                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
7079                                         mainbin[i].gst = NULL;
7080                                 } else
7081                                         gst_object_unref(GST_OBJECT(parent));
7082                         }
7083                 }
7084
7085                 /* release pipeline with it's childs */
7086                 if (mainbin[MMPLAYER_M_PIPE].gst)
7087                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7088
7089                 MMPLAYER_FREEIF(mainbin);
7090         }
7091
7092         MMPLAYER_FREEIF(player->pipeline);
7093         return MM_ERROR_PLAYER_INTERNAL;
7094 }
7095
7096 static void
7097 __mmplayer_reset_gapless_state(mm_player_t* player)
7098 {
7099         MMPLAYER_FENTER();
7100         MMPLAYER_RETURN_IF_FAIL(player
7101                 && player->pipeline
7102                 && player->pipeline->audiobin
7103                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
7104
7105         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
7106
7107         MMPLAYER_FLEAVE();
7108         return;
7109 }
7110
7111 static int
7112 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
7113 {
7114         gint timeout = 0;
7115         int ret = MM_ERROR_NONE;
7116
7117         MMPLAYER_FENTER();
7118
7119         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
7120
7121         /* cleanup stuffs */
7122         MMPLAYER_FREEIF(player->type);
7123         player->have_dynamic_pad = FALSE;
7124         player->no_more_pad = FALSE;
7125         player->num_dynamic_pad = 0;
7126         player->demux_pad_index = 0;
7127         player->use_deinterleave = FALSE;
7128         player->max_audio_channels = 0;
7129         player->video_share_api_delta = 0;
7130         player->video_share_clock_delta = 0;
7131         player->video_hub_download_mode = 0;
7132
7133         MMPLAYER_SUBTITLE_INFO_LOCK(player);
7134         player->subtitle_language_list = NULL;
7135         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7136
7137         __mmplayer_reset_gapless_state(player);
7138
7139         if (player->streamer) {
7140                 __mm_player_streaming_deinitialize(player->streamer);
7141                 __mm_player_streaming_destroy(player->streamer);
7142                 player->streamer = NULL;
7143         }
7144
7145         /* cleanup unlinked mime type */
7146         MMPLAYER_FREEIF(player->unlinked_audio_mime);
7147         MMPLAYER_FREEIF(player->unlinked_video_mime);
7148         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7149
7150         /* cleanup running stuffs */
7151         __mmplayer_cancel_eos_timer(player);
7152
7153         /* cleanup gst stuffs */
7154         if (player->pipeline) {
7155                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7156                 GstTagList* tag_list = player->pipeline->tag_list;
7157
7158                 /* first we need to disconnect all signal hander */
7159                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7160
7161                 if (mainbin) {
7162                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7163                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7164                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7165                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7166                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7167                         gst_object_unref(bus);
7168
7169                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7170                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7171                         if (ret != MM_ERROR_NONE) {
7172                                 LOGE("fail to change state to NULL\n");
7173                                 return MM_ERROR_PLAYER_INTERNAL;
7174                         }
7175
7176                         LOGW("succeeded in chaning state to NULL\n");
7177
7178                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7179
7180                         /* free fakesink */
7181                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7182                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7183
7184                         /* free avsysaudiosink
7185                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7186                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7187                         */
7188                         MMPLAYER_FREEIF(audiobin);
7189                         MMPLAYER_FREEIF(videobin);
7190                         MMPLAYER_FREEIF(textbin);
7191                         MMPLAYER_FREEIF(mainbin);
7192                 }
7193
7194                 if (tag_list)
7195                         gst_tag_list_free(tag_list);
7196
7197                 MMPLAYER_FREEIF(player->pipeline);
7198         }
7199         MMPLAYER_FREEIF(player->album_art);
7200
7201         if (player->v_stream_caps) {
7202                 gst_caps_unref(player->v_stream_caps);
7203                 player->v_stream_caps = NULL;
7204         }
7205         if (player->a_stream_caps) {
7206                 gst_caps_unref(player->a_stream_caps);
7207                 player->a_stream_caps = NULL;
7208         }
7209
7210         if (player->s_stream_caps) {
7211                 gst_caps_unref(player->s_stream_caps);
7212                 player->s_stream_caps = NULL;
7213         }
7214         _mmplayer_track_destroy(player);
7215
7216         if (player->sink_elements)
7217                 g_list_free(player->sink_elements);
7218         player->sink_elements = NULL;
7219
7220         if (player->bufmgr) {
7221                 tbm_bufmgr_deinit(player->bufmgr);
7222                 player->bufmgr = NULL;
7223         }
7224
7225         LOGW("finished destroy pipeline\n");
7226
7227         MMPLAYER_FLEAVE();
7228
7229         return ret;
7230 }
7231
7232 static int __gst_realize(mm_player_t* player)
7233 {
7234         gint timeout = 0;
7235         int ret = MM_ERROR_NONE;
7236
7237         MMPLAYER_FENTER();
7238
7239         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7240
7241         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7242
7243         ret = __mmplayer_gst_create_pipeline(player);
7244         if (ret) {
7245                 LOGE("failed to create pipeline\n");
7246                 return ret;
7247         }
7248
7249         /* set pipeline state to READY */
7250         /* NOTE : state change to READY must be performed sync. */
7251         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7252         ret = __mmplayer_gst_set_state(player,
7253                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7254
7255         if (ret != MM_ERROR_NONE) {
7256                 /* return error if failed to set state */
7257                 LOGE("failed to set READY state");
7258                 return ret;
7259         }
7260
7261         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7262
7263         /* create dot before error-return. for debugging */
7264         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7265
7266         MMPLAYER_FLEAVE();
7267
7268         return ret;
7269 }
7270
7271 static int __gst_unrealize(mm_player_t* player)
7272 {
7273         int ret = MM_ERROR_NONE;
7274
7275         MMPLAYER_FENTER();
7276
7277         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278
7279         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7280         MMPLAYER_PRINT_STATE(player);
7281
7282         /* release miscellaneous information */
7283         __mmplayer_release_misc(player);
7284
7285         /* destroy pipeline */
7286         ret = __mmplayer_gst_destroy_pipeline(player);
7287         if (ret != MM_ERROR_NONE) {
7288                 LOGE("failed to destory pipeline\n");
7289                 return ret;
7290         }
7291
7292         /* release miscellaneous information.
7293            these info needs to be released after pipeline is destroyed. */
7294         __mmplayer_release_misc_post(player);
7295
7296         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7297
7298         MMPLAYER_FLEAVE();
7299
7300         return ret;
7301 }
7302
7303 static int __gst_pending_seek(mm_player_t* player)
7304 {
7305         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7306         int ret = MM_ERROR_NONE;
7307
7308         MMPLAYER_FENTER();
7309
7310         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7311
7312         if (!player->pending_seek.is_pending) {
7313                 LOGD("pending seek is not reserved. nothing to do.\n");
7314                 return ret;
7315         }
7316
7317         /* check player state if player could pending seek or not. */
7318         current_state = MMPLAYER_CURRENT_STATE(player);
7319
7320         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7321                 LOGW("try to pending seek in %s state, try next time. \n",
7322                         MMPLAYER_STATE_GET_NAME(current_state));
7323                 return ret;
7324         }
7325
7326         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7327
7328         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7329
7330         if (MM_ERROR_NONE != ret)
7331                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7332
7333         player->pending_seek.is_pending = FALSE;
7334
7335         MMPLAYER_FLEAVE();
7336
7337         return ret;
7338 }
7339
7340 static int __gst_start(mm_player_t* player)
7341 {
7342         gboolean sound_extraction = 0;
7343         int ret = MM_ERROR_NONE;
7344         gboolean async = FALSE;
7345
7346         MMPLAYER_FENTER();
7347
7348         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7349
7350         /* get sound_extraction property */
7351         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7352
7353         /* NOTE : if SetPosition was called before Start. do it now */
7354         /* streaming doesn't support it. so it should be always sync */
7355         /* !!create one more api to check if there is pending seek rather than checking variables */
7356         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7357                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7358                 ret = __gst_pause(player, FALSE);
7359                 if (ret != MM_ERROR_NONE) {
7360                         LOGE("failed to set state to PAUSED for pending seek\n");
7361                         return ret;
7362                 }
7363
7364                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7365
7366                 if (sound_extraction) {
7367                         LOGD("setting pcm extraction\n");
7368
7369                         ret = __mmplayer_set_pcm_extraction(player);
7370                         if (MM_ERROR_NONE != ret) {
7371                                 LOGW("failed to set pcm extraction\n");
7372                                 return ret;
7373                         }
7374                 } else {
7375                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7376                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7377                 }
7378         }
7379
7380         LOGD("current state before doing transition");
7381         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7382         MMPLAYER_PRINT_STATE(player);
7383
7384         /* set pipeline state to PLAYING  */
7385         if (player->es_player_push_mode)
7386                 async = TRUE;
7387         /* set pipeline state to PLAYING  */
7388         ret = __mmplayer_gst_set_state(player,
7389                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7390
7391         if (ret == MM_ERROR_NONE) {
7392                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7393         } else {
7394                 LOGE("failed to set state to PLAYING");
7395                 return ret;
7396         }
7397
7398         /* generating debug info before returning error */
7399         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7400
7401         MMPLAYER_FLEAVE();
7402
7403         return ret;
7404 }
7405
7406 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7407 {
7408         MMPLAYER_FENTER();
7409
7410         MMPLAYER_RETURN_IF_FAIL(player
7411                 && player->pipeline
7412                 && player->pipeline->audiobin
7413                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7414
7415         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7416
7417         usleep(time);
7418
7419         MMPLAYER_FLEAVE();
7420 }
7421
7422 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7423 {
7424         MMPLAYER_FENTER();
7425
7426         MMPLAYER_RETURN_IF_FAIL(player
7427                 && player->pipeline
7428                 && player->pipeline->audiobin
7429                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7430
7431         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7432
7433         MMPLAYER_FLEAVE();
7434 }
7435
7436 static int __gst_stop(mm_player_t* player)
7437 {
7438         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7439         MMHandleType attrs = 0;
7440         gboolean fadedown = FALSE;
7441         gboolean rewind = FALSE;
7442         gint timeout = 0;
7443         int ret = MM_ERROR_NONE;
7444         gboolean async = FALSE;
7445
7446         MMPLAYER_FENTER();
7447
7448         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7449         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7450
7451         LOGD("current state before doing transition");
7452         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7453         MMPLAYER_PRINT_STATE(player);
7454
7455         attrs = MMPLAYER_GET_ATTRS(player);
7456         if (!attrs) {
7457                 LOGE("cannot get content attribute\n");
7458                 return MM_ERROR_PLAYER_INTERNAL;
7459         }
7460
7461         mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7462
7463         /* enable fadedown */
7464         if (fadedown || player->sound_focus.by_asm_cb)
7465                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7466
7467         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7468         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7469
7470         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7471                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7472                 rewind = TRUE;
7473
7474         if (player->es_player_push_mode)
7475                 async = TRUE;
7476         /* set gst state */
7477         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7478
7479         /* disable fadeout */
7480         if (fadedown || player->sound_focus.by_asm_cb)
7481                 __mmplayer_undo_sound_fadedown(player);
7482
7483         /* return if set_state has failed */
7484         if (ret != MM_ERROR_NONE) {
7485                 LOGE("failed to set state.\n");
7486                 return ret;
7487         }
7488
7489         /* rewind */
7490         if (rewind) {
7491                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7492                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7493                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7494                         LOGW("failed to rewind\n");
7495                         ret = MM_ERROR_PLAYER_SEEK;
7496                 }
7497         }
7498
7499         /* initialize */
7500         player->sent_bos = FALSE;
7501
7502         if (player->es_player_push_mode) //for cloudgame
7503                 timeout = 0;
7504
7505         /* wait for seek to complete */
7506         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7507         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7508                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7509         } else {
7510                 LOGE("fail to stop player.\n");
7511                 ret = MM_ERROR_PLAYER_INTERNAL;
7512                 __mmplayer_dump_pipeline_state(player);
7513         }
7514
7515         /* generate dot file if enabled */
7516         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7517
7518         MMPLAYER_FLEAVE();
7519
7520         return ret;
7521 }
7522
7523 int __gst_pause(mm_player_t* player, gboolean async)
7524 {
7525         int ret = MM_ERROR_NONE;
7526
7527         MMPLAYER_FENTER();
7528
7529         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7530         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7531
7532         LOGD("current state before doing transition");
7533         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7534         MMPLAYER_PRINT_STATE(player);
7535
7536         /* set pipeline status to PAUSED */
7537         ret = __mmplayer_gst_set_state(player,
7538                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7539
7540         if (FALSE == async) {
7541                 if (ret != MM_ERROR_NONE) {
7542                         GstMessage *msg = NULL;
7543                         GTimer *timer = NULL;
7544                         gdouble MAX_TIMEOUT_SEC = 3;
7545
7546                         LOGE("failed to set state to PAUSED");
7547
7548                         if (player->msg_posted) {
7549                                 LOGE("error msg is already posted.");
7550                                 return ret;
7551                         }
7552
7553                         timer = g_timer_new();
7554                         g_timer_start(timer);
7555
7556                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7557
7558                         do {
7559                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7560                                 if (msg) {
7561                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7562                                                 GError *error = NULL;
7563
7564                                                 /* parse error code */
7565                                                 gst_message_parse_error(msg, &error, NULL);
7566
7567                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7568                                                         /* Note : the streaming error from the streaming source is handled
7569                                                          *   using __mmplayer_handle_streaming_error.
7570                                                          */
7571                                                         __mmplayer_handle_streaming_error(player, msg);
7572
7573                                                 } else if (error) {
7574                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7575
7576                                                         if (error->domain == GST_STREAM_ERROR)
7577                                                                 ret = __gst_handle_stream_error(player, error, msg);
7578                                                         else if (error->domain == GST_RESOURCE_ERROR)
7579                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7580                                                         else if (error->domain == GST_LIBRARY_ERROR)
7581                                                                 ret = __gst_handle_library_error(player, error->code);
7582                                                         else if (error->domain == GST_CORE_ERROR)
7583                                                                 ret = __gst_handle_core_error(player, error->code);
7584
7585                                                         g_error_free(error);
7586                                                 }
7587                                                 player->msg_posted = TRUE;
7588                                         }
7589                                         gst_message_unref(msg);
7590                                 }
7591                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7592                         /* clean */
7593                         gst_object_unref(bus);
7594                         g_timer_stop(timer);
7595                         g_timer_destroy(timer);
7596
7597                         return ret;
7598
7599                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7600                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7601
7602                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7603
7604                 } else if (ret == MM_ERROR_NONE) {
7605
7606                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7607                 }
7608         }
7609
7610         /* generate dot file before returning error */
7611         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7612
7613         MMPLAYER_FLEAVE();
7614
7615         return ret;
7616 }
7617
7618 int __gst_resume(mm_player_t* player, gboolean async)
7619 {
7620         int ret = MM_ERROR_NONE;
7621         gint timeout = 0;
7622
7623         MMPLAYER_FENTER();
7624
7625         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7626                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7627
7628         LOGD("current state before doing transition");
7629         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7630         MMPLAYER_PRINT_STATE(player);
7631
7632         /* generate dot file before returning error */
7633         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7634
7635         if (async)
7636                 LOGD("do async state transition to PLAYING.\n");
7637
7638         /* set pipeline state to PLAYING */
7639         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7640
7641         ret = __mmplayer_gst_set_state(player,
7642                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7643         if (ret != MM_ERROR_NONE) {
7644                 LOGE("failed to set state to PLAYING\n");
7645                 return ret;
7646         } else {
7647                 if (async == FALSE) {
7648                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7649                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7650                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7651                 }
7652         }
7653
7654         /* generate dot file before returning error */
7655         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7656
7657         MMPLAYER_FLEAVE();
7658
7659         return ret;
7660 }
7661
7662 static int
7663 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7664 {
7665         unsigned long dur_msec = 0;
7666         gint64 dur_nsec = 0;
7667         gint64 pos_nsec = 0;
7668         gboolean ret = TRUE;
7669         gboolean accurated = FALSE;
7670         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7671
7672         MMPLAYER_FENTER();
7673         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7674         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7675
7676         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7677                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7678                 goto PENDING;
7679
7680         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7681                 /* check duration */
7682                 /* NOTE : duration cannot be zero except live streaming.
7683                  *              Since some element could have some timing problemn with quering duration, try again.
7684                  */
7685                 if (!player->duration) {
7686                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7687                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7688                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7689                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7690                                         player->pending_seek.is_pending = TRUE;
7691                                         player->pending_seek.format = format;
7692                                         player->pending_seek.pos = position;
7693                                         player->doing_seek = FALSE;
7694                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7695                                         return MM_ERROR_NONE;
7696                                 } else {
7697                                         goto SEEK_ERROR;
7698                                 }
7699                         }
7700                         player->duration = dur_nsec;
7701                 }
7702
7703                 if (player->duration) {
7704                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7705                 } else {
7706                         LOGE("could not get the duration. fail to seek.\n");
7707                         goto SEEK_ERROR;
7708                 }
7709         }
7710         LOGD("playback rate: %f\n", player->playback_rate);
7711
7712         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7713         if (accurated)
7714                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7715         else
7716                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7717
7718         /* do seek */
7719         switch (format) {
7720         case MM_PLAYER_POS_FORMAT_TIME:
7721         {
7722                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7723                         GstQuery *query = NULL;
7724                         gboolean seekable = FALSE;
7725
7726                         /* check position is valid or not */
7727                         if (position > dur_msec)
7728                                 goto INVALID_ARGS;
7729
7730                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7731                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7732                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7733                                 gst_query_unref(query);
7734
7735                                 if (!seekable) {
7736                                         LOGW("non-seekable content");
7737                                         player->doing_seek = FALSE;
7738                                         return MM_ERROR_PLAYER_NO_OP;
7739                                 }
7740                         } else {
7741                                 LOGW("failed to get seeking query");
7742                                 gst_query_unref(query); /* keep seeking operation */
7743                         }
7744
7745                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7746
7747                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7748                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7749                            This causes problem is position calculation during normal pause resume scenarios also.
7750                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7751                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7752                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7753                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7754                                         LOGW("getting current position failed in seek\n");
7755
7756                                 player->last_position = pos_nsec;
7757                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7758                         }
7759
7760                         if (player->doing_seek) {
7761                                 LOGD("not completed seek");
7762                                 return MM_ERROR_PLAYER_DOING_SEEK;
7763                         }
7764                 }
7765
7766                 if (!internal_called)
7767                         player->doing_seek = TRUE;
7768
7769                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7770
7771                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7772                         gint64 cur_time = 0;
7773
7774                         /* get current position */
7775                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7776
7777                         /* flush */
7778                         GstEvent *event = gst_event_new_seek(1.0,
7779                                                         GST_FORMAT_TIME,
7780                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7781                                                         GST_SEEK_TYPE_SET, cur_time,
7782                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7783                         if (event)
7784                                 __gst_send_event_to_sink(player, event);
7785
7786                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7787                                 __gst_pause(player, FALSE);
7788                 }
7789
7790                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7791                         that's why set position through property. */
7792                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7793                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7794                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7795                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7796
7797                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7798                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7799                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7800                         player->doing_seek = FALSE;
7801                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7802                 } else {
7803                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7804                                                         GST_FORMAT_TIME, seek_flags,
7805                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7806                 }
7807
7808                 if (!ret) {
7809                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7810                         goto SEEK_ERROR;
7811                 }
7812         }
7813         break;
7814
7815         case MM_PLAYER_POS_FORMAT_PERCENT:
7816         {
7817                 LOGD("seeking to(%lu)%% \n", position);
7818
7819                 if (player->doing_seek) {
7820                         LOGD("not completed seek");
7821                         return MM_ERROR_PLAYER_DOING_SEEK;
7822                 }
7823
7824                 if (!internal_called)
7825                         player->doing_seek = TRUE;
7826
7827                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7828                 pos_nsec = (gint64)((position * player->duration) / 100);
7829                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7830                                                 GST_FORMAT_TIME, seek_flags,
7831                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7832                 if (!ret) {
7833                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7834                         goto SEEK_ERROR;
7835                 }
7836         }
7837         break;
7838
7839         default:
7840                 goto INVALID_ARGS;
7841         }
7842
7843         /* NOTE : store last seeking point to overcome some bad operation
7844           *     (returning zero when getting current position) of some elements
7845           */
7846         player->last_position = pos_nsec;
7847
7848         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7849         if (player->playback_rate > 1.0)
7850                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7851
7852         MMPLAYER_FLEAVE();
7853         return MM_ERROR_NONE;
7854
7855 PENDING:
7856         player->pending_seek.is_pending = TRUE;
7857         player->pending_seek.format = format;
7858         player->pending_seek.pos = position;
7859
7860         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7861                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7862
7863         return MM_ERROR_NONE;
7864
7865 INVALID_ARGS:
7866         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7867         return MM_ERROR_INVALID_ARGUMENT;
7868
7869 SEEK_ERROR:
7870         player->doing_seek = FALSE;
7871         return MM_ERROR_PLAYER_SEEK;
7872 }
7873
7874 #define TRICKPLAY_OFFSET GST_MSECOND
7875
7876 static int
7877 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7878 {
7879         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7880         gint64 pos_msec = 0;
7881         gboolean ret = TRUE;
7882
7883         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7884                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7885
7886         current_state = MMPLAYER_CURRENT_STATE(player);
7887
7888         /* NOTE : query position except paused state to overcome some bad operation
7889          * please refer to below comments in details
7890          */
7891         if (current_state != MM_PLAYER_STATE_PAUSED)
7892                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7893
7894         /* NOTE : get last point to overcome some bad operation of some elements
7895          *(returning zero when getting current position in paused state
7896          * and when failed to get postion during seeking
7897          */
7898         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7899                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7900
7901                 if (player->playback_rate < 0.0)
7902                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7903                 else
7904                         pos_msec = player->last_position;
7905
7906                 if (!ret)
7907                         pos_msec = player->last_position;
7908                 else
7909                         player->last_position = pos_msec;
7910
7911                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7912
7913         } else {
7914                 if (player->duration > 0 && pos_msec > player->duration)
7915                         pos_msec = player->duration;
7916
7917                 if (player->sound_focus.keep_last_pos) {
7918                         LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7919                         pos_msec = player->last_position;
7920                 } else {
7921                         player->last_position = pos_msec;
7922                 }
7923         }
7924
7925         switch (format) {
7926         case MM_PLAYER_POS_FORMAT_TIME:
7927                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7928                 break;
7929
7930         case MM_PLAYER_POS_FORMAT_PERCENT:
7931         {
7932                 if (player->duration <= 0) {
7933                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7934                         *position = 0;
7935                 } else {
7936                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7937                         *position = pos_msec * 100 / player->duration;
7938                 }
7939                 break;
7940         }
7941         default:
7942                 return MM_ERROR_PLAYER_INTERNAL;
7943         }
7944
7945         return MM_ERROR_NONE;
7946 }
7947
7948
7949 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7950 {
7951 #define STREAMING_IS_FINISHED   0
7952 #define BUFFERING_MAX_PER       100
7953 #define DEFAULT_PER_VALUE       -1
7954 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7955
7956         MMPlayerGstElement *mainbin = NULL;
7957         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7958         gint64 buffered_total = 0;
7959         unsigned long position = 0;
7960         gint buffered_sec = -1;
7961         GstBufferingMode mode = GST_BUFFERING_STREAM;
7962         gint64 content_size_time = player->duration;
7963         guint64 content_size_bytes = player->http_content_size;
7964
7965         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7966                                                 player->pipeline &&
7967                                                 player->pipeline->mainbin,
7968                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7969
7970         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7971
7972         *start_pos = 0;
7973         *stop_pos = 0;
7974
7975         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7976                 /* and rtsp is not ready yet. */
7977                 LOGW("it's only used for http streaming case.\n");
7978                 return MM_ERROR_PLAYER_NO_OP;
7979         }
7980
7981         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7982                 LOGW("Time format is not supported yet.\n");
7983                 return MM_ERROR_INVALID_ARGUMENT;
7984         }
7985
7986         if (content_size_time <= 0 || content_size_bytes <= 0) {
7987                 LOGW("there is no content size.");
7988                 return MM_ERROR_NONE;
7989         }
7990
7991         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7992                 LOGW("fail to get current position.");
7993                 return MM_ERROR_NONE;
7994         }
7995
7996         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7997                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7998
7999         mainbin = player->pipeline->mainbin;
8000         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
8001
8002         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
8003                 GstQuery *query = NULL;
8004                 gint byte_in_rate = 0, byte_out_rate = 0;
8005                 gint64 estimated_total = 0;
8006
8007                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
8008                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
8009                         LOGW("fail to get buffering query from queue2");
8010                         if (query)
8011                                 gst_query_unref(query);
8012                         return MM_ERROR_NONE;
8013                 }
8014
8015                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
8016                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
8017
8018                 if (mode == GST_BUFFERING_STREAM) {
8019                         /* using only queue in case of push mode(ts / mp3) */
8020                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
8021                                 GST_FORMAT_BYTES, &buffered_total)) {
8022                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
8023                                 stop_per = 100 * buffered_total / content_size_bytes;
8024                         }
8025                 } else {
8026                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
8027                         guint idx = 0;
8028                         guint num_of_ranges = 0;
8029                         gint64 start_byte = 0, stop_byte = 0;
8030
8031                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
8032                         if (estimated_total != STREAMING_IS_FINISHED) {
8033                                 /* buffered size info from queue2 */
8034                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
8035                                 for (idx = 0; idx < num_of_ranges; idx++) {
8036                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
8037                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
8038
8039                                         buffered_total += (stop_byte - start_byte);
8040                                 }
8041                         } else
8042                                 stop_per = BUFFERING_MAX_PER;
8043                 }
8044                 gst_query_unref(query);
8045         }
8046
8047         if (stop_per == DEFAULT_PER_VALUE) {
8048                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
8049                 if (dur_sec > 0) {
8050                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
8051
8052                         /* buffered size info from multiqueue */
8053                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
8054                                 guint curr_size_bytes = 0;
8055                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
8056                                         "curr-size-bytes", &curr_size_bytes, NULL);
8057                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
8058                                 buffered_total += curr_size_bytes;
8059                         }
8060
8061                         if (avg_byterate > 0)
8062                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
8063                         else if (player->total_maximum_bitrate > 0)
8064                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
8065                         else if (player->total_bitrate > 0)
8066                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
8067
8068                         if (buffered_sec >= 0)
8069                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
8070                 }
8071         }
8072
8073         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
8074         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
8075
8076         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
8077                 buffered_total, buffered_sec, *start_pos, *stop_pos);
8078
8079         return MM_ERROR_NONE;
8080 }
8081
8082 static int
8083 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
8084 {
8085         MMPLAYER_FENTER();
8086
8087         if (!player) {
8088                 LOGW("set_message_callback is called with invalid player handle\n");
8089                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
8090         }
8091
8092         player->msg_cb = callback;
8093         player->msg_cb_param = user_param;
8094
8095         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
8096
8097         MMPLAYER_FLEAVE();
8098
8099         return MM_ERROR_NONE;
8100 }
8101
8102 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
8103 {
8104         int ret = MM_ERROR_PLAYER_INVALID_URI;
8105         char *path = NULL;
8106
8107         MMPLAYER_FENTER();
8108
8109         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
8110         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
8111         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
8112
8113         memset(data, 0, sizeof(MMPlayerParseProfile));
8114
8115         if ((path = strstr(uri, "es_buff://"))) {
8116                 if (strlen(path)) {
8117                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8118                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
8119                         ret = MM_ERROR_NONE;
8120                 }
8121         } else if ((path = strstr(uri, "rtsp://"))) {
8122                 if (strlen(path)) {
8123                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8124                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8125                         ret = MM_ERROR_NONE;
8126                 }
8127         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
8128                 if (strlen(path)) {
8129                         gchar *tmp = NULL;
8130                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8131                         tmp = g_ascii_strdown(uri, strlen(uri));
8132
8133                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
8134                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
8135                         else
8136                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8137
8138                         ret = MM_ERROR_NONE;
8139                         g_free(tmp);
8140                 }
8141         } else if ((path = strstr(uri, "rtspu://"))) {
8142                 if (strlen(path)) {
8143                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8144                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8145                         ret = MM_ERROR_NONE;
8146                 }
8147         } else if ((path = strstr(uri, "rtspr://"))) {
8148                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
8149                 char *separater = strstr(path, "*");
8150
8151                 if (separater) {
8152                         int urgent_len = 0;
8153                         char *urgent = separater + strlen("*");
8154
8155                         if ((urgent_len = strlen(urgent))) {
8156                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
8157                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
8158                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8159                                 ret = MM_ERROR_NONE;
8160                         }
8161                 }
8162         } else if ((path = strstr(uri, "mms://"))) {
8163                 if (strlen(path)) {
8164                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8165                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
8166                         ret = MM_ERROR_NONE;
8167                 }
8168         } else if ((path = strstr(uri, "mem://"))) {
8169                 if (strlen(path)) {
8170                         int mem_size = 0;
8171                         char *buffer = NULL;
8172                         char *seperator = strchr(path, ',');
8173                         char ext[100] = {0,}, size[100] = {0,};
8174
8175                         if (seperator) {
8176                                 if ((buffer = strstr(path, "ext="))) {
8177                                         buffer += strlen("ext=");
8178
8179                                         if (strlen(buffer)) {
8180                                                 strncpy(ext, buffer, 99);
8181
8182                                                 if ((seperator = strchr(ext, ','))
8183                                                         || (seperator = strchr(ext, ' '))
8184                                                         || (seperator = strchr(ext, '\0'))) {
8185                                                         seperator[0] = '\0';
8186                                                 }
8187                                         }
8188                                 }
8189
8190                                 if ((buffer = strstr(path, "size="))) {
8191                                         buffer += strlen("size=");
8192
8193                                         if (strlen(buffer) > 0) {
8194                                                 strncpy(size, buffer, 99);
8195
8196                                                 if ((seperator = strchr(size, ','))
8197                                                         || (seperator = strchr(size, ' '))
8198                                                         || (seperator = strchr(size, '\0'))) {
8199                                                         seperator[0] = '\0';
8200                                                 }
8201
8202                                                 mem_size = atoi(size);
8203                                         }
8204                                 }
8205                         }
8206
8207                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8208                         if (mem_size && param) {
8209                                 if (data->mem)
8210                                         free(data->mem);
8211
8212                                 data->mem = malloc(mem_size);
8213
8214                                 if (data->mem) {
8215                                         memcpy(data->mem, param, mem_size);
8216                                         data->mem_size = mem_size;
8217                                 } else {
8218                                         LOGE("failed to alloc mem %d", mem_size);
8219                                 }
8220
8221                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8222                                 ret = MM_ERROR_NONE;
8223                         }
8224                 }
8225         } else {
8226                 gchar *location = NULL;
8227                 GError *err = NULL;
8228
8229                 if ((path = strstr(uri, "file://"))) {
8230
8231                         location = g_filename_from_uri(uri, NULL, &err);
8232
8233                         if (!location || (err != NULL)) {
8234                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8235                                  (err != NULL) ? err->message : "unknown error");
8236
8237                           if (err) g_error_free(err);
8238                           if (location) g_free(location);
8239
8240                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8241                           goto exit;
8242                         }
8243
8244                         LOGD("path from uri: %s", location);
8245                 }
8246
8247                 path = (location != NULL) ? (location) : ((char*)uri);
8248                 int file_stat = MM_ERROR_NONE;
8249
8250                 file_stat = util_exist_file_path(path);
8251
8252                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8253                 if (file_stat == MM_ERROR_NONE) {
8254                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8255
8256                         if (util_is_sdp_file(path)) {
8257                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8258                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8259                         } else {
8260                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8261                         }
8262                         ret = MM_ERROR_NONE;
8263                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8264                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8265                 } else {
8266                         LOGE("invalid uri, could not play..\n");
8267                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8268                 }
8269
8270                 if (location) g_free(location);
8271         }
8272
8273 exit:
8274         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8275                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8276         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8277                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8278
8279         /* dump parse result */
8280         SECURE_LOGW("incomming uri : %s\n", uri);
8281         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8282                 data->uri_type, data->mem, data->mem_size, data->urgent);
8283
8284         MMPLAYER_FLEAVE();
8285
8286         return ret;
8287 }
8288
8289 gboolean _asm_postmsg(gpointer *data)
8290 {
8291         mm_player_t* player = (mm_player_t*)data;
8292         MMMessageParamType msg = {0, };
8293
8294         MMPLAYER_FENTER();
8295         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8296         LOGW("get notified");
8297
8298         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8299                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8300                 LOGW("dispatched");
8301                 return FALSE;
8302         }
8303
8304
8305         msg.union_type = MM_MSG_UNION_CODE;
8306         msg.code = player->sound_focus.focus_changed_msg;
8307
8308         MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8309         player->resume_event_id = 0;
8310
8311         LOGW("dispatched");
8312         return FALSE;
8313 }
8314
8315 gboolean _asm_lazy_pause(gpointer *data)
8316 {
8317         mm_player_t* player = (mm_player_t*)data;
8318         int ret = MM_ERROR_NONE;
8319
8320         MMPLAYER_FENTER();
8321
8322         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8323
8324         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8325                 LOGD("Ready to proceed lazy pause\n");
8326                 ret = _mmplayer_pause((MMHandleType)player);
8327                 if (MM_ERROR_NONE != ret)
8328                         LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8329         } else
8330                 LOGD("Invalid state to proceed lazy pause\n");
8331
8332         /* unset mute */
8333         if (player->pipeline && player->pipeline->audiobin)
8334                 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8335
8336         player->sound_focus.by_asm_cb = FALSE; //should be reset here
8337
8338         MMPLAYER_FLEAVE();
8339
8340         return FALSE;
8341 }
8342
8343 gboolean
8344 __mmplayer_can_do_interrupt(mm_player_t *player)
8345 {
8346         if (!player || !player->pipeline || !player->attrs) {
8347                 LOGW("not initialized");
8348                 goto FAILED;
8349         }
8350
8351         if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8352                 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8353                 goto FAILED;
8354         }
8355
8356         /* check if seeking */
8357         if (player->doing_seek) {
8358                 MMMessageParamType msg_param;
8359                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8360                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8361                 player->doing_seek = FALSE;
8362                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8363                 goto FAILED;
8364         }
8365
8366         /* check other thread */
8367         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8368                 LOGW("locked already, cmd state : %d", player->cmd);
8369
8370                 /* check application command */
8371                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8372                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8373
8374                         /* lock will be released at mrp_resource_release_cb() */
8375                         MMPLAYER_CMD_LOCK(player);
8376                         goto INTERRUPT;
8377                 }
8378                 LOGW("nothing to do");
8379                 goto FAILED;
8380         } else {
8381                 LOGW("can interrupt immediately");
8382                 goto INTERRUPT;
8383         }
8384
8385 FAILED:    /* with CMD UNLOCKED */
8386         return FALSE;
8387
8388 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8389         return TRUE;
8390 }
8391
8392 static int
8393 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8394                 void *user_data)
8395 {
8396         mm_player_t *player = NULL;
8397
8398         MMPLAYER_FENTER();
8399
8400         if (user_data == NULL) {
8401                 LOGE("- user_data is null\n");
8402                 return FALSE;
8403         }
8404         player = (mm_player_t *)user_data;
8405
8406         /* do something to release resource here.
8407          * player stop and interrupt forwarding */
8408         if (!__mmplayer_can_do_interrupt(player)) {
8409                 LOGW("no need to interrupt, so leave");
8410         } else {
8411                 MMMessageParamType msg = {0, };
8412                 unsigned long pos = 0;
8413
8414                 player->interrupted_by_resource = TRUE;
8415
8416                 /* get last play position */
8417                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8418                         LOGW("failed to get play position.");
8419                 } else {
8420                         msg.union_type = MM_MSG_UNION_TIME;
8421                         msg.time.elapsed = (unsigned int)pos;
8422                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8423                 }
8424                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8425                 if (_mmplayer_unrealize((MMHandleType)player))
8426                         LOGW("failed to unrealize");
8427
8428                 /* lock is called in __mmplayer_can_do_interrupt() */
8429                 MMPLAYER_CMD_UNLOCK(player);
8430         }
8431
8432         if (res == player->video_overlay_resource)
8433                 player->video_overlay_resource = FALSE;
8434         else
8435                 player->video_decoder_resource = FALSE;
8436
8437         MMPLAYER_FLEAVE();
8438
8439         return FALSE;
8440 }
8441
8442 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8443 static int
8444 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8445 {
8446         int ret = MM_ERROR_NONE;
8447         MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8448
8449         if (strstr(reason_for_change, "alarm")) {
8450                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8451
8452         } else if (strstr(reason_for_change, "notification")) {
8453                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8454
8455         } else if (strstr(reason_for_change, "emergency")) {
8456                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8457
8458         } else if (strstr(reason_for_change, "call-voice") ||
8459                                 strstr(reason_for_change, "call-video") ||
8460                                 strstr(reason_for_change, "voip") ||
8461                                 strstr(reason_for_change, "ringtone-voip") ||
8462                                 strstr(reason_for_change, "ringtone-call")) {
8463                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8464
8465         } else if (strstr(reason_for_change, "media") ||
8466                                 strstr(reason_for_change, "radio") ||
8467                                 strstr(reason_for_change, "loopback") ||
8468                                 strstr(reason_for_change, "system") ||
8469                                 strstr(reason_for_change, "voice-information") ||
8470                                 strstr(reason_for_change, "voice-recognition")) {
8471                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8472
8473         } else {
8474                 ret = MM_ERROR_INVALID_ARGUMENT;
8475                 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8476                 goto DONE;
8477         }
8478
8479         if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8480                 /* can acqurie */
8481                 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8482
8483         LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8484         *msg = focus_msg;
8485
8486 DONE:
8487         return ret;
8488 }
8489
8490 /* FIXME: will be updated with new funct */
8491 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8492                                        const char *reason_for_change, const char *additional_info, void *user_data)
8493 {
8494         mm_player_t* player = (mm_player_t*) user_data;
8495         int result = MM_ERROR_NONE;
8496         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8497
8498         LOGW("[handle: %p] focus watch notified", player);
8499
8500         if (!__mmplayer_can_do_interrupt(player)) {
8501                 LOGW("no need to interrupt, so leave");
8502                 goto EXIT_WITHOUT_UNLOCK;
8503         }
8504
8505         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8506                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8507                 goto EXIT;
8508         }
8509
8510         LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8511                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8512
8513         player->sound_focus.cb_pending = TRUE;
8514         player->sound_focus.by_asm_cb = TRUE;
8515
8516         if (focus_state == FOCUS_IS_ACQUIRED) {
8517                 LOGW("watch: FOCUS_IS_ACQUIRED");
8518                 player->sound_focus.acquired = TRUE;
8519
8520                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8521                         player->sound_focus.focus_changed_msg = (int)msg;
8522
8523                 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_CALL ||
8524                         player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_ALARM ||
8525                         player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA) {
8526                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8527                                 // hold 0.7 second to excute "fadedown mute" effect
8528                                 LOGW("do fade down->pause->undo fade down");
8529
8530                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8531
8532                                 result = _mmplayer_pause((MMHandleType)player);
8533                                 if (result != MM_ERROR_NONE) {
8534                                         LOGW("fail to set Pause state by asm");
8535                                         goto EXIT;
8536                                 }
8537
8538                                 __mmplayer_undo_sound_fadedown(player);
8539                         } else {
8540                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8541                                 _mmplayer_unrealize((MMHandleType)player);
8542                         }
8543                 } else {
8544                         LOGW("pause immediately");
8545                         result = _mmplayer_pause((MMHandleType)player);
8546                         if (result != MM_ERROR_NONE) {
8547                                 LOGW("fail to set Pause state by asm");
8548                                 goto EXIT;
8549                         }
8550                 }
8551         } else if (focus_state == FOCUS_IS_RELEASED) {
8552                 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8553                 player->sound_focus.acquired = FALSE;
8554                 player->sound_focus.antishock = TRUE;
8555                 player->sound_focus.by_asm_cb = FALSE;
8556
8557                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8558                         player->sound_focus.focus_changed_msg = (int)msg;
8559
8560                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8561                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8562                 goto DONE;
8563         } else
8564                 LOGW("unknown focus state %d", focus_state);
8565
8566 DONE:
8567         player->sound_focus.by_asm_cb = FALSE;
8568         player->sound_focus.cb_pending = FALSE;
8569
8570 EXIT:
8571         MMPLAYER_CMD_UNLOCK(player);
8572         LOGW("dispatched");
8573         return;
8574
8575 EXIT_WITHOUT_UNLOCK:
8576         LOGW("dispatched");
8577         return;
8578 }
8579
8580 void
8581 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8582         const char *reason_for_change, int option, const char *additional_info, void *user_data)
8583 {
8584         mm_player_t* player = (mm_player_t*) user_data;
8585         int result = MM_ERROR_NONE;
8586         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8587
8588         LOGW("get focus notified");
8589
8590         if (!__mmplayer_can_do_interrupt(player)) {
8591                 LOGW("no need to interrupt, so leave");
8592                 goto EXIT_WITHOUT_UNLOCK;
8593         }
8594
8595         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8596                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8597                 goto EXIT;
8598         }
8599
8600         LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8601                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8602
8603         player->sound_focus.cb_pending = TRUE;
8604         player->sound_focus.by_asm_cb = TRUE;
8605 //      player->sound_focus.event_src = event_src;
8606
8607         if (focus_state == FOCUS_IS_RELEASED) {
8608                 LOGW("FOCUS_IS_RELEASED");
8609                 player->sound_focus.acquired = FALSE;
8610
8611                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8612                         player->sound_focus.focus_changed_msg = (int)msg;
8613
8614                 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_CALL ||
8615                         player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_ALARM ||
8616                         player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA) {
8617                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8618                                 //hold 0.7 second to excute "fadedown mute" effect
8619                                 LOGW("do fade down->pause->undo fade down");
8620
8621                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8622
8623                                 result = _mmplayer_pause((MMHandleType)player);
8624                                 if (result != MM_ERROR_NONE) {
8625                                         LOGW("fail to set Pause state by asm");
8626                                         goto EXIT;
8627                                 }
8628                                 __mmplayer_undo_sound_fadedown(player);
8629                         } else {
8630                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8631                                 _mmplayer_unrealize((MMHandleType)player);
8632                         }
8633                 } else {
8634                         LOGW("pause immediately");
8635                         result = _mmplayer_pause((MMHandleType)player);
8636                         if (result != MM_ERROR_NONE) {
8637                                 LOGW("fail to set Pause state by asm");
8638                                 goto EXIT;
8639                         }
8640                 }
8641
8642                 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA &&
8643                         player->sound_focus.session_type == MM_SESSION_TYPE_MEDIA &&
8644                         !(player->sound_focus.session_flags & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED)) {
8645                         result = mm_sound_set_focus_reacquisition_for_session(player->sound_focus.focus_id, false);
8646                         if (result != MM_ERROR_NONE)
8647                                 LOGW("fail to set focus reacquisition to FALSE, skip going on..");
8648                 }
8649         } else if (focus_state == FOCUS_IS_ACQUIRED) {
8650                 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8651                 player->sound_focus.antishock = TRUE;
8652                 player->sound_focus.by_asm_cb = FALSE;
8653
8654                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8655                         player->sound_focus.focus_changed_msg = (int)msg;
8656
8657                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8658                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8659                 goto DONE;
8660         } else
8661                 LOGW("unknown focus state %d", focus_state);
8662
8663 DONE:
8664         player->sound_focus.by_asm_cb = FALSE;
8665         player->sound_focus.cb_pending = FALSE;
8666
8667 EXIT:
8668         if (mm_sound_update_focus_status(id, 0))
8669                 LOGE("failed to update focus status\n");
8670         MMPLAYER_CMD_UNLOCK(player);
8671         LOGW("dispatched");
8672         return;
8673
8674 EXIT_WITHOUT_UNLOCK:
8675         LOGW("dispatched");
8676         return;
8677 }
8678
8679
8680 int
8681 _mmplayer_create_player(MMHandleType handle)
8682 {
8683         int ret = MM_ERROR_PLAYER_INTERNAL;
8684         mm_player_t* player = MM_PLAYER_CAST(handle);
8685
8686         MMPLAYER_FENTER();
8687
8688         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8689
8690         /* initialize player state */
8691         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8692         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8693         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8694         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8695
8696         /* check current state */
8697         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8698
8699         /* construct attributes */
8700         player->attrs = _mmplayer_construct_attribute(handle);
8701
8702         if (!player->attrs) {
8703                 LOGE("Failed to construct attributes\n");
8704                 return ret;
8705         }
8706
8707         /* initialize gstreamer with configured parameter */
8708         if (!__mmplayer_init_gstreamer(player)) {
8709                 LOGE("Initializing gstreamer failed\n");
8710                 _mmplayer_deconstruct_attribute(handle);
8711                 return ret;
8712         }
8713
8714         /* create lock. note that g_tread_init() has already called in gst_init() */
8715         g_mutex_init(&player->fsink_lock);
8716
8717         /* create update tag lock */
8718         g_mutex_init(&player->update_tag_lock);
8719
8720         /* create repeat mutex */
8721         g_mutex_init(&player->repeat_thread_mutex);
8722
8723         /* create repeat cond */
8724         g_cond_init(&player->repeat_thread_cond);
8725
8726         /* create repeat thread */
8727         player->repeat_thread =
8728                 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8729         if (!player->repeat_thread) {
8730                 LOGE("failed to create repeat_thread(%s)");
8731                 g_mutex_clear(&player->repeat_thread_mutex);
8732                 g_cond_clear(&player->repeat_thread_cond);
8733                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8734                 goto ERROR;
8735         }
8736
8737         /* create next play mutex */
8738         g_mutex_init(&player->next_play_thread_mutex);
8739
8740         /* create next play cond */
8741         g_cond_init(&player->next_play_thread_cond);
8742
8743         /* create next play thread */
8744         player->next_play_thread =
8745                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8746         if (!player->next_play_thread) {
8747                 LOGE("failed to create next play thread");
8748                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8749                 g_mutex_clear(&player->next_play_thread_mutex);
8750                 g_cond_clear(&player->next_play_thread_cond);
8751                 goto ERROR;
8752         }
8753
8754         ret = _mmplayer_initialize_video_capture(player);
8755         if (ret != MM_ERROR_NONE) {
8756                 LOGE("failed to initialize video capture\n");
8757                 goto ERROR;
8758         }
8759
8760         /* initialize resource manager */
8761         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8762                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8763                         &player->resource_manager)) {
8764                 LOGE("failed to initialize resource manager\n");
8765                 goto ERROR;
8766         }
8767
8768         if (MMPLAYER_IS_HTTP_PD(player)) {
8769                 player->pd_downloader = NULL;
8770                 player->pd_file_save_path = NULL;
8771         }
8772
8773         /* create video bo lock and cond */
8774         g_mutex_init(&player->video_bo_mutex);
8775         g_cond_init(&player->video_bo_cond);
8776
8777         /* create media stream callback mutex */
8778         g_mutex_init(&player->media_stream_cb_lock);
8779
8780         /* create subtitle info lock and cond */
8781         g_mutex_init(&player->subtitle_info_mutex);
8782         g_cond_init(&player->subtitle_info_cond);
8783
8784         /* create sound focus lock */
8785         g_mutex_init(&player->sound_focus.focus_lock);
8786
8787         player->streaming_type = STREAMING_SERVICE_NONE;
8788
8789         /* give default value of audio effect setting */
8790         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8791         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8792
8793         player->play_subtitle = FALSE;
8794         player->play_count = 0;
8795         player->use_deinterleave = FALSE;
8796         player->max_audio_channels = 0;
8797         player->video_share_api_delta = 0;
8798         player->video_share_clock_delta = 0;
8799         player->has_closed_caption = FALSE;
8800         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8801         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8802         player->pending_resume = FALSE;
8803         if (player->ini.dump_element_keyword[0][0] == '\0')
8804                 player->ini.set_dump_element_flag = FALSE;
8805         else
8806                 player->ini.set_dump_element_flag = TRUE;
8807
8808         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8809         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8810         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8811
8812         /* Set video360 settings to their defaults for just-created player.
8813          * */
8814         player->is_content_spherical = FALSE;
8815         player->is_video360_enabled = TRUE;
8816         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8817         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8818         player->video360_yaw_radians = 4;
8819         player->video360_pitch_radians = 4;
8820         player->video360_zoom = 1.0f;
8821         player->video360_horizontal_fov = 0;
8822         player->video360_vertical_fov = 0;
8823
8824         /* set player state to null */
8825         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8826         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8827
8828         return MM_ERROR_NONE;
8829
8830 ERROR:
8831         /* free lock */
8832         g_mutex_clear(&player->fsink_lock);
8833
8834         /* free update tag lock */
8835         g_mutex_clear(&player->update_tag_lock);
8836
8837         /* free thread */
8838         if (player->repeat_thread) {
8839                 MMPLAYER_REPEAT_THREAD_LOCK(player);
8840                 player->repeat_thread_exit = TRUE;
8841                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8842                 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8843
8844                 g_thread_join(player->repeat_thread);
8845                 player->repeat_thread = NULL;
8846
8847                 g_mutex_clear(&player->repeat_thread_mutex);
8848                 g_cond_clear(&player->repeat_thread_cond);
8849         }
8850
8851         /* free next play thread */
8852         if (player->next_play_thread) {
8853                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8854                 player->next_play_thread_exit = TRUE;
8855                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8856                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8857
8858                 g_thread_join(player->next_play_thread);
8859                 player->next_play_thread = NULL;
8860
8861                 g_mutex_clear(&player->next_play_thread_mutex);
8862                 g_cond_clear(&player->next_play_thread_cond);
8863         }
8864
8865         /* release attributes */
8866         _mmplayer_deconstruct_attribute(handle);
8867
8868         MMPLAYER_FLEAVE();
8869
8870         return ret;
8871 }
8872
8873 static gboolean
8874 __mmplayer_init_gstreamer(mm_player_t* player)
8875 {
8876         static gboolean initialized = FALSE;
8877         static const int max_argc = 50;
8878         gint* argc = NULL;
8879         gchar** argv = NULL;
8880         gchar** argv2 = NULL;
8881         GError *err = NULL;
8882         int i = 0;
8883         int arg_count = 0;
8884
8885         if (initialized) {
8886                 LOGD("gstreamer already initialized.\n");
8887                 return TRUE;
8888         }
8889
8890         /* alloc */
8891         argc = malloc(sizeof(int));
8892         argv = malloc(sizeof(gchar*) * max_argc);
8893         argv2 = malloc(sizeof(gchar*) * max_argc);
8894
8895         if (!argc || !argv || !argv2)
8896                 goto ERROR;
8897
8898         memset(argv, 0, sizeof(gchar*) * max_argc);
8899         memset(argv2, 0, sizeof(gchar*) * max_argc);
8900
8901         /* add initial */
8902         *argc = 1;
8903         argv[0] = g_strdup("mmplayer");
8904
8905         /* add gst_param */
8906         for (i = 0; i < 5; i++) {
8907                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8908                 if (strlen(player->ini.gst_param[i]) > 0) {
8909                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8910                         (*argc)++;
8911                 }
8912         }
8913
8914         /* we would not do fork for scanning plugins */
8915         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8916         (*argc)++;
8917
8918         /* check disable registry scan */
8919         if (player->ini.skip_rescan) {
8920                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8921                 (*argc)++;
8922         }
8923
8924         /* check disable segtrap */
8925         if (player->ini.disable_segtrap) {
8926                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8927                 (*argc)++;
8928         }
8929
8930         LOGD("initializing gstreamer with following parameter\n");
8931         LOGD("argc : %d\n", *argc);
8932         arg_count = *argc;
8933
8934         for (i = 0; i < arg_count; i++) {
8935                 argv2[i] = argv[i];
8936                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8937         }
8938
8939         /* initializing gstreamer */
8940         if (!gst_init_check(argc, &argv, &err)) {
8941                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8942                 if (err)
8943                         g_error_free(err);
8944
8945                 goto ERROR;
8946         }
8947         /* release */
8948         for (i = 0; i < arg_count; i++) {
8949                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8950                 MMPLAYER_FREEIF(argv2[i]);
8951         }
8952
8953         MMPLAYER_FREEIF(argv);
8954         MMPLAYER_FREEIF(argv2);
8955         MMPLAYER_FREEIF(argc);
8956
8957         /* done */
8958         initialized = TRUE;
8959
8960         return TRUE;
8961
8962 ERROR:
8963
8964         /* release */
8965         for (i = 0; i < arg_count; i++) {
8966                 LOGD("free[%d] : %s\n", i, argv2[i]);
8967                 MMPLAYER_FREEIF(argv2[i]);
8968         }
8969
8970         MMPLAYER_FREEIF(argv);
8971         MMPLAYER_FREEIF(argv2);
8972         MMPLAYER_FREEIF(argc);
8973
8974         return FALSE;
8975 }
8976
8977 int
8978 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8979 {
8980         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8981
8982         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8983                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8984                 MMPLAYER_FREEIF(player->pd_file_save_path);
8985         }
8986
8987         return MM_ERROR_NONE;
8988 }
8989
8990 static void
8991 __mmplayer_check_async_state_transition(mm_player_t* player)
8992 {
8993         GstState element_state = GST_STATE_VOID_PENDING;
8994         GstState element_pending_state = GST_STATE_VOID_PENDING;
8995         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8996         GstElement * element = NULL;
8997         gboolean async = FALSE;
8998
8999         /* check player handle */
9000         MMPLAYER_RETURN_IF_FAIL(player &&
9001                                                 player->pipeline &&
9002                                                 player->pipeline->mainbin &&
9003                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
9004
9005         if (player->attrs)
9006                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9007
9008         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
9009                 LOGD("don't need to check the pipeline state");
9010                 return;
9011         }
9012
9013         MMPLAYER_PRINT_STATE(player);
9014
9015         /* wait for state transition */
9016         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
9017         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
9018
9019         if (ret == GST_STATE_CHANGE_FAILURE) {
9020                 LOGE(" [%s] state : %s   pending : %s \n",
9021                         GST_ELEMENT_NAME(element),
9022                         gst_element_state_get_name(element_state),
9023                         gst_element_state_get_name(element_pending_state));
9024
9025                 /* dump state of all element */
9026                 __mmplayer_dump_pipeline_state(player);
9027
9028                 return;
9029         }
9030
9031         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
9032         return;
9033 }
9034
9035 int
9036 _mmplayer_destroy(MMHandleType handle)
9037 {
9038         mm_player_t* player = MM_PLAYER_CAST(handle);
9039
9040         MMPLAYER_FENTER();
9041
9042         /* check player handle */
9043         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9044
9045         /* destroy can called at anytime */
9046         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
9047
9048         /* check async state transition */
9049         __mmplayer_check_async_state_transition(player);
9050
9051         __mmplayer_destroy_streaming_ext(player);
9052
9053         /* release repeat thread */
9054         if (player->repeat_thread) {
9055                 MMPLAYER_REPEAT_THREAD_LOCK(player);
9056                 player->repeat_thread_exit = TRUE;
9057                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
9058                 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
9059
9060                 LOGD("waitting for repeat thread exit\n");
9061                 g_thread_join(player->repeat_thread);
9062                 g_mutex_clear(&player->repeat_thread_mutex);
9063                 g_cond_clear(&player->repeat_thread_cond);
9064                 LOGD("repeat thread released\n");
9065         }
9066
9067         /* release next play thread */
9068         if (player->next_play_thread) {
9069                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
9070                 player->next_play_thread_exit = TRUE;
9071                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
9072                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
9073
9074                 LOGD("waitting for next play thread exit\n");
9075                 g_thread_join(player->next_play_thread);
9076                 g_mutex_clear(&player->next_play_thread_mutex);
9077                 g_cond_clear(&player->next_play_thread_cond);
9078                 LOGD("next play thread released\n");
9079         }
9080
9081         _mmplayer_release_video_capture(player);
9082
9083         /* flush any pending asm_cb */
9084         if (player->sound_focus.cb_pending) {
9085                 /* set a flag for make sure asm_cb to be returned immediately */
9086                 LOGW("asm cb has pending state");
9087                 player->sound_focus.exit_cb = TRUE;
9088
9089                 /* make sure to release any pending asm_cb which locked by cmd_lock */
9090                 MMPLAYER_CMD_UNLOCK(player);
9091                 sched_yield();
9092                 MMPLAYER_CMD_LOCK(player);
9093         }
9094
9095         /* withdraw asm */
9096         if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
9097                 LOGE("failed to deregister asm server\n");
9098
9099         /* de-initialize resource manager */
9100         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
9101                         player->resource_manager))
9102                 LOGE("failed to deinitialize resource manager\n");
9103
9104         if (player->resume_event_id) {
9105                 g_source_remove(player->resume_event_id);
9106                 player->resume_event_id = 0;
9107         }
9108
9109         if (player->resumable_cancel_id) {
9110                 g_source_remove(player->resumable_cancel_id);
9111                 player->resumable_cancel_id = 0;
9112         }
9113
9114         /* release pipeline */
9115         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
9116                 LOGE("failed to destory pipeline\n");
9117                 return MM_ERROR_PLAYER_INTERNAL;
9118         }
9119
9120         /* release subtitle info lock and cond */
9121         g_mutex_clear(&player->subtitle_info_mutex);
9122         g_cond_clear(&player->subtitle_info_cond);
9123
9124         __mmplayer_release_dump_list(player->dump_list);
9125
9126         /* release miscellaneous information */
9127         __mmplayer_release_misc(player);
9128
9129         /* release miscellaneous information.
9130            these info needs to be released after pipeline is destroyed. */
9131         __mmplayer_release_misc_post(player);
9132
9133         /* release attributes */
9134         _mmplayer_deconstruct_attribute(handle);
9135
9136         /* release lock */
9137         g_mutex_clear(&player->fsink_lock);
9138
9139         /* release lock */
9140         g_mutex_clear(&player->update_tag_lock);
9141
9142         /* release video bo lock and cond */
9143         g_mutex_clear(&player->video_bo_mutex);
9144         g_cond_clear(&player->video_bo_cond);
9145
9146         /* release media stream callback lock */
9147         g_mutex_clear(&player->media_stream_cb_lock);
9148
9149         /* release sound focus lock */
9150         g_mutex_clear(&player->sound_focus.focus_lock);
9151
9152         MMPLAYER_FLEAVE();
9153
9154         return MM_ERROR_NONE;
9155 }
9156
9157 int
9158 __mmplayer_realize_streaming_ext(mm_player_t* player)
9159 {
9160         int ret = MM_ERROR_NONE;
9161
9162         MMPLAYER_FENTER();
9163         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9164
9165         if (MMPLAYER_IS_HTTP_PD(player)) {
9166                 gboolean bret = FALSE;
9167
9168                 player->pd_downloader = _mmplayer_create_pd_downloader();
9169                 if (!player->pd_downloader) {
9170                         LOGE("Unable to create PD Downloader...");
9171                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
9172                 }
9173
9174                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
9175
9176                 if (FALSE == bret) {
9177                         LOGE("Unable to create PD Downloader...");
9178                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
9179                 }
9180         }
9181
9182         MMPLAYER_FLEAVE();
9183         return ret;
9184 }
9185
9186 int
9187 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid)
9188 {
9189         mm_player_t* player = (mm_player_t*)hplayer;
9190         MMHandleType attrs = 0;
9191         int ret = MM_ERROR_NONE;
9192
9193         attrs = MMPLAYER_GET_ATTRS(player);
9194         if (!attrs) {
9195                 LOGE("fail to get attributes.\n");
9196                 return MM_ERROR_PLAYER_INTERNAL;
9197         }
9198
9199         player->sound_focus.pid = pid;
9200
9201         /* register to asm */
9202         if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
9203                                                 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
9204                                                 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
9205                                                 (void*)player)) {
9206                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
9207                 LOGE("failed to register asm server\n");
9208                 return MM_ERROR_POLICY_INTERNAL;
9209         }
9210         return ret;
9211 }
9212
9213 int
9214 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
9215 {
9216         mm_player_t* player = (mm_player_t*) hplayer;
9217
9218         MMPLAYER_FENTER();
9219
9220         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9221
9222         *pid = player->sound_focus.pid;
9223
9224         LOGD("registered pid[%d] %p", *pid, player);
9225
9226         MMPLAYER_FLEAVE();
9227
9228         return MM_ERROR_NONE;
9229 }
9230
9231 int
9232 _mmplayer_realize(MMHandleType hplayer)
9233 {
9234         mm_player_t* player = (mm_player_t*)hplayer;
9235         char *uri = NULL;
9236         void *param = NULL;
9237         gboolean update_registry = FALSE;
9238         MMHandleType attrs = 0;
9239         int ret = MM_ERROR_NONE;
9240
9241         MMPLAYER_FENTER();
9242
9243         /* check player handle */
9244         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9245
9246         /* check current state */
9247         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
9248
9249         attrs = MMPLAYER_GET_ATTRS(player);
9250         if (!attrs) {
9251                 LOGE("fail to get attributes.\n");
9252                 return MM_ERROR_PLAYER_INTERNAL;
9253         }
9254         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9255         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
9256
9257         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
9258                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9259
9260                 if (ret != MM_ERROR_NONE) {
9261                         LOGE("failed to parse profile\n");
9262                         return ret;
9263                 }
9264         }
9265
9266         /* profile.mem or mem_buf.buf have to be free when player is destroyed */
9267         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
9268                 player->mem_buf.buf = (char *)player->profile.mem;
9269                 player->mem_buf.len = player->profile.mem_size;
9270                 player->mem_buf.offset = 0;
9271         }
9272
9273         if (uri && (strstr(uri, "es_buff://"))) {
9274                 if (strstr(uri, "es_buff://push_mode"))
9275                         player->es_player_push_mode = TRUE;
9276                 else
9277                         player->es_player_push_mode = FALSE;
9278         }
9279
9280         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
9281                 LOGW("mms protocol is not supported format.\n");
9282                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9283         }
9284
9285         if (MMPLAYER_IS_STREAMING(player))
9286                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9287         else
9288                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9289
9290         player->smooth_streaming = FALSE;
9291         player->videodec_linked  = 0;
9292         player->videosink_linked = 0;
9293         player->audiodec_linked  = 0;
9294         player->audiosink_linked = 0;
9295         player->textsink_linked = 0;
9296         player->is_external_subtitle_present = FALSE;
9297         player->is_external_subtitle_added_now = FALSE;
9298         /* set the subtitle ON default */
9299         player->is_subtitle_off = FALSE;
9300
9301         /* registry should be updated for downloadable codec */
9302         mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9303
9304         if (update_registry) {
9305                 LOGD("updating registry...\n");
9306                 gst_update_registry();
9307         }
9308
9309         /* realize pipeline */
9310         ret = __gst_realize(player);
9311         if (ret != MM_ERROR_NONE)
9312                 LOGE("fail to realize the player.\n");
9313         else
9314                 ret = __mmplayer_realize_streaming_ext(player);
9315
9316         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
9317         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
9318
9319         MMPLAYER_FLEAVE();
9320
9321         return ret;
9322 }
9323
9324 int
9325 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9326 {
9327         MMPLAYER_FENTER();
9328         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9329
9330         /* destroy can called at anytime */
9331         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
9332                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9333
9334         MMPLAYER_FLEAVE();
9335         return MM_ERROR_NONE;
9336 }
9337
9338 int
9339 _mmplayer_unrealize(MMHandleType hplayer)
9340 {
9341         mm_player_t* player = (mm_player_t*)hplayer;
9342         int ret = MM_ERROR_NONE;
9343
9344         MMPLAYER_FENTER();
9345
9346         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9347
9348         MMPLAYER_CMD_UNLOCK(player);
9349         /* destroy the gst bus msg thread which is created during realize.
9350            this funct have to be called before getting cmd lock. */
9351         _mmplayer_bus_msg_thread_destroy(player);
9352         MMPLAYER_CMD_LOCK(player);
9353
9354         /* check current state */
9355         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9356
9357         /* check async state transition */
9358         __mmplayer_check_async_state_transition(player);
9359
9360         __mmplayer_unrealize_streaming_ext(player);
9361
9362         /* unrealize pipeline */
9363         ret = __gst_unrealize(player);
9364
9365         /* set asm stop if success */
9366         if (MM_ERROR_NONE == ret) {
9367                 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9368                 if (ret != MM_ERROR_NONE)
9369                         LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9370
9371                 if (!player->interrupted_by_resource) {
9372                         if (player->video_decoder_resource != NULL) {
9373                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
9374                                                 player->video_decoder_resource);
9375                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9376                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
9377                                 else
9378                                         player->video_decoder_resource = NULL;
9379                         }
9380
9381                         if (player->video_overlay_resource != NULL) {
9382                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
9383                                                 player->video_overlay_resource);
9384                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9385                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
9386                                 else
9387                                         player->video_overlay_resource = NULL;
9388                         }
9389
9390                         ret = mm_resource_manager_commit(player->resource_manager);
9391                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9392                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
9393                 }
9394         } else
9395                 LOGE("failed and don't change asm state to stop");
9396
9397         MMPLAYER_FLEAVE();
9398
9399         return ret;
9400 }
9401
9402 int
9403 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
9404 {
9405         mm_player_t* player = (mm_player_t*)hplayer;
9406
9407         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9408
9409         return __gst_set_message_callback(player, callback, user_param);
9410 }
9411
9412 int
9413 _mmplayer_get_state(MMHandleType hplayer, int* state)
9414 {
9415         mm_player_t *player = (mm_player_t*)hplayer;
9416
9417         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9418
9419         *state = MMPLAYER_CURRENT_STATE(player);
9420
9421         return MM_ERROR_NONE;
9422 }
9423
9424
9425 int
9426 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
9427 {
9428         mm_player_t* player = (mm_player_t*) hplayer;
9429         GstElement* vol_element = NULL;
9430         int i = 0;
9431
9432         MMPLAYER_FENTER();
9433
9434         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9435
9436         LOGD("volume [L]=%f:[R]=%f\n",
9437                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9438
9439         /* invalid factor range or not */
9440         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9441                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9442                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
9443                         return MM_ERROR_INVALID_ARGUMENT;
9444                 }
9445         }
9446
9447         /* not support to set other value into each channel */
9448         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9449                 return MM_ERROR_INVALID_ARGUMENT;
9450
9451         /* Save volume to handle. Currently the first array element will be saved. */
9452         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9453
9454         /* check pipeline handle */
9455         if (!player->pipeline || !player->pipeline->audiobin) {
9456                 LOGD("audiobin is not created yet\n");
9457                 LOGD("but, current stored volume will be set when it's created.\n");
9458
9459                 /* NOTE : stored volume will be used in create_audiobin
9460                  * returning MM_ERROR_NONE here makes application to able to
9461                  * set volume at anytime.
9462                  */
9463                 return MM_ERROR_NONE;
9464         }
9465
9466         /* setting volume to volume element */
9467         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9468
9469         if (vol_element) {
9470                 LOGD("volume is set [%f]\n", player->sound.volume);
9471                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9472         }
9473
9474         MMPLAYER_FLEAVE();
9475
9476         return MM_ERROR_NONE;
9477 }
9478
9479
9480 int
9481 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9482 {
9483         mm_player_t* player = (mm_player_t*) hplayer;
9484         int i = 0;
9485
9486         MMPLAYER_FENTER();
9487
9488         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9489         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9490
9491         /* returning stored volume */
9492         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9493                 volume->level[i] = player->sound.volume;
9494
9495         MMPLAYER_FLEAVE();
9496
9497         return MM_ERROR_NONE;
9498 }
9499
9500 int
9501 _mmplayer_set_mute(MMHandleType hplayer, int mute)
9502 {
9503         mm_player_t* player = (mm_player_t*) hplayer;
9504         GstElement* vol_element = NULL;
9505
9506         MMPLAYER_FENTER();
9507
9508         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9509
9510         /* mute value shoud 0 or 1 */
9511         if (mute != 0 && mute != 1) {
9512                 LOGE("bad mute value\n");
9513
9514                 /* FIXIT : definitly, we need _BAD_PARAM error code */
9515                 return MM_ERROR_INVALID_ARGUMENT;
9516         }
9517
9518         player->sound.mute = mute;
9519
9520         /* just hold mute value if pipeline is not ready */
9521         if (!player->pipeline || !player->pipeline->audiobin) {
9522                 LOGD("pipeline is not ready. holding mute value\n");
9523                 return MM_ERROR_NONE;
9524         }
9525
9526         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9527
9528         /* NOTE : volume will only created when the bt is enabled */
9529         if (vol_element) {
9530                 LOGD("mute : %d\n", mute);
9531                 g_object_set(vol_element, "mute", mute, NULL);
9532         } else
9533                 LOGD("volume elemnet is not created. using volume in audiosink\n");
9534
9535         MMPLAYER_FLEAVE();
9536
9537         return MM_ERROR_NONE;
9538 }
9539
9540 int
9541 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
9542 {
9543         mm_player_t* player = (mm_player_t*) hplayer;
9544
9545         MMPLAYER_FENTER();
9546
9547         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9548         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9549
9550         /* just hold mute value if pipeline is not ready */
9551         if (!player->pipeline || !player->pipeline->audiobin) {
9552                 LOGD("pipeline is not ready. returning stored value\n");
9553                 *pmute = player->sound.mute;
9554                 return MM_ERROR_NONE;
9555         }
9556
9557         *pmute = player->sound.mute;
9558
9559         MMPLAYER_FLEAVE();
9560
9561         return MM_ERROR_NONE;
9562 }
9563
9564 int
9565 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9566 {
9567         mm_player_t* player = (mm_player_t*) hplayer;
9568
9569         MMPLAYER_FENTER();
9570
9571         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9572
9573         player->video_stream_changed_cb = callback;
9574         player->video_stream_changed_cb_user_param = user_param;
9575         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9576
9577         MMPLAYER_FLEAVE();
9578
9579         return MM_ERROR_NONE;
9580 }
9581
9582 int
9583 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9584 {
9585         mm_player_t* player = (mm_player_t*) hplayer;
9586
9587         MMPLAYER_FENTER();
9588
9589         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9590
9591         player->audio_stream_changed_cb = callback;
9592         player->audio_stream_changed_cb_user_param = user_param;
9593         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9594
9595         MMPLAYER_FLEAVE();
9596
9597         return MM_ERROR_NONE;
9598 }
9599
9600 int
9601 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9602 {
9603         mm_player_t* player = (mm_player_t*) hplayer;
9604
9605         MMPLAYER_FENTER();
9606
9607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9608
9609         player->audio_stream_render_cb_ex = callback;
9610         player->audio_stream_cb_user_param = user_param;
9611         player->audio_stream_sink_sync = sync;
9612         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);
9613
9614         MMPLAYER_FLEAVE();
9615
9616         return MM_ERROR_NONE;
9617 }
9618
9619 int
9620 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9621 {
9622         mm_player_t* player = (mm_player_t*) hplayer;
9623
9624         MMPLAYER_FENTER();
9625
9626         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9627
9628         if (callback && !player->bufmgr)
9629                 player->bufmgr = tbm_bufmgr_init(-1);
9630
9631         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9632         player->video_stream_cb = callback;
9633         player->video_stream_cb_user_param = user_param;
9634
9635         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9636
9637         MMPLAYER_FLEAVE();
9638
9639         return MM_ERROR_NONE;
9640 }
9641
9642 int
9643 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9644 {
9645         mm_player_t* player = (mm_player_t*) hplayer;
9646
9647         MMPLAYER_FENTER();
9648
9649         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9650
9651         player->audio_stream_cb = callback;
9652         player->audio_stream_cb_user_param = user_param;
9653         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9654
9655         MMPLAYER_FLEAVE();
9656
9657         return MM_ERROR_NONE;
9658 }
9659
9660 static int
9661 __mmplayer_start_streaming_ext(mm_player_t *player)
9662 {
9663         gint ret = MM_ERROR_NONE;
9664
9665         MMPLAYER_FENTER();
9666         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9667
9668         if (MMPLAYER_IS_HTTP_PD(player)) {
9669                 if (!player->pd_downloader) {
9670                         ret = __mmplayer_realize_streaming_ext(player);
9671
9672                         if (ret != MM_ERROR_NONE) {
9673                                 LOGE("failed to realize streaming ext\n");
9674                                 return ret;
9675                         }
9676                 }
9677
9678                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9679                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9680                         if (!ret) {
9681                                 LOGE("ERROR while starting PD...\n");
9682                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9683                         }
9684                         ret = MM_ERROR_NONE;
9685                 }
9686         }
9687
9688         MMPLAYER_FLEAVE();
9689         return ret;
9690 }
9691
9692 int
9693 _mmplayer_start(MMHandleType hplayer)
9694 {
9695         mm_player_t* player = (mm_player_t*) hplayer;
9696         gint ret = MM_ERROR_NONE;
9697
9698         MMPLAYER_FENTER();
9699
9700         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9701
9702         /* check current state */
9703         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9704
9705         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9706         if (ret != MM_ERROR_NONE) {
9707                 LOGE("failed to acquire sound focus.\n");
9708                 return ret;
9709         }
9710
9711         /* NOTE : we should check and create pipeline again if not created as we destroy
9712          * whole pipeline when stopping in streamming playback
9713          */
9714         if (!player->pipeline) {
9715                 ret = __gst_realize(player);
9716                 if (MM_ERROR_NONE != ret) {
9717                         LOGE("failed to realize before starting. only in streamming\n");
9718                         /* unlock */
9719                         return ret;
9720                 }
9721         }
9722
9723         ret = __mmplayer_start_streaming_ext(player);
9724         if (ret != MM_ERROR_NONE) {
9725                 LOGE("failed to start streaming ext 0x%X", ret);
9726                 return ret;
9727         }
9728
9729         /* start pipeline */
9730         ret = __gst_start(player);
9731         if (ret != MM_ERROR_NONE)
9732                 LOGE("failed to start player.\n");
9733
9734         MMPLAYER_FLEAVE();
9735
9736         return ret;
9737 }
9738
9739 /* NOTE: post "not supported codec message" to application
9740  * when one codec is not found during AUTOPLUGGING in MSL.
9741  * So, it's separated with error of __mmplayer_gst_callback().
9742  * And, if any codec is not found, don't send message here.
9743  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9744  */
9745 int
9746 __mmplayer_handle_missed_plugin(mm_player_t* player)
9747 {
9748         MMMessageParamType msg_param;
9749         memset(&msg_param, 0, sizeof(MMMessageParamType));
9750         gboolean post_msg_direct = FALSE;
9751
9752         MMPLAYER_FENTER();
9753
9754         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9755
9756         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9757                         player->not_supported_codec, player->can_support_codec);
9758
9759         if (player->not_found_demuxer) {
9760                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9761                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9762
9763                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9764                 MMPLAYER_FREEIF(msg_param.data);
9765
9766                 return MM_ERROR_NONE;
9767         }
9768
9769         if (player->not_supported_codec) {
9770                 if (player->can_support_codec) {
9771                         // There is one codec to play
9772                         post_msg_direct = TRUE;
9773                 } else {
9774                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9775                                 post_msg_direct = TRUE;
9776                 }
9777
9778                 if (post_msg_direct) {
9779                         MMMessageParamType msg_param;
9780                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9781
9782                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9783                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9784
9785                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9786                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9787                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9788                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9789
9790                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9791                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9792                         }
9793
9794                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9795
9796                         MMPLAYER_FREEIF(msg_param.data);
9797
9798                         return MM_ERROR_NONE;
9799                 } else {
9800                         // no any supported codec case
9801                         LOGW("not found any codec, posting error code to application.\n");
9802
9803                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9804                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9805                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9806                         } else {
9807                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9808                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9809                         }
9810
9811                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9812
9813                         MMPLAYER_FREEIF(msg_param.data);
9814                 }
9815         }
9816
9817         MMPLAYER_FLEAVE();
9818
9819         return MM_ERROR_NONE;
9820 }
9821
9822 static void __mmplayer_check_pipeline(mm_player_t* player)
9823 {
9824         GstState element_state = GST_STATE_VOID_PENDING;
9825         GstState element_pending_state = GST_STATE_VOID_PENDING;
9826         gint timeout = 0;
9827         int ret = MM_ERROR_NONE;
9828
9829         if (player->gapless.reconfigure) {
9830                 LOGW("pipeline is under construction.\n");
9831
9832                 MMPLAYER_PLAYBACK_LOCK(player);
9833                 MMPLAYER_PLAYBACK_UNLOCK(player);
9834
9835                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9836
9837                 /* wait for state transition */
9838                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9839
9840                 if (ret == GST_STATE_CHANGE_FAILURE)
9841                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9842         }
9843 }
9844
9845 /* NOTE : it should be able to call 'stop' anytime*/
9846 int
9847 _mmplayer_stop(MMHandleType hplayer)
9848 {
9849         mm_player_t* player = (mm_player_t*)hplayer;
9850         int ret = MM_ERROR_NONE;
9851
9852         MMPLAYER_FENTER();
9853
9854         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9855
9856         /* check current state */
9857         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9858
9859         /* check pipline building state */
9860         __mmplayer_check_pipeline(player);
9861         __mmplayer_reset_gapless_state(player);
9862
9863         /* NOTE : application should not wait for EOS after calling STOP */
9864         __mmplayer_cancel_eos_timer(player);
9865
9866         __mmplayer_unrealize_streaming_ext(player);
9867
9868         /* reset */
9869         player->doing_seek = FALSE;
9870
9871         /* stop pipeline */
9872         ret = __gst_stop(player);
9873
9874         if (ret != MM_ERROR_NONE)
9875                 LOGE("failed to stop player.\n");
9876
9877         MMPLAYER_FLEAVE();
9878
9879         return ret;
9880 }
9881
9882 int
9883 _mmplayer_pause(MMHandleType hplayer)
9884 {
9885         mm_player_t* player = (mm_player_t*)hplayer;
9886         gint64 pos_msec = 0;
9887         gboolean async = FALSE;
9888         gint ret = MM_ERROR_NONE;
9889
9890         MMPLAYER_FENTER();
9891
9892         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9893
9894         /* check current state */
9895         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9896
9897         /* check pipline building state */
9898         __mmplayer_check_pipeline(player);
9899
9900         switch (MMPLAYER_CURRENT_STATE(player)) {
9901         case MM_PLAYER_STATE_READY:
9902                 {
9903                         /* check prepare async or not.
9904                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9905                          */
9906                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9907                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9908
9909                         /* Changing back sync of rtspsrc to async */
9910                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9911                                 LOGD("async prepare working mode for rtsp");
9912                                 async = TRUE;
9913                         }
9914                 }
9915                 break;
9916
9917         case MM_PLAYER_STATE_PLAYING:
9918                 {
9919                         /* NOTE : store current point to overcome some bad operation
9920                         *(returning zero when getting current position in paused state) of some
9921                         * elements
9922                         */
9923                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9924                                 LOGW("getting current position failed in paused\n");
9925
9926                         player->last_position = pos_msec;
9927
9928                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9929                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9930                            This causes problem is position calculation during normal pause resume scenarios also.
9931                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9932                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9933                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9934                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9935                         }
9936                 }
9937                 break;
9938         }
9939
9940         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9941                 LOGD("doing async pause in case of ms buff src");
9942                 async = TRUE;
9943         }
9944
9945         /* pause pipeline */
9946         ret = __gst_pause(player, async);
9947
9948         if (ret != MM_ERROR_NONE)
9949                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9950
9951         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9952                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9953                         LOGE("failed to update display_rotation");
9954         }
9955
9956         MMPLAYER_FLEAVE();
9957
9958         return ret;
9959 }
9960
9961 int
9962 _mmplayer_resume(MMHandleType hplayer)
9963 {
9964         mm_player_t* player = (mm_player_t*)hplayer;
9965         int ret = MM_ERROR_NONE;
9966         gboolean async = FALSE;
9967
9968         MMPLAYER_FENTER();
9969
9970         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9971
9972         /* Changing back sync mode rtspsrc to async */
9973         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9974                 LOGD("async resume for rtsp case");
9975                 async = TRUE;
9976         }
9977
9978         /* check current state */
9979         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9980
9981         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9982         if (ret != MM_ERROR_NONE) {
9983                 LOGE("failed to acquire sound focus.\n");
9984                 return ret;
9985         }
9986
9987         ret = __gst_resume(player, async);
9988
9989         if (ret != MM_ERROR_NONE)
9990                 LOGE("failed to resume player.\n");
9991
9992         MMPLAYER_FLEAVE();
9993
9994         return ret;
9995 }
9996
9997 int
9998 __mmplayer_set_play_count(mm_player_t* player, gint count)
9999 {
10000         MMHandleType attrs = 0;
10001
10002         MMPLAYER_FENTER();
10003
10004         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10005
10006         attrs =  MMPLAYER_GET_ATTRS(player);
10007         if (!attrs) {
10008                 LOGE("fail to get attributes.\n");
10009                 return MM_ERROR_PLAYER_INTERNAL;
10010         }
10011
10012         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10013         if (mmf_attrs_commit(attrs)) /* return -1 if error */
10014                 LOGE("failed to commit\n");
10015
10016         MMPLAYER_FLEAVE();
10017
10018         return  MM_ERROR_NONE;
10019 }
10020
10021 int
10022 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
10023 {
10024         mm_player_t* player = (mm_player_t*)hplayer;
10025         gint64 start_pos = 0;
10026         gint64 end_pos = 0;
10027         gint infinity = -1;
10028
10029         MMPLAYER_FENTER();
10030
10031         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10032         MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
10033
10034         player->section_repeat = TRUE;
10035         player->section_repeat_start = start;
10036         player->section_repeat_end = end;
10037
10038         start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
10039         end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
10040
10041         __mmplayer_set_play_count(player, infinity);
10042
10043         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10044                                         player->playback_rate,
10045                                         GST_FORMAT_TIME,
10046                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10047                                         GST_SEEK_TYPE_SET, start_pos,
10048                                         GST_SEEK_TYPE_SET, end_pos))) {
10049                 LOGE("failed to activate section repeat\n");
10050
10051                 return MM_ERROR_PLAYER_SEEK;
10052         }
10053
10054         LOGD("succeeded to set section repeat from %d to %d\n",
10055                 player->section_repeat_start, player->section_repeat_end);
10056
10057         MMPLAYER_FLEAVE();
10058
10059         return  MM_ERROR_NONE;
10060 }
10061
10062 static int
10063 __mmplayer_set_pcm_extraction(mm_player_t* player)
10064 {
10065         gint64 start_nsec = 0;
10066         gint64 end_nsec = 0;
10067         gint64 dur_nsec = 0;
10068         gint64 dur_msec = 0;
10069         int required_start = 0;
10070         int required_end = 0;
10071         int ret = 0;
10072
10073         MMPLAYER_FENTER();
10074
10075         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10076
10077         mm_attrs_multiple_get(player->attrs,
10078                 NULL,
10079                 "pcm_extraction_start_msec", &required_start,
10080                 "pcm_extraction_end_msec", &required_end,
10081                 NULL);
10082
10083         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
10084
10085         if (required_start == 0 && required_end == 0) {
10086                 LOGD("extracting entire stream");
10087                 return MM_ERROR_NONE;
10088         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
10089                 LOGD("invalid range for pcm extraction");
10090                 return MM_ERROR_INVALID_ARGUMENT;
10091         }
10092
10093         /* get duration */
10094         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
10095         if (!ret) {
10096                 LOGE("failed to get duration");
10097                 return MM_ERROR_PLAYER_INTERNAL;
10098         }
10099         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
10100
10101         if (dur_msec < required_end) {
10102                 // FIXME
10103                 LOGD("invalid end pos for pcm extraction");
10104                 return MM_ERROR_INVALID_ARGUMENT;
10105         }
10106
10107         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
10108         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
10109
10110         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10111                                         1.0,
10112                                         GST_FORMAT_TIME,
10113                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10114                                         GST_SEEK_TYPE_SET, start_nsec,
10115                                         GST_SEEK_TYPE_SET, end_nsec))) {
10116                 LOGE("failed to seek for pcm extraction\n");
10117
10118                 return MM_ERROR_PLAYER_SEEK;
10119         }
10120
10121         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
10122
10123         MMPLAYER_FLEAVE();
10124
10125         return MM_ERROR_NONE;
10126 }
10127
10128 int
10129 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
10130 {
10131         mm_player_t* player = (mm_player_t*)hplayer;
10132         gint64 cur_pos = 0;
10133         gint onetime = 1;
10134
10135         MMPLAYER_FENTER();
10136
10137         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10138
10139         player->section_repeat = FALSE;
10140
10141         __mmplayer_set_play_count(player, onetime);
10142
10143         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
10144
10145         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10146                                         1.0,
10147                                         GST_FORMAT_TIME,
10148                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10149                                         GST_SEEK_TYPE_SET, cur_pos,
10150                                         GST_SEEK_TYPE_SET, player->duration))) {
10151                 LOGE("failed to deactivate section repeat\n");
10152
10153                 return MM_ERROR_PLAYER_SEEK;
10154         }
10155
10156         MMPLAYER_FENTER();
10157
10158         return MM_ERROR_NONE;
10159 }
10160
10161 int
10162 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
10163 {
10164         mm_player_t* player = (mm_player_t*)hplayer;
10165         gint64 pos_msec = 0;
10166         int ret = MM_ERROR_NONE;
10167         int mute = FALSE;
10168         signed long long start = 0, stop = 0;
10169         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10170         MMPLAYER_FENTER();
10171
10172         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10173         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
10174
10175         /* The sound of video is not supported under 0.0 and over 2.0. */
10176         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
10177                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10178                         mute = TRUE;
10179         }
10180         _mmplayer_set_mute(hplayer, mute);
10181
10182         if (player->playback_rate == rate)
10183                 return MM_ERROR_NONE;
10184
10185         /* If the position is reached at start potion during fast backward, EOS is posted.
10186          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10187          * */
10188         player->playback_rate = rate;
10189
10190         current_state = MMPLAYER_CURRENT_STATE(player);
10191
10192         if (current_state != MM_PLAYER_STATE_PAUSED)
10193                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10194
10195         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
10196
10197         if ((current_state == MM_PLAYER_STATE_PAUSED)
10198                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
10199                 LOGW("returning last point : %lld\n", player->last_position);
10200                 pos_msec = player->last_position;
10201         }
10202
10203         if (rate >= 0) {
10204                 start = pos_msec;
10205                 stop = GST_CLOCK_TIME_NONE;
10206         } else {
10207                 start = GST_CLOCK_TIME_NONE;
10208                 stop = pos_msec;
10209         }
10210
10211         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10212                                 player->playback_rate,
10213                                 GST_FORMAT_TIME,
10214                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10215                                 GST_SEEK_TYPE_SET, start,
10216                                 GST_SEEK_TYPE_SET, stop)) {
10217                 LOGE("failed to set speed playback\n");
10218                 return MM_ERROR_PLAYER_SEEK;
10219         }
10220
10221         LOGD("succeeded to set speed playback as %0.1f\n", rate);
10222
10223         MMPLAYER_FLEAVE();
10224
10225         return MM_ERROR_NONE;;
10226 }
10227
10228 int
10229 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
10230 {
10231         mm_player_t* player = (mm_player_t*)hplayer;
10232         int ret = MM_ERROR_NONE;
10233
10234         MMPLAYER_FENTER();
10235
10236         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10237
10238         /* check pipline building state */
10239         __mmplayer_check_pipeline(player);
10240
10241         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10242
10243         MMPLAYER_FLEAVE();
10244
10245         return ret;
10246 }
10247
10248 int
10249 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
10250 {
10251         mm_player_t* player = (mm_player_t*)hplayer;
10252         int ret = MM_ERROR_NONE;
10253
10254         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10255
10256         ret = __gst_get_position(player, format, position);
10257
10258         return ret;
10259 }
10260
10261 int
10262 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
10263 {
10264         mm_player_t* player = (mm_player_t*)hplayer;
10265         int ret = MM_ERROR_NONE;
10266
10267         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10268
10269         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10270
10271         return ret;
10272 }
10273
10274 int
10275 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
10276 {
10277         mm_player_t* player = (mm_player_t*)hplayer;
10278         int ret = MM_ERROR_NONE;
10279
10280         MMPLAYER_FENTER();
10281
10282         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10283
10284         ret = __gst_adjust_subtitle_position(player, format, position);
10285
10286         MMPLAYER_FLEAVE();
10287
10288         return ret;
10289 }
10290 int
10291 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
10292 {
10293         mm_player_t* player = (mm_player_t*)hplayer;
10294         int ret = MM_ERROR_NONE;
10295
10296         MMPLAYER_FENTER();
10297
10298         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10299
10300         ret = __gst_adjust_video_position(player, offset);
10301
10302         MMPLAYER_FLEAVE();
10303
10304         return ret;
10305 }
10306
10307 static gboolean
10308 __mmplayer_is_midi_type(gchar* str_caps)
10309 {
10310         if ((g_strrstr(str_caps, "audio/midi")) ||
10311                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10312                 (g_strrstr(str_caps, "application/x-smaf")) ||
10313                 (g_strrstr(str_caps, "audio/x-imelody")) ||
10314                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10315                 (g_strrstr(str_caps, "audio/xmf")) ||
10316                 (g_strrstr(str_caps, "audio/mxmf"))) {
10317                 LOGD("midi\n");
10318                 return TRUE;
10319         }
10320
10321         return FALSE;
10322 }
10323
10324 static gboolean
10325 __mmplayer_is_only_mp3_type(gchar *str_caps)
10326 {
10327         if (g_strrstr(str_caps, "application/x-id3") ||
10328                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10329                 return TRUE;
10330         return FALSE;
10331 }
10332
10333 static void
10334 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10335 {
10336         GstStructure* caps_structure = NULL;
10337         gint samplerate = 0;
10338         gint channels = 0;
10339
10340         MMPLAYER_FENTER();
10341         MMPLAYER_RETURN_IF_FAIL(player && caps);
10342
10343         caps_structure = gst_caps_get_structure(caps, 0);
10344
10345         /* set stream information */
10346         gst_structure_get_int(caps_structure, "rate", &samplerate);
10347         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10348
10349         gst_structure_get_int(caps_structure, "channels", &channels);
10350         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10351
10352         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
10353 }
10354
10355 static void
10356 __mmplayer_update_content_type_info(mm_player_t* player)
10357 {
10358         MMPLAYER_FENTER();
10359         MMPLAYER_RETURN_IF_FAIL(player && player->type);
10360
10361         if (__mmplayer_is_midi_type(player->type)) {
10362                 player->bypass_audio_effect = TRUE;
10363         } else if (g_strrstr(player->type, "application/x-hls")) {
10364                 /* If it can't know exact type when it parses uri because of redirection case,
10365                  * it will be fixed by typefinder or when doing autoplugging.
10366                  */
10367                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10368                 if (player->streamer) {
10369                         player->streamer->is_adaptive_streaming = TRUE;
10370                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10371                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
10372                 }
10373         } else if (g_strrstr(player->type, "application/dash+xml")) {
10374                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10375         }
10376
10377         MMPLAYER_FLEAVE();
10378 }
10379
10380 static void
10381 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
10382 GstCaps *caps, gpointer data)
10383 {
10384         mm_player_t* player = (mm_player_t*)data;
10385         GstPad* pad = NULL;
10386
10387         MMPLAYER_FENTER();
10388
10389         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10390
10391         /* store type string */
10392         MMPLAYER_FREEIF(player->type);
10393         player->type = gst_caps_to_string(caps);
10394         if (player->type) {
10395                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
10396                                 player, player->type, probability, gst_caps_get_size(caps));
10397         }
10398
10399         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10400                 (g_strrstr(player->type, "audio/x-raw-int"))) {
10401                 LOGE("not support media format\n");
10402
10403                 if (player->msg_posted == FALSE) {
10404                         MMMessageParamType msg_param;
10405                         memset(&msg_param, 0, sizeof(MMMessageParamType));
10406
10407                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10408                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10409
10410                         /* don't post more if one was sent already */
10411                         player->msg_posted = TRUE;
10412                 }
10413                 return;
10414         }
10415
10416         __mmplayer_update_content_type_info(player);
10417
10418         pad = gst_element_get_static_pad(tf, "src");
10419         if (!pad) {
10420                 LOGE("fail to get typefind src pad.\n");
10421                 return;
10422         }
10423
10424         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10425                 gboolean async = FALSE;
10426                 LOGE("failed to autoplug %s\n", player->type);
10427
10428                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10429
10430                 if (async && player->msg_posted == FALSE)
10431                         __mmplayer_handle_missed_plugin(player);
10432
10433                 goto DONE;
10434         }
10435
10436 DONE:
10437         gst_object_unref(GST_OBJECT(pad));
10438
10439         MMPLAYER_FLEAVE();
10440
10441         return;
10442 }
10443
10444 static GstElement *
10445 __mmplayer_create_decodebin(mm_player_t* player)
10446 {
10447         GstElement *decodebin = NULL;
10448
10449         MMPLAYER_FENTER();
10450
10451         /* create decodebin */
10452         decodebin = gst_element_factory_make("decodebin", NULL);
10453
10454         if (!decodebin) {
10455                 LOGE("fail to create decodebin\n");
10456                 goto ERROR;
10457         }
10458
10459         /* raw pad handling signal */
10460         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10461                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10462
10463         /* no-more-pad pad handling signal */
10464         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10465                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10466
10467         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10468                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10469
10470         /* This signal is emitted when a pad for which there is no further possible
10471            decoding is added to the decodebin.*/
10472         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10473                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10474
10475         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10476            before looking for any elements that can handle that stream.*/
10477         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10478                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10479
10480         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10481            before looking for any elements that can handle that stream.*/
10482         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10483                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10484
10485         /* This signal is emitted once decodebin has finished decoding all the data.*/
10486         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10487                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10488
10489         /* This signal is emitted when a element is added to the bin.*/
10490         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10491                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
10492
10493 ERROR:
10494         return decodebin;
10495 }
10496
10497 static gboolean
10498 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10499 {
10500         MMPlayerGstElement* mainbin = NULL;
10501         GstElement* decodebin = NULL;
10502         GstElement* queue2 = NULL;
10503         GstPad* sinkpad = NULL;
10504         GstPad* qsrcpad = NULL;
10505         gint64 dur_bytes = 0L;
10506
10507         guint max_buffer_size_bytes = 0;
10508         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
10509
10510         MMPLAYER_FENTER();
10511         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10512
10513         mainbin = player->pipeline->mainbin;
10514
10515         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10516                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10517                 LOGD("creating http streaming buffering queue(queue2)\n");
10518
10519                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10520                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10521                 } else {
10522                         queue2 = gst_element_factory_make("queue2", "queue2");
10523                         if (!queue2) {
10524                                 LOGE("failed to create buffering queue element\n");
10525                                 goto ERROR;
10526                         }
10527
10528                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10529                                 LOGE("failed to add buffering queue\n");
10530                                 goto ERROR;
10531                         }
10532
10533                         sinkpad = gst_element_get_static_pad(queue2, "sink");
10534                         qsrcpad = gst_element_get_static_pad(queue2, "src");
10535
10536                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10537                                 LOGE("failed to link buffering queue\n");
10538                                 goto ERROR;
10539                         }
10540
10541                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10542                                 LOGE("fail to get duration.\n");
10543
10544                         LOGD("dur_bytes = %lld\n", dur_bytes);
10545
10546                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10547
10548                         if (dur_bytes > 0) {
10549                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10550                                         type = MUXED_BUFFER_TYPE_FILE;
10551                                 } else {
10552                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10553                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10554                                 }
10555                         } else {
10556                                 dur_bytes = 0;
10557                         }
10558
10559                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
10560                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10561                         if (!g_strrstr(player->type, "video/mpegts")) {
10562                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10563                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10564
10565                                 // FIXME : pass ini setting directly. is this ok?
10566                                 __mm_player_streaming_set_queue2(player->streamer,
10567                                                                                                 queue2,
10568                                                                                                 FALSE,
10569                                                                                                 max_buffer_size_bytes,
10570                                                                                                 player->ini.http_buffering_time,
10571                                                                                                 1.0,                                                            // no meaning
10572                                                                                                 player->ini.http_buffering_limit,       // no meaning
10573                                                                                                 type,
10574                                                                                                 player->http_file_buffering_path,
10575                                                                                                 (guint64)dur_bytes);
10576                         }
10577
10578                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10579                                 LOGE("failed to sync queue2 state with parent\n");
10580                                 goto ERROR;
10581                         }
10582
10583                         srcpad = qsrcpad;
10584
10585                         gst_object_unref(GST_OBJECT(sinkpad));
10586
10587                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10588                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10589                 }
10590         }
10591
10592         /* create decodebin */
10593         decodebin = __mmplayer_create_decodebin(player);
10594
10595         if (!decodebin) {
10596                 LOGE("can not create autoplug element\n");
10597                 goto ERROR;
10598         }
10599
10600         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10601                 LOGE("failed to add decodebin\n");
10602                 goto ERROR;
10603         }
10604
10605         /* to force caps on the decodebin element and avoid reparsing stuff by
10606         * typefind. It also avoids a deadlock in the way typefind activates pads in
10607         * the state change */
10608         g_object_set(decodebin, "sink-caps", caps, NULL);
10609
10610         sinkpad = gst_element_get_static_pad(decodebin, "sink");
10611
10612         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10613                 LOGE("failed to link decodebin\n");
10614                 goto ERROR;
10615         }
10616
10617         gst_object_unref(GST_OBJECT(sinkpad));
10618
10619         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10620         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10621
10622         /* set decodebin property about buffer in streaming playback. *
10623          * in case of HLS/DASH, it does not need to have big buffer        *
10624          * because it is kind of adaptive streaming.                  */
10625         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
10626                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10627                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10628                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10629
10630                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
10631                         || MMPLAYER_IS_DASH_STREAMING(player)) {
10632                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10633                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10634                 }
10635
10636                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10637                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
10638                                                                                         "low-percent", 1,   // 1%
10639                                                                                         "max-size-bytes", max_size_bytes,
10640                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
10641                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
10642         }
10643
10644         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10645                 LOGE("failed to sync decodebin state with parent\n");
10646                 goto ERROR;
10647         }
10648
10649         MMPLAYER_FLEAVE();
10650
10651         return TRUE;
10652
10653 ERROR:
10654
10655         if (sinkpad)
10656                 gst_object_unref(GST_OBJECT(sinkpad));
10657
10658         if (queue2) {
10659                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10660                  * You need to explicitly set elements to the NULL state before
10661                  * dropping the final reference, to allow them to clean up.
10662                  */
10663                 gst_element_set_state(queue2, GST_STATE_NULL);
10664
10665                 /* And, it still has a parent "player".
10666                  * You need to let the parent manage the object instead of unreffing the object directly.
10667                  */
10668                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10669                 gst_object_unref(queue2);
10670                 queue2 = NULL;
10671         }
10672
10673         if (decodebin) {
10674                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10675                  * You need to explicitly set elements to the NULL state before
10676                  * dropping the final reference, to allow them to clean up.
10677                  */
10678                 gst_element_set_state(decodebin, GST_STATE_NULL);
10679
10680                 /* And, it still has a parent "player".
10681                  * You need to let the parent manage the object instead of unreffing the object directly.
10682                  */
10683
10684                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10685                 gst_object_unref(decodebin);
10686                 decodebin = NULL;
10687         }
10688
10689         return FALSE;
10690 }
10691
10692 static int
10693 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10694 {
10695         MMPLAYER_FENTER();
10696
10697         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10698         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10699
10700         LOGD("class : %s, mime : %s \n", factory_class, mime);
10701
10702         /* add missing plugin */
10703         /* NOTE : msl should check missing plugin for image mime type.
10704          * Some motion jpeg clips can have playable audio track.
10705          * So, msl have to play audio after displaying popup written video format not supported.
10706          */
10707         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10708                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10709                         LOGD("not found demuxer\n");
10710                         player->not_found_demuxer = TRUE;
10711                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10712
10713                         goto DONE;
10714                 }
10715         }
10716
10717         if (!g_strrstr(factory_class, "Demuxer")) {
10718                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10719                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10720                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10721
10722                         /* check that clip have multi tracks or not */
10723                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10724                                 LOGD("video plugin is already linked\n");
10725                         } else {
10726                                 LOGW("add VIDEO to missing plugin\n");
10727                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10728                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10729                         }
10730                 } else if (g_str_has_prefix(mime, "audio")) {
10731                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10732                                 LOGD("audio plugin is already linked\n");
10733                         } else {
10734                                 LOGW("add AUDIO to missing plugin\n");
10735                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10736                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10737                         }
10738                 }
10739         }
10740
10741 DONE:
10742         MMPLAYER_FLEAVE();
10743
10744         return MM_ERROR_NONE;
10745 }
10746
10747
10748 static void
10749 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10750 {
10751         mm_player_t* player = (mm_player_t*)data;
10752
10753         MMPLAYER_FENTER();
10754
10755         MMPLAYER_RETURN_IF_FAIL(player);
10756
10757         /* remove fakesink. */
10758         if (!__mmplayer_gst_remove_fakesink(player,
10759                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10760                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10761                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10762                  * source element are not same. To overcome this situation, this function will called
10763                  * several places and several times. Therefore, this is not an error case.
10764                  */
10765                 return;
10766         }
10767
10768         LOGD("[handle: %p] pipeline has completely constructed", player);
10769
10770         if ((player->ini.async_start) &&
10771                 (player->msg_posted == FALSE) &&
10772                 (player->cmd >= MMPLAYER_COMMAND_START))
10773                 __mmplayer_handle_missed_plugin(player);
10774
10775         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10776 }
10777
10778 static gboolean
10779 __mmplayer_verify_next_play_path(mm_player_t *player)
10780 {
10781         MMHandleType attrs = 0;
10782         MMPlayerParseProfile profile;
10783         gint uri_idx = 0, check_cnt = 0;
10784         char *uri = NULL;
10785         gint mode = MM_PLAYER_PD_MODE_NONE;
10786         gint video = 0;
10787         gint count = 0;
10788         gint gapless = 0;
10789         guint num_of_list = 0;
10790         static int profile_tv = -1;
10791
10792         MMPLAYER_FENTER();
10793
10794         LOGD("checking for gapless play");
10795
10796         if (player->pipeline->textbin) {
10797                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10798                 goto ERROR;
10799         }
10800
10801         attrs = MMPLAYER_GET_ATTRS(player);
10802         if (!attrs) {
10803                 LOGE("fail to get attributes.\n");
10804                 goto ERROR;
10805         }
10806
10807         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10808
10809         if (__builtin_expect(profile_tv == -1, 0)) {
10810                 char *profileName;
10811                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10812                 switch (*profileName) {
10813                 case 't':
10814                 case 'T':
10815                         profile_tv = 1;
10816                         break;
10817                 default:
10818                         profile_tv = 0;
10819                 }
10820                 free(profileName);
10821         }
10822         /* gapless playback is not supported in case of video at TV profile. */
10823         if (profile_tv && video) {
10824                 LOGW("not support video gapless playback");
10825                 goto ERROR;
10826         }
10827
10828         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10829                 if (mode == TRUE) {
10830                         LOGW("pd mode\n");
10831                         goto ERROR;
10832                 }
10833         }
10834
10835         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10836                 LOGE("can not get play count\n");
10837
10838         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10839                 LOGE("can not get gapless mode\n");
10840
10841         if (video && !gapless) {
10842                 LOGW("not enabled video gapless playback");
10843                 goto ERROR;
10844         }
10845
10846         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10847                 gapless = 1;
10848
10849         if (!gapless) {
10850                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10851                 goto ERROR;
10852         }
10853
10854         num_of_list = g_list_length(player->uri_info.uri_list);
10855
10856         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10857
10858         if (num_of_list == 0) {
10859                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10860                         LOGE("can not get profile_uri\n");
10861                         goto ERROR;
10862                 }
10863
10864                 if (!uri) {
10865                         LOGE("uri list is empty.\n");
10866                         goto ERROR;
10867                 }
10868
10869                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10870                 LOGD("add original path : %s ", uri);
10871
10872                 num_of_list = 1;
10873                 uri = NULL;
10874         }
10875
10876         uri_idx = player->uri_info.uri_idx;
10877
10878         while (TRUE) {
10879                 check_cnt++;
10880
10881                 if (check_cnt > num_of_list) {
10882                         LOGE("there is no valid uri.");
10883                         goto ERROR;
10884                 }
10885
10886                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10887
10888                 if (uri_idx < num_of_list-1) {
10889                         uri_idx++;
10890                 } else {
10891                         if ((count <= 1) && (count != -1)) {
10892                                 LOGD("no repeat.");
10893                                 goto ERROR;
10894                         } else if (count > 1) {
10895                                 /* decrease play count */
10896                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10897                                 count--;
10898
10899                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10900
10901                                 /* commit attribute */
10902                                 if (mmf_attrs_commit(attrs))
10903                                         LOGE("failed to commit attribute\n");
10904                         }
10905
10906                         /* count < 0 : repeat continually */
10907                         uri_idx = 0;
10908                 }
10909
10910                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10911                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10912
10913                 if (uri == NULL) {
10914                         LOGW("next uri does not exist\n");
10915                         continue;
10916                 }
10917
10918                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10919                         LOGE("failed to parse profile\n");
10920                         continue;
10921                 }
10922
10923                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10924                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10925                         LOGW("uri type is not supported(%d).", profile.uri_type);
10926                         continue;
10927                 }
10928
10929                 break;
10930         }
10931
10932         player->uri_info.uri_idx = uri_idx;
10933         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10934
10935         if (mmf_attrs_commit(player->attrs)) {
10936                 LOGE("failed to commit.\n");
10937                 goto ERROR;
10938         }
10939
10940         LOGD("next uri %s(%d)\n", uri, uri_idx);
10941
10942         return TRUE;
10943
10944 ERROR:
10945
10946         LOGE("unable to play next path. EOS will be posted soon.\n");
10947         return FALSE;
10948 }
10949
10950 static void
10951 __mmplayer_initialize_next_play(mm_player_t *player)
10952 {
10953         int i;
10954
10955         MMPLAYER_FENTER();
10956
10957         player->smooth_streaming = FALSE;
10958         player->videodec_linked = 0;
10959         player->audiodec_linked = 0;
10960         player->videosink_linked = 0;
10961         player->audiosink_linked = 0;
10962         player->textsink_linked = 0;
10963         player->is_external_subtitle_present = FALSE;
10964         player->is_external_subtitle_added_now = FALSE;
10965         player->not_supported_codec = MISSING_PLUGIN_NONE;
10966         player->can_support_codec = FOUND_PLUGIN_NONE;
10967         player->pending_seek.is_pending = FALSE;
10968         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10969         player->pending_seek.pos = 0;
10970         player->msg_posted = FALSE;
10971         player->has_many_types = FALSE;
10972         player->no_more_pad = FALSE;
10973         player->not_found_demuxer = 0;
10974         player->doing_seek = FALSE;
10975         player->max_audio_channels = 0;
10976         player->is_subtitle_force_drop = FALSE;
10977         player->play_subtitle = FALSE;
10978         player->adjust_subtitle_pos = 0;
10979
10980         player->total_bitrate = 0;
10981         player->total_maximum_bitrate = 0;
10982
10983         _mmplayer_track_initialize(player);
10984         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10985
10986         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10987                 player->bitrate[i] = 0;
10988                 player->maximum_bitrate[i] = 0;
10989         }
10990
10991         if (player->v_stream_caps) {
10992                 gst_caps_unref(player->v_stream_caps);
10993                 player->v_stream_caps = NULL;
10994         }
10995
10996         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10997         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
10998
10999         /* clean found parsers */
11000         if (player->parsers) {
11001                 GList *parsers = player->parsers;
11002                 for (; parsers; parsers = g_list_next(parsers)) {
11003                         gchar *name = parsers->data;
11004                         MMPLAYER_FREEIF(name);
11005                 }
11006                 g_list_free(player->parsers);
11007                 player->parsers = NULL;
11008         }
11009
11010         /* clean found audio decoders */
11011         if (player->audio_decoders) {
11012                 GList *a_dec = player->audio_decoders;
11013                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11014                         gchar *name = a_dec->data;
11015                         MMPLAYER_FREEIF(name);
11016                 }
11017                 g_list_free(player->audio_decoders);
11018                 player->audio_decoders = NULL;
11019         }
11020
11021         MMPLAYER_FLEAVE();
11022 }
11023
11024 static void
11025 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11026 {
11027         MMPlayerGstElement *mainbin = NULL;
11028         MMMessageParamType msg_param = {0,};
11029         GstElement *element = NULL;
11030         MMHandleType attrs = 0;
11031         char *uri = NULL;
11032         enum MainElementID elemId = MMPLAYER_M_NUM;
11033
11034         MMPLAYER_FENTER();
11035
11036         if ((player == NULL) ||
11037                 (player->pipeline == NULL) ||
11038                 (player->pipeline->mainbin == NULL)) {
11039                 LOGE("player is null.\n");
11040                 goto ERROR;
11041         }
11042
11043         mainbin = player->pipeline->mainbin;
11044         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11045
11046         attrs = MMPLAYER_GET_ATTRS(player);
11047         if (!attrs) {
11048                 LOGE("fail to get attributes.\n");
11049                 goto ERROR;
11050         }
11051
11052         /* Initialize Player values */
11053         __mmplayer_initialize_next_play(player);
11054
11055         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11056
11057         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11058                 LOGE("failed to parse profile\n");
11059                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11060                 goto ERROR;
11061         }
11062
11063         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11064                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11065                 LOGE("it's dash or hls. not support.");
11066                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11067                 goto ERROR;
11068         }
11069
11070         /* setup source */
11071         switch (player->profile.uri_type) {
11072         /* file source */
11073         case MM_PLAYER_URI_TYPE_FILE:
11074         {
11075                 LOGD("using filesrc for 'file://' handler.\n");
11076                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
11077                         LOGE("failed to get storage info");
11078                         break;
11079                 }
11080
11081                 element = gst_element_factory_make("filesrc", "source");
11082
11083                 if (!element) {
11084                         LOGE("failed to create filesrc\n");
11085                         break;
11086                 }
11087
11088                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
11089                 break;
11090         }
11091         case MM_PLAYER_URI_TYPE_URL_HTTP:
11092         {
11093                 gchar *user_agent, *proxy, *cookies, **cookie_list;
11094                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11095                 user_agent = proxy = cookies = NULL;
11096                 cookie_list = NULL;
11097
11098                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11099                 if (!element) {
11100                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11101                         break;
11102                 }
11103                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11104
11105                 /* get attribute */
11106                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11107                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11108                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11109                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11110
11111                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11112                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11113                         LOGD("get timeout from ini\n");
11114                         http_timeout = player->ini.http_timeout;
11115                 }
11116
11117                 /* get attribute */
11118                 SECURE_LOGD("location : %s\n", player->profile.uri);
11119                 SECURE_LOGD("cookies : %s\n", cookies);
11120                 SECURE_LOGD("proxy : %s\n", proxy);
11121                 SECURE_LOGD("user_agent :  %s\n", user_agent);
11122                 LOGD("timeout : %d\n", http_timeout);
11123
11124                 /* setting property to streaming source */
11125                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11126                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11127                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11128
11129                 /* check if prosy is vailid or not */
11130                 if (util_check_valid_url(proxy))
11131                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11132                 /* parsing cookies */
11133                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11134                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11135                 if (user_agent)
11136                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11137                 break;
11138         }
11139         default:
11140                 LOGE("not support uri type %d\n", player->profile.uri_type);
11141                 break;
11142         }
11143
11144         if (!element) {
11145                 LOGE("no source element was created.\n");
11146                 goto ERROR;
11147         }
11148
11149         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11150                 LOGE("failed to add source element to pipeline\n");
11151                 gst_object_unref(GST_OBJECT(element));
11152                 element = NULL;
11153                 goto ERROR;
11154         }
11155
11156         /* take source element */
11157         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11158         mainbin[MMPLAYER_M_SRC].gst = element;
11159
11160         element = NULL;
11161
11162         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11163                 if (player->streamer == NULL) {
11164                         player->streamer = __mm_player_streaming_create();
11165                         __mm_player_streaming_initialize(player->streamer);
11166                 }
11167
11168                 elemId = MMPLAYER_M_TYPEFIND;
11169                 element = gst_element_factory_make("typefind", "typefinder");
11170                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11171                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11172         } else {
11173                 elemId = MMPLAYER_M_AUTOPLUG;
11174                 element = __mmplayer_create_decodebin(player);
11175         }
11176
11177         /* check autoplug element is OK */
11178         if (!element) {
11179                 LOGE("can not create element(%d)\n", elemId);
11180                 goto ERROR;
11181         }
11182
11183         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11184                 LOGE("failed to add sinkbin to pipeline\n");
11185                 gst_object_unref(GST_OBJECT(element));
11186                 element = NULL;
11187                 goto ERROR;
11188         }
11189
11190         mainbin[elemId].id = elemId;
11191         mainbin[elemId].gst = element;
11192
11193         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11194                 LOGE("Failed to link src - autoplug(or typefind)\n");
11195                 goto ERROR;
11196         }
11197
11198         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11199                 LOGE("Failed to change state of src element\n");
11200                 goto ERROR;
11201         }
11202
11203         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11204                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11205                         LOGE("Failed to change state of decodebin\n");
11206                         goto ERROR;
11207                 }
11208         } else {
11209                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11210                         LOGE("Failed to change state of src element\n");
11211                         goto ERROR;
11212                 }
11213         }
11214
11215         player->gapless.stream_changed = TRUE;
11216         player->gapless.running = TRUE;
11217         MMPLAYER_FLEAVE();
11218         return;
11219
11220 ERROR:
11221         if (player) {
11222                 MMPLAYER_PLAYBACK_UNLOCK(player);
11223
11224                 if (!player->msg_posted) {
11225                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11226                         player->msg_posted = TRUE;
11227                 }
11228         }
11229         return;
11230 }
11231
11232 static gboolean
11233 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11234 {
11235         mm_player_selector_t *selector = &player->selector[type];
11236         MMPlayerGstElement *sinkbin = NULL;
11237         enum MainElementID selectorId = MMPLAYER_M_NUM;
11238         enum MainElementID sinkId = MMPLAYER_M_NUM;
11239         GstPad *srcpad = NULL;
11240         GstPad *sinkpad = NULL;
11241         gboolean send_notice = FALSE;
11242
11243         MMPLAYER_FENTER();
11244         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11245
11246         LOGD("type %d", type);
11247
11248         switch (type) {
11249         case MM_PLAYER_TRACK_TYPE_AUDIO:
11250                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11251                 sinkId = MMPLAYER_A_BIN;
11252                 sinkbin = player->pipeline->audiobin;
11253                 break;
11254         case MM_PLAYER_TRACK_TYPE_VIDEO:
11255                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11256                 sinkId = MMPLAYER_V_BIN;
11257                 sinkbin = player->pipeline->videobin;
11258                 send_notice = TRUE;
11259                 break;
11260         case MM_PLAYER_TRACK_TYPE_TEXT:
11261                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11262                 sinkId = MMPLAYER_T_BIN;
11263                 sinkbin = player->pipeline->textbin;
11264                 break;
11265         default:
11266                 LOGE("requested type is not supportable");
11267                 return FALSE;
11268                 break;
11269         }
11270
11271         if (player->pipeline->mainbin[selectorId].gst) {
11272                 gint n;
11273
11274                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11275
11276                 if (selector->event_probe_id != 0)
11277                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
11278                 selector->event_probe_id = 0;
11279
11280                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11281                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11282
11283                         if (srcpad && sinkpad) {
11284                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
11285                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11286                                 gst_pad_unlink(srcpad, sinkpad);
11287
11288                                 /* send custom event to sink pad to handle it at video sink */
11289                                 if (send_notice) {
11290                                         LOGD("send custom event to sinkpad");
11291                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11292                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11293                                         gst_pad_send_event(sinkpad, event);
11294                                 }
11295                         }
11296
11297                         gst_object_unref(sinkpad);
11298                         sinkpad = NULL;
11299                 }
11300                 gst_object_unref(srcpad);
11301                 srcpad = NULL;
11302
11303                 LOGD("selector release");
11304
11305                 /* release and unref requests pad from the selector */
11306                 for (n = 0; n < selector->channels->len; n++) {
11307                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11308                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11309                 }
11310                 g_ptr_array_set_size(selector->channels, 0);
11311
11312                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11313                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11314
11315                 player->pipeline->mainbin[selectorId].gst = NULL;
11316                 selector = NULL;
11317         }
11318
11319         return TRUE;
11320 }
11321
11322 static void
11323 __mmplayer_deactivate_old_path(mm_player_t *player)
11324 {
11325         MMPLAYER_FENTER();
11326         MMPLAYER_RETURN_IF_FAIL(player);
11327
11328         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11329                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11330                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11331                 LOGE("deactivate selector error");
11332                 goto ERROR;
11333         }
11334
11335         _mmplayer_track_destroy(player);
11336         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11337
11338         if (player->streamer) {
11339                 __mm_player_streaming_deinitialize(player->streamer);
11340                 __mm_player_streaming_destroy(player->streamer);
11341                 player->streamer = NULL;
11342         }
11343
11344         MMPLAYER_PLAYBACK_LOCK(player);
11345         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11346
11347         MMPLAYER_FLEAVE();
11348         return;
11349
11350 ERROR:
11351
11352         if (!player->msg_posted) {
11353                 MMMessageParamType msg = {0,};
11354
11355                 /*post error*/
11356                 msg.code = MM_ERROR_PLAYER_INTERNAL;
11357                 LOGE("next_uri_play> deactivate error");
11358
11359                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11360                 player->msg_posted = TRUE;
11361         }
11362         return;
11363 }
11364
11365 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11366 {
11367         int result = MM_ERROR_NONE;
11368         mm_player_t* player = (mm_player_t*) hplayer;
11369         MMPLAYER_FENTER();
11370
11371         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11372
11373         if (file_path) {
11374                 player->http_file_buffering_path = (gchar*)file_path;
11375                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11376         }
11377         MMPLAYER_FLEAVE();
11378         return result;
11379 }
11380
11381 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11382 {
11383         int result = MM_ERROR_NONE;
11384         mm_player_t* player = (mm_player_t*) hplayer;
11385         MMPLAYER_FENTER();
11386
11387         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11388
11389         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11390         if (mmf_attrs_commit(player->attrs)) {
11391                 LOGE("failed to commit the original uri.\n");
11392                 result = MM_ERROR_PLAYER_INTERNAL;
11393         } else {
11394                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11395                         LOGE("failed to add the original uri in the uri list.\n");
11396         }
11397
11398         MMPLAYER_FLEAVE();
11399         return result;
11400 }
11401
11402 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11403 {
11404         mm_player_t* player = (mm_player_t*) hplayer;
11405         guint num_of_list = 0;
11406
11407         MMPLAYER_FENTER();
11408
11409         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11410         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11411
11412         if (player->pipeline && player->pipeline->textbin) {
11413                 LOGE("subtitle path is enabled.\n");
11414                 return MM_ERROR_PLAYER_INVALID_STATE;
11415         }
11416
11417         num_of_list = g_list_length(player->uri_info.uri_list);
11418
11419         if (is_first_path == TRUE) {
11420                 if (num_of_list == 0) {
11421                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11422                         LOGD("add original path : %s", uri);
11423                 } else {
11424                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11425                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11426
11427                         LOGD("change original path : %s", uri);
11428                 }
11429         } else {
11430                 MMHandleType attrs = 0;
11431                 attrs = MMPLAYER_GET_ATTRS(player);
11432
11433                 if (num_of_list == 0) {
11434                         char *original_uri = NULL;
11435
11436                         if (attrs) {
11437                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11438
11439                                 if (!original_uri) {
11440                                         LOGE("there is no original uri.");
11441                                         return MM_ERROR_PLAYER_INVALID_STATE;
11442                                 }
11443
11444                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11445                                 player->uri_info.uri_idx = 0;
11446
11447                                 LOGD("add original path at first : %s(%d)", original_uri);
11448                         }
11449                 }
11450
11451                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11452                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11453         }
11454
11455         MMPLAYER_FLEAVE();
11456         return MM_ERROR_NONE;
11457 }
11458
11459 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11460 {
11461         mm_player_t* player = (mm_player_t*) hplayer;
11462         char *next_uri = NULL;
11463         guint num_of_list = 0;
11464
11465         MMPLAYER_FENTER();
11466         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11467
11468         num_of_list = g_list_length(player->uri_info.uri_list);
11469
11470         if (num_of_list > 0) {
11471                 gint uri_idx = player->uri_info.uri_idx;
11472
11473                 if (uri_idx < num_of_list-1)
11474                         uri_idx++;
11475                 else
11476                         uri_idx = 0;
11477
11478                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11479                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11480
11481                 *uri = g_strdup(next_uri);
11482         }
11483
11484         MMPLAYER_FLEAVE();
11485         return MM_ERROR_NONE;
11486 }
11487
11488 static void
11489 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
11490 GstCaps *caps, gpointer data)
11491 {
11492         mm_player_t* player = (mm_player_t*)data;
11493         const gchar* klass = NULL;
11494         const gchar* mime = NULL;
11495         gchar* caps_str = NULL;
11496
11497         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11498         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11499         caps_str = gst_caps_to_string(caps);
11500
11501         LOGW("unknown type of caps : %s from %s",
11502                                         caps_str, GST_ELEMENT_NAME(elem));
11503
11504         MMPLAYER_FREEIF(caps_str);
11505
11506         /* There is no available codec. */
11507         __mmplayer_check_not_supported_codec(player, klass, mime);
11508 }
11509
11510 static gboolean
11511 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
11512 GstCaps * caps,  gpointer data)
11513 {
11514         mm_player_t* player = (mm_player_t*)data;
11515         const char* mime = NULL;
11516         gboolean ret = TRUE;
11517
11518         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11519         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11520
11521         if (g_str_has_prefix(mime, "audio")) {
11522                 GstStructure* caps_structure = NULL;
11523                 gint samplerate = 0;
11524                 gint channels = 0;
11525                 gchar *caps_str = NULL;
11526
11527                 caps_structure = gst_caps_get_structure(caps, 0);
11528                 gst_structure_get_int(caps_structure, "rate", &samplerate);
11529                 gst_structure_get_int(caps_structure, "channels", &channels);
11530
11531                 if ((channels > 0 && samplerate == 0)) {
11532                         LOGD("exclude audio...");
11533                         ret = FALSE;
11534                 }
11535
11536                 caps_str = gst_caps_to_string(caps);
11537                 /* set it directly because not sent by TAG */
11538                 if (g_strrstr(caps_str, "mobile-xmf"))
11539                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11540                 MMPLAYER_FREEIF(caps_str);
11541         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11542                 MMMessageParamType msg_param;
11543                 memset(&msg_param, 0, sizeof(MMMessageParamType));
11544                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11545                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11546                 LOGD("video file is not supported on this device");
11547                 ret = FALSE;
11548         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11549                 LOGD("already video linked");
11550                 ret = FALSE;
11551         } else {
11552                 LOGD("found new stream");
11553         }
11554
11555         return ret;
11556 }
11557
11558 static int
11559 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
11560 {
11561         int ret = MM_ERROR_NONE;
11562         int idx = 0;
11563         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
11564
11565         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11566                 GstStructure* str = NULL;
11567                 gint channels = 0;
11568                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
11569
11570                 LOGD("audio codec type: %d", codec_type);
11571                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
11572                         /* sw codec will be skipped */
11573                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
11574                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
11575                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
11576                                         ret = MM_ERROR_PLAYER_INTERNAL;
11577                                         goto DONE;
11578                                 }
11579                         }
11580                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
11581                         /* hw codec will be skipped */
11582                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
11583                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
11584                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
11585                                 ret = MM_ERROR_PLAYER_INTERNAL;
11586                                 goto DONE;
11587                         }
11588                 }
11589
11590                 str = gst_caps_get_structure(caps, 0);
11591                 if (str) {
11592                         gst_structure_get_int(str, "channels", &channels);
11593
11594                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11595                         if (player->max_audio_channels < channels)
11596                                 player->max_audio_channels = channels;
11597                 }
11598                 /* set stream information */
11599                 if (!player->audiodec_linked)
11600                         __mmplayer_set_audio_attrs(player, caps);
11601
11602                 /* update codec info */
11603                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11604                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11605                 player->audiodec_linked = 1;
11606
11607         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11608
11609                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
11610
11611                 LOGD("video codec type: %d", codec_type);
11612                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
11613                         /* sw codec is skipped */
11614                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
11615                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
11616                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
11617                                         ret = MM_ERROR_PLAYER_INTERNAL;
11618                                         goto DONE;
11619                                 }
11620                         }
11621                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
11622                         /* hw codec is skipped */
11623                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11624                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
11625                                 ret = MM_ERROR_PLAYER_INTERNAL;
11626                                 goto DONE;
11627                         }
11628                 }
11629
11630                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11631                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11632
11633                         /* mark video decoder for acquire */
11634                         if (player->video_decoder_resource == NULL) {
11635                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
11636                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
11637                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
11638                                                 &player->video_decoder_resource)
11639                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
11640                                         LOGE("could not mark video_decoder resource for acquire");
11641                                         ret = MM_ERROR_PLAYER_INTERNAL;
11642                                         goto DONE;
11643                                 }
11644                         } else {
11645                                 LOGW("video decoder resource is already acquired, skip it.");
11646                                 ret = MM_ERROR_PLAYER_INTERNAL;
11647                                 goto DONE;
11648                         }
11649
11650                         player->interrupted_by_resource = FALSE;
11651                         /* acquire resources for video playing */
11652                         if (mm_resource_manager_commit(player->resource_manager)
11653                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
11654                                 LOGE("could not acquire resources for video decoding\n");
11655                                 ret = MM_ERROR_PLAYER_INTERNAL;
11656                                 goto DONE;
11657                         }
11658                 }
11659
11660                 /* update codec info */
11661                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11662                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11663                 player->videodec_linked = 1;
11664         }
11665
11666 DONE:
11667         return ret;
11668 }
11669
11670 static gint
11671 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
11672 GstCaps* caps, GstElementFactory* factory, gpointer data)
11673 {
11674         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11675          We are defining our own and will be removed when it actually exposed */
11676         typedef enum {
11677                 GST_AUTOPLUG_SELECT_TRY,
11678                 GST_AUTOPLUG_SELECT_EXPOSE,
11679                 GST_AUTOPLUG_SELECT_SKIP
11680         } GstAutoplugSelectResult;
11681
11682         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11683         mm_player_t* player = (mm_player_t*)data;
11684
11685         gchar* factory_name = NULL;
11686         gchar* caps_str = NULL;
11687         const gchar* klass = NULL;
11688         gint idx = 0;
11689
11690         factory_name = GST_OBJECT_NAME(factory);
11691         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11692         caps_str = gst_caps_to_string(caps);
11693
11694         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
11695
11696         /* store type string */
11697         if (player->type == NULL) {
11698                 player->type = gst_caps_to_string(caps);
11699                 __mmplayer_update_content_type_info(player);
11700         }
11701
11702         /* filtering exclude keyword */
11703         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11704                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11705                         LOGW("skipping [%s] by exculde keyword [%s]\n",
11706                                         factory_name, player->ini.exclude_element_keyword[idx]);
11707
11708                         result = GST_AUTOPLUG_SELECT_SKIP;
11709                         goto DONE;
11710                 }
11711         }
11712
11713         /* exclude webm format */
11714         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11715          * because webm format is not supportable.
11716          * If webm is disabled in "autoplug-continue", there is no state change
11717          * failure or error because the decodebin will expose the pad directly.
11718          * It make MSL invoke _prepare_async_callback.
11719          * So, we need to disable webm format in "autoplug-select" */
11720         if (caps_str && strstr(caps_str, "webm")) {
11721                 LOGW("webm is not supported");
11722                 result = GST_AUTOPLUG_SELECT_SKIP;
11723                 goto DONE;
11724         }
11725
11726         /* check factory class for filtering */
11727         /* NOTE : msl don't need to use image plugins.
11728          * So, those plugins should be skipped for error handling.
11729          */
11730         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11731                 LOGD("skipping [%s] by not required\n", factory_name);
11732                 result = GST_AUTOPLUG_SELECT_SKIP;
11733                 goto DONE;
11734         }
11735
11736         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11737                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11738                 // TO CHECK : subtitle if needed, add subparse exception.
11739                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11740                 result = GST_AUTOPLUG_SELECT_SKIP;
11741                 goto DONE;
11742         }
11743
11744         if (g_strrstr(factory_name, "mpegpsdemux")) {
11745                 LOGD("skipping PS container - not support\n");
11746                 result = GST_AUTOPLUG_SELECT_SKIP;
11747                 goto DONE;
11748         }
11749
11750         if (g_strrstr(factory_name, "mssdemux"))
11751                 player->smooth_streaming = TRUE;
11752
11753         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11754                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11755                 gint stype = 0;
11756                 gint width = 0;
11757                 GstStructure *str = NULL;
11758                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11759
11760                 /* don't make video because of not required */
11761                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11762                         (player->set_mode.media_packet_video_stream == FALSE)) {
11763                         LOGD("no video because it's not required. -> return expose");
11764                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11765                         goto DONE;
11766                 }
11767
11768                 /* get w/h for omx state-tune */
11769                 /* FIXME: deprecated? */
11770                 str = gst_caps_get_structure(caps, 0);
11771                 gst_structure_get_int(str, "width", &width);
11772
11773                 if (width != 0) {
11774                         if (player->v_stream_caps) {
11775                                 gst_caps_unref(player->v_stream_caps);
11776                                 player->v_stream_caps = NULL;
11777                         }
11778
11779                         player->v_stream_caps = gst_caps_copy(caps);
11780                         LOGD("take caps for video state tune");
11781                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11782                 }
11783         }
11784
11785         if (g_strrstr(klass, "Codec/Decoder")) {
11786                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11787                         LOGD("skipping %s codec", factory_name);
11788                         result = GST_AUTOPLUG_SELECT_SKIP;
11789                         goto DONE;
11790                 }
11791         }
11792
11793 DONE:
11794         MMPLAYER_FREEIF(caps_str);
11795
11796         return result;
11797 }
11798
11799 static void
11800 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11801 gpointer data)
11802 {
11803         //mm_player_t* player = (mm_player_t*)data;
11804         GstCaps* caps = NULL;
11805
11806         LOGD("[Decodebin2] pad-removed signal\n");
11807
11808         caps = gst_pad_query_caps(new_pad, NULL);
11809         if (caps) {
11810                 gchar* caps_str = NULL;
11811                 caps_str = gst_caps_to_string(caps);
11812
11813                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11814
11815                 MMPLAYER_FREEIF(caps_str);
11816                 gst_caps_unref(caps);
11817         }
11818 }
11819
11820 static void
11821 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11822 {
11823         mm_player_t* player = (mm_player_t*)data;
11824         GstIterator *iter = NULL;
11825         GValue item = { 0, };
11826         GstPad *pad = NULL;
11827         gboolean done = FALSE;
11828         gboolean is_all_drained = TRUE;
11829
11830         MMPLAYER_FENTER();
11831         MMPLAYER_RETURN_IF_FAIL(player);
11832
11833         LOGD("__mmplayer_gst_decode_drained");
11834
11835         if (player->use_deinterleave == TRUE) {
11836                 LOGD("group playing mode.");
11837                 return;
11838         }
11839
11840         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11841                 LOGW("Fail to get cmd lock");
11842                 return;
11843         }
11844
11845         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11846                 !__mmplayer_verify_next_play_path(player)) {
11847                 LOGD("decoding is finished.");
11848                 __mmplayer_reset_gapless_state(player);
11849                 MMPLAYER_CMD_UNLOCK(player);
11850                 return;
11851         }
11852
11853         player->gapless.reconfigure = TRUE;
11854
11855         /* check decodebin src pads whether they received EOS or not */
11856         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11857
11858         while (!done) {
11859                 switch (gst_iterator_next(iter, &item)) {
11860                 case GST_ITERATOR_OK:
11861                         pad = g_value_get_object(&item);
11862                         if (pad && !GST_PAD_IS_EOS(pad)) {
11863                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11864                                 is_all_drained = FALSE;
11865                                 break;
11866                         }
11867                         g_value_reset(&item);
11868                         break;
11869                 case GST_ITERATOR_RESYNC:
11870                         gst_iterator_resync(iter);
11871                         break;
11872                 case GST_ITERATOR_ERROR:
11873                 case GST_ITERATOR_DONE:
11874                         done = TRUE;
11875                         break;
11876                 }
11877         }
11878         g_value_unset(&item);
11879         gst_iterator_free(iter);
11880
11881         if (!is_all_drained) {
11882                 LOGD("Wait util the all pads get EOS.");
11883                 MMPLAYER_CMD_UNLOCK(player);
11884                 MMPLAYER_FLEAVE();
11885                 return;
11886         }
11887
11888         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11889         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11890
11891         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11892         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11893         __mmplayer_deactivate_old_path(player);
11894         MMPLAYER_CMD_UNLOCK(player);
11895
11896         MMPLAYER_FLEAVE();
11897 }
11898
11899 static void
11900 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11901 {
11902         mm_player_t* player = (mm_player_t*)data;
11903         const gchar* klass = NULL;
11904         gchar* factory_name = NULL;
11905
11906         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11907         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11908
11909         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11910
11911         if (__mmplayer_add_dump_buffer_probe(player, element))
11912                 LOGD("add buffer probe");
11913
11914         //<-
11915         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11916                 gchar* selected = NULL;
11917                 selected = g_strdup(GST_ELEMENT_NAME(element));
11918                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11919         }
11920         //-> temp code
11921
11922         if (g_strrstr(klass, "Parser")) {
11923                 gchar* selected = NULL;
11924
11925                 selected = g_strdup(factory_name);
11926                 player->parsers = g_list_append(player->parsers, selected);
11927         }
11928
11929         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11930                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11931                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11932
11933                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11934                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11935
11936                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11937                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11938                                                 "max-video-width", player->adaptive_info.limit.width,
11939                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11940
11941         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11942                 /* FIXIT : first value will be overwritten if there's more
11943                  * than 1 demuxer/parser
11944                  */
11945
11946                 //LOGD("plugged element is demuxer. take it\n");
11947                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11948                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11949
11950                 /*Added for multi audio support */ // Q. del?
11951                 if (g_strrstr(klass, "Demux")) {
11952                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11953                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11954                 }
11955         }
11956
11957         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11958                 int surface_type = 0;
11959
11960                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11961         }
11962
11963         // to support trust-zone only
11964         if (g_strrstr(factory_name, "asfdemux")) {
11965                 LOGD("set file-location %s\n", player->profile.uri);
11966                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11967
11968                 if (player->video_hub_download_mode == TRUE)
11969                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11970         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11971                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11972                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11973         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11974                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11975                         (__mmplayer_is_only_mp3_type(player->type))) {
11976                         LOGD("[mpegaudioparse] set streaming pull mode.");
11977                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11978                 }
11979         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11980                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11981         }
11982
11983         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11984                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11985                 LOGD("plugged element is multiqueue. take it\n");
11986
11987                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11988                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11989
11990                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11991                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
11992                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11993                         __mm_player_streaming_set_multiqueue(player->streamer,
11994                                 element,
11995                                 TRUE,
11996                                 player->ini.http_buffering_time,
11997                                 1.0,
11998                                 player->ini.http_buffering_limit);
11999
12000                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12001                 }
12002         }
12003
12004         return;
12005 }
12006
12007 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12008 {
12009         MMPLAYER_FENTER();
12010         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12011
12012         if (MMPLAYER_IS_STREAMING(player))
12013                 return FALSE;
12014
12015         /* This callback can be set to music player only. */
12016         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12017                 LOGW("audio callback is not supported for video");
12018                 return FALSE;
12019         }
12020
12021         if (player->audio_stream_cb) {
12022                 GstPad *pad = NULL;
12023
12024                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12025
12026                 if (!pad) {
12027                         LOGE("failed to get sink pad from audiosink to probe data\n");
12028                         return FALSE;
12029                 }
12030                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12031                         __mmplayer_audio_stream_probe, player, NULL);
12032
12033                 gst_object_unref(pad);
12034
12035                 pad = NULL;
12036         } else {
12037                 LOGE("There is no audio callback to configure.\n");
12038                 return FALSE;
12039         }
12040
12041         MMPLAYER_FLEAVE();
12042
12043         return TRUE;
12044 }
12045
12046 static void
12047 __mmplayer_release_misc(mm_player_t* player)
12048 {
12049         int i;
12050         bool cur_mode = player->set_mode.rich_audio;
12051         MMPLAYER_FENTER();
12052
12053         MMPLAYER_RETURN_IF_FAIL(player);
12054
12055         player->video_stream_cb = NULL;
12056         player->video_stream_cb_user_param = NULL;
12057         player->video_stream_prerolled = FALSE;
12058
12059         player->audio_stream_cb = NULL;
12060         player->audio_stream_render_cb_ex = NULL;
12061         player->audio_stream_cb_user_param = NULL;
12062         player->audio_stream_sink_sync = false;
12063
12064         player->video_stream_changed_cb = NULL;
12065         player->video_stream_changed_cb_user_param = NULL;
12066
12067         player->audio_stream_changed_cb = NULL;
12068         player->audio_stream_changed_cb_user_param = NULL;
12069
12070         player->sent_bos = FALSE;
12071         player->playback_rate = DEFAULT_PLAYBACK_RATE;
12072
12073         player->doing_seek = FALSE;
12074
12075         player->total_bitrate = 0;
12076         player->total_maximum_bitrate = 0;
12077
12078         player->not_found_demuxer = 0;
12079
12080         player->last_position = 0;
12081         player->duration = 0;
12082         player->http_content_size = 0;
12083         player->not_supported_codec = MISSING_PLUGIN_NONE;
12084         player->can_support_codec = FOUND_PLUGIN_NONE;
12085         player->pending_seek.is_pending = FALSE;
12086         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12087         player->pending_seek.pos = 0;
12088         player->msg_posted = FALSE;
12089         player->has_many_types = FALSE;
12090         player->max_audio_channels = 0;
12091         player->video_share_api_delta = 0;
12092         player->video_share_clock_delta = 0;
12093         player->sound_focus.keep_last_pos = FALSE;
12094         player->is_subtitle_force_drop = FALSE;
12095         player->play_subtitle = FALSE;
12096         player->adjust_subtitle_pos = 0;
12097         player->last_multiwin_status = FALSE;
12098         player->has_closed_caption = FALSE;
12099         player->set_mode.media_packet_video_stream = FALSE;
12100         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12101         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12102         /* recover mode */
12103         player->set_mode.rich_audio = cur_mode;
12104
12105         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12106                 player->bitrate[i] = 0;
12107                 player->maximum_bitrate[i] = 0;
12108         }
12109
12110         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12111
12112         /* remove media stream cb(appsrc cb) */
12113         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12114                 player->media_stream_buffer_status_cb[i] = NULL;
12115                 player->media_stream_seek_data_cb[i] = NULL;
12116                 player->buffer_cb_user_param[i] = NULL;
12117                 player->seek_cb_user_param[i] = NULL;
12118         }
12119         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12120
12121         /* free memory related to audio effect */
12122         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12123
12124         if (player->adaptive_info.var_list) {
12125                 g_list_free_full(player->adaptive_info.var_list, g_free);
12126                 player->adaptive_info.var_list = NULL;
12127         }
12128
12129         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12130         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12131         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12132
12133         /* Reset video360 settings to their defaults in case if the pipeline is to be
12134          * re-created.
12135          * */
12136         player->video360_metadata.is_spherical = -1;
12137         player->is_openal_plugin_used = FALSE;
12138
12139         player->is_content_spherical = FALSE;
12140         player->is_video360_enabled = TRUE;
12141         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
12142         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
12143         player->video360_yaw_radians = 4;
12144         player->video360_pitch_radians = 4;
12145         player->video360_zoom = 1.0f;
12146         player->video360_horizontal_fov = 0;
12147         player->video360_vertical_fov = 0;
12148
12149         MMPLAYER_FLEAVE();
12150 }
12151
12152 static void
12153 __mmplayer_release_misc_post(mm_player_t* player)
12154 {
12155         char *original_uri = NULL;
12156         MMPLAYER_FENTER();
12157
12158         /* player->pipeline is already released before. */
12159
12160         MMPLAYER_RETURN_IF_FAIL(player);
12161
12162         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12163         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12164
12165         /* clean found parsers */
12166         if (player->parsers) {
12167                 GList *parsers = player->parsers;
12168                 for (; parsers; parsers = g_list_next(parsers)) {
12169                         gchar *name = parsers->data;
12170                         MMPLAYER_FREEIF(name);
12171                 }
12172                 g_list_free(player->parsers);
12173                 player->parsers = NULL;
12174         }
12175
12176         /* clean found audio decoders */
12177         if (player->audio_decoders) {
12178                 GList *a_dec = player->audio_decoders;
12179                 for (; a_dec; a_dec = g_list_next(a_dec)) {
12180                         gchar *name = a_dec->data;
12181                         MMPLAYER_FREEIF(name);
12182                 }
12183                 g_list_free(player->audio_decoders);
12184                 player->audio_decoders = NULL;
12185         }
12186
12187         /* clean the uri list except original uri */
12188         if (player->uri_info.uri_list) {
12189                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12190
12191                 if (player->attrs) {
12192                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12193                         LOGD("restore original uri = %s\n", original_uri);
12194
12195                         if (mmf_attrs_commit(player->attrs))
12196                                 LOGE("failed to commit the original uri.\n");
12197                 }
12198
12199                 GList *uri_list = player->uri_info.uri_list;
12200                 for (; uri_list; uri_list = g_list_next(uri_list)) {
12201                         gchar *uri = uri_list->data;
12202                         MMPLAYER_FREEIF(uri);
12203                 }
12204                 g_list_free(player->uri_info.uri_list);
12205                 player->uri_info.uri_list = NULL;
12206         }
12207
12208         /* clear the audio stream buffer list */
12209         __mmplayer_audio_stream_clear_buffer(player, FALSE);
12210
12211         /* clear the video stream bo list */
12212         __mmplayer_video_stream_destroy_bo_list(player);
12213         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
12214
12215         if (player->profile.mem) {
12216                 free(player->profile.mem);
12217                 player->profile.mem = NULL;
12218                 player->mem_buf.buf = NULL;
12219         }
12220         player->uri_info.uri_idx = 0;
12221         MMPLAYER_FLEAVE();
12222 }
12223
12224 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12225 {
12226         GstElement *element = NULL;
12227         GstPad *sinkpad;
12228
12229         LOGD("creating %s to plug\n", name);
12230
12231         element = gst_element_factory_make(name, NULL);
12232         if (!element) {
12233                 LOGE("failed to create queue\n");
12234                 return NULL;
12235         }
12236
12237         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12238                 LOGE("failed to set state READY to %s\n", name);
12239                 gst_object_unref(element);
12240                 return NULL;
12241         }
12242
12243         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12244                 LOGE("failed to add %s\n", name);
12245                 gst_object_unref(element);
12246                 return NULL;
12247         }
12248
12249         sinkpad = gst_element_get_static_pad(element, "sink");
12250
12251         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12252                 LOGE("failed to link %s\n", name);
12253                 gst_object_unref(sinkpad);
12254                 gst_object_unref(element);
12255                 return NULL;
12256         }
12257
12258         LOGD("linked %s to pipeline successfully\n", name);
12259
12260         gst_object_unref(sinkpad);
12261
12262         return element;
12263 }
12264
12265 gboolean
12266 __mmplayer_check_subtitle(mm_player_t* player)
12267 {
12268         MMHandleType attrs = 0;
12269         char *subtitle_uri = NULL;
12270
12271         MMPLAYER_FENTER();
12272
12273         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12274
12275         /* get subtitle attribute */
12276         attrs = MMPLAYER_GET_ATTRS(player);
12277         if (!attrs)
12278                 return FALSE;
12279
12280         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12281         if (!subtitle_uri || !strlen(subtitle_uri))
12282                 return FALSE;
12283
12284         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
12285         player->is_external_subtitle_present = TRUE;
12286
12287         MMPLAYER_FLEAVE();
12288
12289         return TRUE;
12290 }
12291
12292 static gboolean
12293 __mmplayer_can_extract_pcm(mm_player_t* player)
12294 {
12295         MMHandleType attrs = 0;
12296         gboolean sound_extraction = FALSE;
12297
12298         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12299
12300         attrs = MMPLAYER_GET_ATTRS(player);
12301         if (!attrs) {
12302                 LOGE("fail to get attributes.");
12303                 return FALSE;
12304         }
12305
12306         /* get sound_extraction property */
12307         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
12308
12309         if (!sound_extraction) {
12310                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
12311                 return FALSE;
12312         }
12313
12314         return TRUE;
12315 }
12316
12317 static gboolean
12318 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
12319 {
12320         LOGD("\n");
12321         MMMessageParamType msg_param;
12322         gchar *msg_src_element = NULL;
12323         GstStructure *s = NULL;
12324         guint error_id = 0;
12325         gchar *error_string = NULL;
12326
12327         MMPLAYER_FENTER();
12328
12329         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12330         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
12331
12332         s = gst_structure_copy(gst_message_get_structure(message));
12333
12334
12335         if (!gst_structure_get_uint(s, "error_id", &error_id))
12336                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
12337
12338         switch (error_id) {
12339         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
12340                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
12341                 break;
12342         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
12343                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
12344                 break;
12345         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
12346                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
12347                 break;
12348         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
12349                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
12350                 break;
12351         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
12352                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
12353                 break;
12354         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
12355                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
12356                 break;
12357         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
12358                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
12359                 break;
12360         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
12361                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
12362                 break;
12363         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
12364                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
12365                 break;
12366         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
12367                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
12368                 break;
12369         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
12370                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
12371                 break;
12372         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
12373                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
12374                 break;
12375         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
12376                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
12377                 break;
12378         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
12379                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
12380                 break;
12381         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
12382                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
12383                 break;
12384         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
12385                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
12386                 break;
12387         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
12388                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
12389                 break;
12390         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
12391                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
12392                 break;
12393         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
12394                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
12395                 break;
12396         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
12397                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
12398                 break;
12399         case MMPLAYER_STREAMING_ERROR_GONE:
12400                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
12401                 break;
12402         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
12403                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
12404                 break;
12405         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
12406                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
12407                 break;
12408         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
12409                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
12410                 break;
12411         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
12412                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
12413                 break;
12414         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
12415                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
12416                 break;
12417         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
12418                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
12419                 break;
12420         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
12421                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
12422                 break;
12423         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
12424                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
12425                 break;
12426         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
12427                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
12428                 break;
12429         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
12430                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
12431                 break;
12432         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
12433                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
12434                 break;
12435         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
12436                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
12437                 break;
12438         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
12439                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
12440                 break;
12441         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
12442                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
12443                 break;
12444         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
12445                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
12446                 break;
12447         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
12448                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
12449                 break;
12450         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
12451                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
12452                 break;
12453         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
12454                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
12455                 break;
12456         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
12457                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
12458                 break;
12459         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
12460                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
12461                 break;
12462         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
12463                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
12464                 break;
12465         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
12466                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
12467                 break;
12468         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
12469                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
12470                 break;
12471         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
12472                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
12473                 break;
12474         default:
12475                 {
12476                         gst_structure_free(s);
12477                         return MM_ERROR_PLAYER_STREAMING_FAIL;
12478                 }
12479         }
12480
12481         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
12482         if (error_string)
12483                 msg_param.data = (void *) error_string;
12484
12485         if (message->src) {
12486                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
12487
12488                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
12489                         msg_src_element, msg_param.code, (char*)msg_param.data);
12490         }
12491
12492         /* post error to application */
12493         if (!player->msg_posted) {
12494                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
12495
12496                 /* don't post more if one was sent already */
12497                 player->msg_posted = TRUE;
12498         } else
12499                 LOGD("skip error post because it's sent already.\n");
12500
12501         gst_structure_free(s);
12502         MMPLAYER_FLEAVE();
12503         g_free(error_string);
12504
12505         return TRUE;
12506
12507 }
12508
12509 static void
12510 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
12511 {
12512         MMPLAYER_RETURN_IF_FAIL(player);
12513
12514         /* post now if delay is zero */
12515         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
12516                 LOGD("eos delay is zero. posting EOS now\n");
12517                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12518
12519                 if (player->set_mode.pcm_extraction)
12520                         __mmplayer_cancel_eos_timer(player);
12521
12522                 return;
12523         }
12524
12525         /* cancel if existing */
12526         __mmplayer_cancel_eos_timer(player);
12527
12528         /* init new timeout */
12529         /* NOTE : consider give high priority to this timer */
12530         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
12531
12532         player->eos_timer = g_timeout_add(delay_in_ms,
12533                 __mmplayer_eos_timer_cb, player);
12534
12535         player->global_default = g_main_context_default();
12536         LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
12537
12538         /* check timer is valid. if not, send EOS now */
12539         if (player->eos_timer == 0) {
12540                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
12541                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12542         }
12543 }
12544
12545 static void
12546 __mmplayer_cancel_eos_timer(mm_player_t* player)
12547 {
12548         MMPLAYER_RETURN_IF_FAIL(player);
12549
12550         if (player->eos_timer) {
12551                 LOGD("cancel eos timer");
12552                 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
12553                 player->eos_timer = 0;
12554         }
12555
12556         return;
12557 }
12558
12559 static gboolean
12560 __mmplayer_eos_timer_cb(gpointer u_data)
12561 {
12562         mm_player_t* player = NULL;
12563         player = (mm_player_t*) u_data;
12564
12565         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12566
12567         if (player->play_count > 1) {
12568                 gint ret_value = 0;
12569                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
12570                 if (ret_value == MM_ERROR_NONE) {
12571                         MMHandleType attrs = 0;
12572                         attrs = MMPLAYER_GET_ATTRS(player);
12573
12574                         /* we successeded to rewind. update play count and then wait for next EOS */
12575                         player->play_count--;
12576
12577                         mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
12578                         if (mmf_attrs_commit(attrs))
12579                                 LOGE("failed to update attributes\n");
12580                 } else {
12581                         LOGE("seeking to 0 failed in repeat play");
12582                 }
12583         } else {
12584                 /* posting eos */
12585                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12586         }
12587
12588         /* we are returning FALSE as we need only one posting */
12589         return FALSE;
12590 }
12591
12592 /* sending event to one of sinkelements */
12593 static gboolean
12594 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
12595 {
12596         GstEvent * event2 = NULL;
12597         GList *sinks = NULL;
12598         gboolean res = FALSE;
12599         MMPLAYER_FENTER();
12600
12601         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12602         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
12603
12604         /* While adding subtitles in live feeds seek is getting called.
12605            Adding defensive check in framework layer.*/
12606         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
12607                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
12608                         LOGE("Should not send seek event during live playback");
12609                         return TRUE;
12610                 }
12611         }
12612
12613         if (player->play_subtitle)
12614                 event2 = gst_event_copy((const GstEvent *)event);
12615
12616         sinks = player->sink_elements;
12617         while (sinks) {
12618                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
12619
12620                 if (GST_IS_ELEMENT(sink)) {
12621                         /* keep ref to the event */
12622                         gst_event_ref(event);
12623
12624                         if ((res = gst_element_send_event(sink, event))) {
12625                                 LOGD("sending event[%s] to sink element [%s] success!\n",
12626                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
12627
12628                                 /* rtsp case, asyn_done is not called after seek during pause state */
12629                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
12630                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
12631                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
12632                                                         LOGD("RTSP seek completed, after pause state..\n");
12633                                                         player->doing_seek = FALSE;
12634                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
12635                                                 }
12636
12637                                         }
12638                                 }
12639
12640                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
12641                                         sinks = g_list_next(sinks);
12642                                         continue;
12643                                 } else {
12644                                         break;
12645                                 }
12646                         }
12647
12648                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
12649                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
12650                 }
12651
12652                 sinks = g_list_next(sinks);
12653         }
12654
12655         /* Note : Textbin is not linked to the video or audio bin.
12656          * It needs to send the event to the text sink seperatelly.
12657          */
12658          if (player->play_subtitle && player->pipeline) {
12659                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
12660
12661                 if (GST_IS_ELEMENT(text_sink)) {
12662                         /* keep ref to the event */
12663                         gst_event_ref(event2);
12664
12665                         if ((res = gst_element_send_event(text_sink, event2)))
12666                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
12667                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
12668                         else
12669                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
12670                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
12671
12672                         gst_event_unref(event2);
12673                 }
12674          }
12675
12676         gst_event_unref(event);
12677
12678         MMPLAYER_FLEAVE();
12679
12680         return res;
12681 }
12682
12683 static void
12684 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
12685 {
12686         MMPLAYER_FENTER();
12687
12688         MMPLAYER_RETURN_IF_FAIL(player);
12689         MMPLAYER_RETURN_IF_FAIL(sink);
12690
12691         player->sink_elements =
12692                 g_list_append(player->sink_elements, sink);
12693
12694         MMPLAYER_FLEAVE();
12695 }
12696
12697 static void
12698 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
12699 {
12700         MMPLAYER_FENTER();
12701
12702         MMPLAYER_RETURN_IF_FAIL(player);
12703         MMPLAYER_RETURN_IF_FAIL(sink);
12704
12705         player->sink_elements =
12706                         g_list_remove(player->sink_elements, sink);
12707
12708         MMPLAYER_FLEAVE();
12709 }
12710
12711 static gboolean
12712 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
12713                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
12714                         gint64 cur, GstSeekType stop_type, gint64 stop)
12715 {
12716         GstEvent* event = NULL;
12717         gboolean result = FALSE;
12718
12719         MMPLAYER_FENTER();
12720
12721         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12722
12723         if (player->pipeline && player->pipeline->textbin)
12724                 __mmplayer_drop_subtitle(player, FALSE);
12725
12726         event = gst_event_new_seek(rate, format, flags, cur_type,
12727                 cur, stop_type, stop);
12728
12729         result = __gst_send_event_to_sink(player, event);
12730
12731         MMPLAYER_FLEAVE();
12732
12733         return result;
12734 }
12735
12736 /* NOTE : be careful with calling this api. please refer to below glib comment
12737  * glib comment : Note that there is a bug in GObject that makes this function much
12738  * less useful than it might seem otherwise. Once gobject is disposed, the callback
12739  * will no longer be called, but, the signal handler is not currently disconnected.
12740  * If the instance is itself being freed at the same time than this doesn't matter,
12741  * since the signal will automatically be removed, but if instance persists,
12742  * then the signal handler will leak. You should not remove the signal yourself
12743  * because in a future versions of GObject, the handler will automatically be
12744  * disconnected.
12745  *
12746  * It's possible to work around this problem in a way that will continue to work
12747  * with future versions of GObject by checking that the signal handler is still
12748  * connected before disconnected it:
12749  *
12750  *  if (g_signal_handler_is_connected(instance, id))
12751  *    g_signal_handler_disconnect(instance, id);
12752  */
12753 static void
12754 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12755 {
12756         GList* sig_list = NULL;
12757         MMPlayerSignalItem* item = NULL;
12758
12759         MMPLAYER_FENTER();
12760
12761         MMPLAYER_RETURN_IF_FAIL(player);
12762
12763         LOGD("release signals type : %d", type);
12764
12765         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12766                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12767                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12768                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12769                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12770                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12771                 return;
12772         }
12773
12774         sig_list = player->signals[type];
12775
12776         for (; sig_list; sig_list = sig_list->next) {
12777                 item = sig_list->data;
12778
12779                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12780                         if (g_signal_handler_is_connected(item->obj, item->sig))
12781                                 g_signal_handler_disconnect(item->obj, item->sig);
12782                 }
12783
12784                 MMPLAYER_FREEIF(item);
12785         }
12786
12787         g_list_free(player->signals[type]);
12788         player->signals[type] = NULL;
12789
12790         MMPLAYER_FLEAVE();
12791
12792         return;
12793 }
12794
12795 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12796 {
12797         mm_player_t* player = 0;
12798         int prev_display_surface_type = 0;
12799         void *prev_display_overlay = NULL;
12800         const gchar *klass = NULL;
12801         gchar *cur_videosink_name = NULL;
12802         int ret = 0;
12803         int i = 0;
12804         int num_of_dec = 2; /* DEC1, DEC2 */
12805
12806         MMPLAYER_FENTER();
12807
12808         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12809         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12810
12811         player = MM_PLAYER_CAST(handle);
12812
12813         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12814                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12815                 MMPLAYER_FLEAVE();
12816                 return MM_ERROR_INVALID_ARGUMENT;
12817         }
12818
12819         /* load previous attributes */
12820         if (player->attrs) {
12821                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12822                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12823                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12824                 if (prev_display_surface_type == surface_type) {
12825                         LOGD("incoming display surface type is same as previous one, do nothing..");
12826                         MMPLAYER_FLEAVE();
12827                         return MM_ERROR_NONE;
12828                 }
12829         } else {
12830                 LOGE("failed to load attributes");
12831                 MMPLAYER_FLEAVE();
12832                 return MM_ERROR_PLAYER_INTERNAL;
12833         }
12834
12835         /* check videosink element is created */
12836         if (!player->pipeline || !player->pipeline->videobin ||
12837                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12838                 LOGD("videosink element is not yet ready");
12839
12840                 /* videobin is not created yet, so we just set attributes related to display surface */
12841                 LOGD("store display attribute for given surface type(%d)", surface_type);
12842                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12843                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12844                 if (mmf_attrs_commit(player->attrs)) {
12845                         LOGE("failed to commit attribute");
12846                         MMPLAYER_FLEAVE();
12847                         return MM_ERROR_PLAYER_INTERNAL;
12848                 }
12849                 MMPLAYER_FLEAVE();
12850                 return MM_ERROR_NONE;
12851         } else {
12852                 /* get player command status */
12853                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12854                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12855                         MMPLAYER_FLEAVE();
12856                         return MM_ERROR_PLAYER_INVALID_STATE;
12857                 }
12858
12859                 /* surface change */
12860                 for (i = 0 ; i < num_of_dec ; i++) {
12861                         if (player->pipeline->mainbin &&
12862                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12863                                 GstElementFactory *decfactory;
12864                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12865
12866                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12867                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12868                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12869                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12870                                                 if (ret) {
12871                                                         goto ERROR_CASE;
12872                                                 } else {
12873                                                         LOGW("success to changing display surface(%d)", surface_type);
12874                                                         MMPLAYER_FLEAVE();
12875                                                         return MM_ERROR_NONE;
12876                                                 }
12877                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12878                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12879                                                 if (ret) {
12880                                                         goto ERROR_CASE;
12881                                                 } else {
12882                                                         LOGW("success to changing display surface(%d)", surface_type);
12883                                                         MMPLAYER_FLEAVE();
12884                                                         return MM_ERROR_NONE;
12885                                                 }
12886                                         } else {
12887                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12888                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12889                                                 goto ERROR_CASE;
12890                                         }
12891                                 }
12892                         }
12893                 }
12894         }
12895
12896 ERROR_CASE:
12897         /* rollback to previous attributes */
12898         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12899         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12900         if (mmf_attrs_commit(player->attrs)) {
12901                 LOGE("failed to commit attributes to rollback");
12902                 MMPLAYER_FLEAVE();
12903                 return MM_ERROR_PLAYER_INTERNAL;
12904         }
12905         MMPLAYER_FLEAVE();
12906         return ret;
12907 }
12908
12909 /* NOTE : It does not support some use cases, eg using colorspace converter */
12910 int
12911 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12912 {
12913         GstPad *src_pad_dec = NULL;
12914         GstPad *sink_pad_videosink = NULL;
12915         GstPad *sink_pad_videobin = NULL;
12916         GstClock *clock = NULL;
12917         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12918         int ret = MM_ERROR_NONE;
12919         gboolean is_audiobin_created = TRUE;
12920
12921         MMPLAYER_FENTER();
12922
12923         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12924         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12925         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12926
12927         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12928         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12929
12930         /* get information whether if audiobin is created */
12931         if (!player->pipeline->audiobin ||
12932                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12933                 LOGW("audiobin is null, this video content may not have audio data");
12934                 is_audiobin_created = FALSE;
12935         }
12936
12937         /* get current state of player */
12938         previous_state = MMPLAYER_CURRENT_STATE(player);
12939         LOGD("previous state(%d)", previous_state);
12940
12941
12942         /* get src pad of decoder and block it */
12943         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12944         if (!src_pad_dec) {
12945                 LOGE("failed to get src pad from decode in mainbin");
12946                 return MM_ERROR_PLAYER_INTERNAL;
12947         }
12948
12949         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12950                 LOGW("trying to block pad(video)");
12951 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12952                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12953                         NULL, NULL, NULL);
12954                 {
12955                         LOGE("failed to set block pad(video)");
12956                         return MM_ERROR_PLAYER_INTERNAL;
12957                 }
12958                 LOGW("pad is blocked(video)");
12959         } else {
12960                 /* no data flows, so no need to do pad_block */
12961                 if (player->doing_seek)
12962                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12963
12964                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12965         }
12966
12967         /* remove pad */
12968         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12969                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12970                 LOGE("failed to remove previous ghost_pad for videobin");
12971                 return MM_ERROR_PLAYER_INTERNAL;
12972         }
12973
12974         /* change state of videobin to NULL */
12975         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12976         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12977         if (ret != GST_STATE_CHANGE_SUCCESS) {
12978                 LOGE("failed to change state of videobin to NULL");
12979                 return MM_ERROR_PLAYER_INTERNAL;
12980         }
12981
12982         /* unlink between decoder and videobin and remove previous videosink from videobin */
12983         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12984         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12985                 LOGE("failed to remove former videosink from videobin");
12986                 return MM_ERROR_PLAYER_INTERNAL;
12987         }
12988
12989         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12990
12991         /* create a new videosink and add it to videobin */
12992         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
12993         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12994                 LOGE("failed to create videosink element\n");
12995                 MMPLAYER_FLEAVE();
12996                 return MM_ERROR_PLAYER_INTERNAL;
12997         }
12998         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12999         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13000         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13001
13002         /* save attributes */
13003         if (player->attrs) {
13004                 /* set a new display surface type */
13005                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13006                 /* set a new diplay overlay */
13007                 switch (surface_type) {
13008                 case MM_DISPLAY_SURFACE_OVERLAY:
13009                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13010                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13011                         break;
13012                 default:
13013                         LOGE("invalid type(%d) for changing display surface", surface_type);
13014                         MMPLAYER_FLEAVE();
13015                         return MM_ERROR_INVALID_ARGUMENT;
13016                 }
13017                 if (mmf_attrs_commit(player->attrs)) {
13018                         LOGE("failed to commit");
13019                         MMPLAYER_FLEAVE();
13020                         return MM_ERROR_PLAYER_INTERNAL;
13021                 }
13022         } else {
13023                 LOGE("player->attrs is null, failed to save attributes");
13024                 MMPLAYER_FLEAVE();
13025                 return MM_ERROR_PLAYER_INTERNAL;
13026         }
13027
13028         /* update video param */
13029         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13030                 LOGE("failed to update video param");
13031                 return MM_ERROR_PLAYER_INTERNAL;
13032         }
13033
13034         /* change state of videobin to READY */
13035         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13036         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13037         if (ret != GST_STATE_CHANGE_SUCCESS) {
13038                 LOGE("failed to change state of videobin to READY");
13039                 return MM_ERROR_PLAYER_INTERNAL;
13040         }
13041
13042         /* change ghostpad */
13043         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13044         if (!sink_pad_videosink) {
13045                 LOGE("failed to get sink pad from videosink element");
13046                 return MM_ERROR_PLAYER_INTERNAL;
13047         }
13048         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13049         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13050                 LOGE("failed to set active to ghost_pad");
13051                 return MM_ERROR_PLAYER_INTERNAL;
13052         }
13053         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13054                 LOGE("failed to change ghostpad for videobin");
13055                 return MM_ERROR_PLAYER_INTERNAL;
13056         }
13057         gst_object_unref(sink_pad_videosink);
13058
13059         /* link decoder with videobin */
13060         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13061         if (!sink_pad_videobin) {
13062                 LOGE("failed to get sink pad from videobin");
13063                 return MM_ERROR_PLAYER_INTERNAL;
13064         }
13065         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
13066                 LOGE("failed to link");
13067                 return MM_ERROR_PLAYER_INTERNAL;
13068         }
13069         gst_object_unref(sink_pad_videobin);
13070
13071         /* clock setting for a new videosink plugin */
13072         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13073                         so we set it from audiosink plugin or pipeline(system clock) */
13074         if (!is_audiobin_created) {
13075                 LOGW("audiobin is not created, get clock from pipeline..");
13076                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13077         } else {
13078                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13079         }
13080         if (clock) {
13081                 GstClockTime now;
13082                 GstClockTime base_time;
13083                 LOGD("set the clock to videosink");
13084                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13085                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13086                 if (clock) {
13087                         LOGD("got clock of videosink");
13088                         now = gst_clock_get_time(clock);
13089                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13090                         LOGD("at time %" GST_TIME_FORMAT ", base %"
13091                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13092                 } else {
13093                         LOGE("failed to get clock of videosink after setting clock");
13094                         return MM_ERROR_PLAYER_INTERNAL;
13095                 }
13096         } else
13097                 LOGW("failed to get clock, maybe it is the time before first playing");
13098
13099         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13100                 /* change state of videobin to PAUSED */
13101                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13102                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13103                 if (ret != GST_STATE_CHANGE_FAILURE) {
13104                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13105                 } else {
13106                         LOGE("failed to change state of videobin to PLAYING");
13107                         return MM_ERROR_PLAYER_INTERNAL;
13108                 }
13109
13110                 /* release blocked and unref src pad of video decoder */
13111                 #if 0
13112                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13113                         LOGE("failed to set pad blocked FALSE(video)");
13114                         return MM_ERROR_PLAYER_INTERNAL;
13115                 }
13116                 #endif
13117                 LOGW("pad is unblocked(video)");
13118         } else {
13119                 if (player->doing_seek)
13120                         LOGW("not completed seek(%d)", player->doing_seek);
13121                 /* change state of videobin to PAUSED */
13122                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13123                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13124                 if (ret != GST_STATE_CHANGE_FAILURE) {
13125                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13126                 } else {
13127                         LOGE("failed to change state of videobin to PLAYING");
13128                         return MM_ERROR_PLAYER_INTERNAL;
13129                 }
13130
13131                 /* already skipped pad block */
13132                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
13133         }
13134
13135         /* do get/set position for new videosink plugin */
13136         {
13137                 unsigned long position = 0;
13138                 gint64 pos_msec = 0;
13139
13140                 LOGD("do get/set position for new videosink plugin");
13141                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
13142                         LOGE("failed to get position");
13143                         return MM_ERROR_PLAYER_INTERNAL;
13144                 }
13145 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
13146                 /* accurate seek */
13147                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
13148                         LOGE("failed to set position");
13149                         return MM_ERROR_PLAYER_INTERNAL;
13150                 }
13151 #else
13152                 /* key unit seek */
13153                 pos_msec = position * G_GINT64_CONSTANT(1000000);
13154                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
13155                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
13156                                                         GST_SEEK_TYPE_SET, pos_msec,
13157                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
13158                 if (!ret) {
13159                         LOGE("failed to set position");
13160                         return MM_ERROR_PLAYER_INTERNAL;
13161                 }
13162 #endif
13163         }
13164
13165         if (src_pad_dec)
13166                 gst_object_unref(src_pad_dec);
13167         LOGD("success to change sink");
13168
13169         MMPLAYER_FLEAVE();
13170
13171         return MM_ERROR_NONE;
13172 }
13173
13174
13175 /* Note : if silent is true, then subtitle would not be displayed. :*/
13176 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
13177 {
13178         mm_player_t* player = (mm_player_t*) hplayer;
13179
13180         MMPLAYER_FENTER();
13181
13182         /* check player handle */
13183         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13184
13185         player->set_mode.subtitle_off = silent;
13186
13187         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
13188
13189         MMPLAYER_FLEAVE();
13190
13191         return MM_ERROR_NONE;
13192 }
13193
13194 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
13195 {
13196         MMPlayerGstElement* mainbin = NULL;
13197         MMPlayerGstElement* textbin = NULL;
13198         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
13199         GstState current_state = GST_STATE_VOID_PENDING;
13200         GstState element_state = GST_STATE_VOID_PENDING;
13201         GstState element_pending_state = GST_STATE_VOID_PENDING;
13202         gint64 time = 0;
13203         GstEvent *event = NULL;
13204         int result = MM_ERROR_NONE;
13205
13206         GstClock *curr_clock = NULL;
13207         GstClockTime base_time, start_time, curr_time;
13208
13209
13210         MMPLAYER_FENTER();
13211
13212         /* check player handle */
13213         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
13214                                                                 player->pipeline &&
13215                                                                 player->pipeline->mainbin &&
13216                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13217
13218         mainbin = player->pipeline->mainbin;
13219         textbin = player->pipeline->textbin;
13220
13221         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13222
13223         // sync clock with current pipeline
13224         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13225         curr_time = gst_clock_get_time(curr_clock);
13226
13227         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
13228         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
13229
13230         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
13231                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
13232
13233         if (current_state > GST_STATE_READY) {
13234                 // sync state with current pipeline
13235                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
13236                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
13237                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
13238
13239                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
13240                 if (GST_STATE_CHANGE_FAILURE == ret) {
13241                         LOGE("fail to state change.\n");
13242                         result = MM_ERROR_PLAYER_INTERNAL;
13243                         goto ERROR;
13244                 }
13245         }
13246
13247         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
13248         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
13249
13250         if (curr_clock) {
13251                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
13252                 gst_object_unref(curr_clock);
13253         }
13254
13255         // seek to current position
13256         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
13257                 result = MM_ERROR_PLAYER_INVALID_STATE;
13258                 LOGE("gst_element_query_position failed, invalid state\n");
13259                 goto ERROR;
13260         }
13261
13262         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
13263         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);
13264         if (event) {
13265                 __gst_send_event_to_sink(player, event);
13266         } else {
13267                 result = MM_ERROR_PLAYER_INTERNAL;
13268                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
13269                 goto ERROR;
13270         }
13271
13272         /* sync state with current pipeline */
13273         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
13274         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
13275         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
13276
13277         return MM_ERROR_NONE;
13278
13279 ERROR:
13280         /* release text pipeline resource */
13281         player->textsink_linked = 0;
13282
13283         /* release signal */
13284         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13285
13286         /* release textbin with it's childs */
13287         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
13288         MMPLAYER_FREEIF(player->pipeline->textbin);
13289         player->pipeline->textbin = NULL;
13290
13291         /* release subtitle elem */
13292         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
13293         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
13294
13295         return result;
13296 }
13297
13298 static int
13299 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
13300 {
13301         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
13302         GstState current_state = GST_STATE_VOID_PENDING;
13303
13304         MMHandleType attrs = 0;
13305         MMPlayerGstElement* mainbin = NULL;
13306         MMPlayerGstElement* textbin = NULL;
13307
13308         gchar* subtitle_uri = NULL;
13309         int result = MM_ERROR_NONE;
13310         const gchar *charset = NULL;
13311
13312         MMPLAYER_FENTER();
13313
13314         /* check player handle */
13315         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
13316                                                                 player->pipeline &&
13317                                                                 player->pipeline->mainbin &&
13318                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13319         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
13320
13321         mainbin = player->pipeline->mainbin;
13322         textbin = player->pipeline->textbin;
13323
13324         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13325         if (current_state < GST_STATE_READY) {
13326                 result = MM_ERROR_PLAYER_INVALID_STATE;
13327                 LOGE("Pipeline is not in proper state\n");
13328                 goto EXIT;
13329         }
13330
13331         attrs = MMPLAYER_GET_ATTRS(player);
13332         if (!attrs) {
13333                 LOGE("cannot get content attribute\n");
13334                 result = MM_ERROR_PLAYER_INTERNAL;
13335                 goto EXIT;
13336         }
13337
13338         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13339         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
13340                 LOGE("subtitle uri is not proper filepath\n");
13341                 result = MM_ERROR_PLAYER_INVALID_URI;
13342                 goto EXIT;
13343         }
13344
13345         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
13346                 LOGE("failed to get storage info of subtitle path");
13347                 result = MM_ERROR_PLAYER_INVALID_URI;
13348                 goto EXIT;
13349         }
13350
13351         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
13352         LOGD("new subtitle file path is [%s]\n", filepath);
13353
13354         if (!strcmp(filepath, subtitle_uri)) {
13355                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
13356                 goto EXIT;
13357         } else {
13358                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13359                 if (mmf_attrs_commit(player->attrs)) {
13360                         LOGE("failed to commit.\n");
13361                         goto EXIT;
13362                 }
13363         }
13364
13365         //gst_pad_set_blocked_async(src-srcpad, TRUE)
13366         MMPLAYER_SUBTITLE_INFO_LOCK(player);
13367         player->subtitle_language_list = NULL;
13368         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
13369
13370         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
13371         if (ret != GST_STATE_CHANGE_SUCCESS) {
13372                 LOGE("failed to change state of textbin to READY");
13373                 result = MM_ERROR_PLAYER_INTERNAL;
13374                 goto EXIT;
13375         }
13376
13377         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
13378         if (ret != GST_STATE_CHANGE_SUCCESS) {
13379                 LOGE("failed to change state of subparse to READY");
13380                 result = MM_ERROR_PLAYER_INTERNAL;
13381                 goto EXIT;
13382         }
13383
13384         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
13385         if (ret != GST_STATE_CHANGE_SUCCESS) {
13386                 LOGE("failed to change state of filesrc to READY");
13387                 result = MM_ERROR_PLAYER_INTERNAL;
13388                 goto EXIT;
13389         }
13390
13391         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
13392
13393         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
13394
13395         charset = util_get_charset(filepath);
13396         if (charset) {
13397                 LOGD("detected charset is %s\n", charset);
13398                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
13399         }
13400
13401         result = _mmplayer_sync_subtitle_pipeline(player);
13402
13403 EXIT:
13404         MMPLAYER_FLEAVE();
13405         return result;
13406 }
13407
13408 /* API to switch between external subtitles */
13409 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
13410 {
13411         int result = MM_ERROR_NONE;
13412         mm_player_t* player = (mm_player_t*)hplayer;
13413         char *path = NULL;
13414
13415         MMPLAYER_FENTER();
13416
13417         /* check player handle */
13418         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13419
13420         /* filepath can be null in idle state */
13421         if (filepath) {
13422                 /* check file path */
13423                 if ((path = strstr(filepath, "file://")))
13424                         result = util_exist_file_path(path + 7);
13425                 else
13426                         result = util_exist_file_path(filepath);
13427
13428
13429                 if (result != MM_ERROR_NONE) {
13430                         LOGE("invalid subtitle path 0x%X", result);
13431                         return result; /* file not found or permission denied */
13432                 }
13433         }
13434
13435         if (!player->pipeline) {
13436                 /* IDLE state */
13437                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13438                 if (mmf_attrs_commit(player->attrs)) {
13439                         LOGE("failed to commit");       /* subtitle path will not be created */
13440                         return MM_ERROR_PLAYER_INTERNAL;
13441                 }
13442         } else {
13443                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
13444                 /* check filepath */
13445                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
13446
13447                 if (!__mmplayer_check_subtitle(player)) {
13448                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13449                         if (mmf_attrs_commit(player->attrs)) {
13450                                 LOGE("failed to commit");
13451                                 return MM_ERROR_PLAYER_INTERNAL;
13452                         }
13453
13454                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
13455                                 LOGE("fail to create text pipeline");
13456                                 return MM_ERROR_PLAYER_INTERNAL;
13457                         }
13458
13459                         result = _mmplayer_sync_subtitle_pipeline(player);
13460                 } else {
13461                         result = __mmplayer_change_external_subtitle_language(player, filepath);
13462                 }
13463
13464                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
13465                 player->is_external_subtitle_added_now = TRUE;
13466
13467                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
13468                 if (!player->subtitle_language_list) {
13469                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
13470                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
13471                                 LOGW("subtitle language list is not updated yet");
13472                 }
13473                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
13474         }
13475
13476         MMPLAYER_FLEAVE();
13477         return result;
13478 }
13479
13480 static int
13481 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
13482 {
13483         int result = MM_ERROR_NONE;
13484         gchar* change_pad_name = NULL;
13485         GstPad* sinkpad = NULL;
13486         MMPlayerGstElement* mainbin = NULL;
13487         enum MainElementID elemId = MMPLAYER_M_NUM;
13488         GstCaps* caps = NULL;
13489         gint total_track_num = 0;
13490
13491         MMPLAYER_FENTER();
13492
13493         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
13494                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
13495
13496         LOGD("Change Track(%d) to %d\n", type, index);
13497
13498         mainbin = player->pipeline->mainbin;
13499
13500         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
13501                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
13502         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
13503                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
13504         } else {
13505                 /* Changing Video Track is not supported. */
13506                 LOGE("Track Type Error\n");
13507                 goto EXIT;
13508         }
13509
13510         if (mainbin[elemId].gst == NULL) {
13511                 result = MM_ERROR_PLAYER_NO_OP;
13512                 LOGD("Req track doesn't exist\n");
13513                 goto EXIT;
13514         }
13515
13516         total_track_num = player->selector[type].total_track_num;
13517         if (total_track_num <= 0) {
13518                 result = MM_ERROR_PLAYER_NO_OP;
13519                 LOGD("Language list is not available \n");
13520                 goto EXIT;
13521         }
13522
13523         if ((index < 0) || (index >= total_track_num)) {
13524                 result = MM_ERROR_INVALID_ARGUMENT;
13525                 LOGD("Not a proper index : %d \n", index);
13526                 goto EXIT;
13527         }
13528
13529         /*To get the new pad from the selector*/
13530         change_pad_name = g_strdup_printf("sink_%u", index);
13531         if (change_pad_name == NULL) {
13532                 result = MM_ERROR_PLAYER_INTERNAL;
13533                 LOGD("Pad does not exists\n");
13534                 goto EXIT;
13535         }
13536
13537         LOGD("new active pad name: %s\n", change_pad_name);
13538
13539         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
13540         if (sinkpad == NULL) {
13541                 LOGD("sinkpad is NULL");
13542                 result = MM_ERROR_PLAYER_INTERNAL;
13543                 goto EXIT;
13544         }
13545
13546         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
13547         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
13548
13549         caps = gst_pad_get_current_caps(sinkpad);
13550         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13551
13552         if (sinkpad)
13553                 gst_object_unref(sinkpad);
13554
13555         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
13556                 __mmplayer_set_audio_attrs(player, caps);
13557
13558 EXIT:
13559
13560         MMPLAYER_FREEIF(change_pad_name);
13561         return result;
13562 }
13563
13564 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
13565 {
13566         int result = MM_ERROR_NONE;
13567         mm_player_t* player = NULL;
13568         MMPlayerGstElement* mainbin = NULL;
13569
13570         gint current_active_index = 0;
13571
13572         GstState current_state = GST_STATE_VOID_PENDING;
13573         GstEvent* event = NULL;
13574         gint64 time = 0;
13575
13576         MMPLAYER_FENTER();
13577
13578         player = (mm_player_t*)hplayer;
13579         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13580
13581         if (!player->pipeline) {
13582                 LOGE("Track %d pre setting -> %d\n", type, index);
13583
13584                 player->selector[type].active_pad_index = index;
13585                 goto EXIT;
13586         }
13587
13588         mainbin = player->pipeline->mainbin;
13589
13590         current_active_index = player->selector[type].active_pad_index;
13591
13592         /*If index is same as running index no need to change the pad*/
13593         if (current_active_index == index)
13594                 goto EXIT;
13595
13596         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
13597                 result = MM_ERROR_PLAYER_INVALID_STATE;
13598                 goto EXIT;
13599         }
13600
13601         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13602         if (current_state < GST_STATE_PAUSED) {
13603                 result = MM_ERROR_PLAYER_INVALID_STATE;
13604                 LOGW("Pipeline not in porper state\n");
13605                 goto EXIT;
13606         }
13607
13608         result = __mmplayer_change_selector_pad(player, type, index);
13609         if (result != MM_ERROR_NONE) {
13610                 LOGE("change selector pad error\n");
13611                 goto EXIT;
13612         }
13613
13614         player->selector[type].active_pad_index = index;
13615
13616         if (current_state == GST_STATE_PLAYING) {
13617                 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);
13618                 if (event) {
13619                         __gst_send_event_to_sink(player, event);
13620                 } else {
13621                         result = MM_ERROR_PLAYER_INTERNAL;
13622                         goto EXIT;
13623                 }
13624         }
13625
13626 EXIT:
13627         return result;
13628 }
13629
13630 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
13631 {
13632         mm_player_t* player = (mm_player_t*) hplayer;
13633
13634         MMPLAYER_FENTER();
13635
13636         /* check player handle */
13637         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638
13639         *silent = player->set_mode.subtitle_off;
13640
13641         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
13642
13643         MMPLAYER_FLEAVE();
13644
13645         return MM_ERROR_NONE;
13646 }
13647
13648 gboolean
13649 __is_ms_buff_src(mm_player_t* player)
13650 {
13651         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13652
13653         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
13654 }
13655
13656 gboolean
13657 __has_suffix(mm_player_t* player, const gchar* suffix)
13658 {
13659         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13660         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
13661
13662         gboolean ret = FALSE;
13663         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
13664         gchar* t_suffix = g_ascii_strdown(suffix, -1);
13665
13666         if (g_str_has_suffix(player->profile.uri, suffix))
13667                 ret = TRUE;
13668
13669         MMPLAYER_FREEIF(t_url);
13670         MMPLAYER_FREEIF(t_suffix);
13671
13672         return ret;
13673 }
13674
13675 int
13676 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
13677 {
13678         mm_player_t* player = (mm_player_t*) hplayer;
13679
13680         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13681
13682         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
13683                 MMPLAYER_PRINT_STATE(player);
13684                 LOGE("wrong-state : can't set the download mode to parse");
13685                 return MM_ERROR_PLAYER_INVALID_STATE;
13686         }
13687
13688         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
13689         player->video_hub_download_mode = mode;
13690
13691         return MM_ERROR_NONE;
13692 }
13693
13694 int
13695 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
13696 {
13697         mm_player_t* player = (mm_player_t*) hplayer;
13698
13699         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13700
13701         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
13702         player->sync_handler = enable;
13703
13704         return MM_ERROR_NONE;
13705 }
13706
13707 int
13708 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
13709                                         long long clock,
13710                                         long long clock_delta,
13711                                         long long video_time,
13712                                         long long media_clock,
13713                                         long long audio_time)
13714 {
13715         mm_player_t* player = (mm_player_t*) hplayer;
13716         MMPlayerGstElement* mainbin = NULL;
13717         GstClockTime start_time_audio = 0, start_time_video = 0;
13718         GstClockTimeDiff base_time = 0, new_base_time = 0;
13719         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13720         gint64 api_delta = 0;
13721         gint64 position = 0, position_delta = 0;
13722         gint64 adj_base_time = 0;
13723         GstClock *curr_clock = NULL;
13724         GstClockTime curr_time = 0;
13725         gboolean query_ret = TRUE;
13726         int result = MM_ERROR_NONE;
13727
13728         MMPLAYER_FENTER();
13729
13730         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13731         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13732         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13733
13734         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13735
13736         if ((video_time < 0) || (player->doing_seek)) {
13737                 LOGD("skip setting master clock.  %lld", video_time);
13738                 goto EXIT;
13739         }
13740
13741         mainbin = player->pipeline->mainbin;
13742
13743         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13744         curr_time = gst_clock_get_time(curr_clock);
13745
13746         current_state = MMPLAYER_CURRENT_STATE(player);
13747
13748         if (current_state == MM_PLAYER_STATE_PLAYING)
13749                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13750
13751         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13752                 (!query_ret)) {
13753                 position = player->last_position;
13754                 LOGD("query fail. %lld", position);
13755         }
13756
13757         clock *= GST_USECOND;
13758         clock_delta *= GST_USECOND;
13759
13760         api_delta = clock - curr_time;
13761         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13762                 player->video_share_api_delta = api_delta;
13763         else
13764                 clock_delta += (api_delta - player->video_share_api_delta);
13765
13766         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13767                 player->video_share_clock_delta = (gint64)clock_delta;
13768
13769                 position_delta = (position/GST_USECOND) - video_time;
13770                 position_delta *= GST_USECOND;
13771
13772                 adj_base_time = position_delta;
13773                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13774
13775         } else {
13776                 gint64 new_play_time = 0;
13777                 gint64 network_delay = 0;
13778
13779                 video_time *= GST_USECOND;
13780
13781                 network_delay = clock_delta - player->video_share_clock_delta;
13782                 new_play_time = video_time + network_delay;
13783
13784                 adj_base_time = position - new_play_time;
13785
13786                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13787                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13788         }
13789
13790         /* Adjust Current Stream Time with base_time of sink
13791          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13792          * 2. Set new base time
13793          *    if adj_base_time is positive value, the stream time will be decreased.
13794          * 3. If seek event is occurred, the start time will be reset. */
13795         if ((player->pipeline->audiobin) &&
13796                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13797                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13798
13799                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13800                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13801                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13802                 }
13803
13804                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13805         }
13806
13807         if ((player->pipeline->videobin) &&
13808                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13809                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13810
13811                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13812                         LOGD("video sink : gst_element_set_start_time -> NONE");
13813                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13814                 }
13815
13816                 // if videobin exist, get base_time from videobin.
13817                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13818         }
13819
13820         new_base_time = base_time + adj_base_time;
13821
13822         if ((player->pipeline->audiobin) &&
13823                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13824                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13825
13826         if ((player->pipeline->videobin) &&
13827                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13828                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13829
13830 EXIT:
13831         MMPLAYER_FLEAVE();
13832
13833         return result;
13834 }
13835
13836 int
13837 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13838                                         long long *video_time,
13839                                         long long *media_clock,
13840                                         long long *audio_time)
13841 {
13842         mm_player_t* player = (mm_player_t*) hplayer;
13843         MMPlayerGstElement* mainbin = NULL;
13844         GstClock *curr_clock = NULL;
13845         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13846         gint64 position = 0;
13847         gboolean query_ret = TRUE;
13848
13849         MMPLAYER_FENTER();
13850
13851         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13852         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13853         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13854
13855         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13856         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13857         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13858
13859         mainbin = player->pipeline->mainbin;
13860
13861         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13862
13863         current_state = MMPLAYER_CURRENT_STATE(player);
13864
13865         if (current_state != MM_PLAYER_STATE_PAUSED)
13866                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13867
13868         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13869                 (!query_ret))
13870                 position = player->last_position;
13871
13872         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13873
13874         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13875
13876         if (curr_clock)
13877                 gst_object_unref(curr_clock);
13878
13879         MMPLAYER_FLEAVE();
13880
13881         return MM_ERROR_NONE;
13882 }
13883
13884 static gboolean
13885 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13886 {
13887         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13888         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13889
13890         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13891         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13892
13893         int idx = 0;
13894
13895         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13896                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13897                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13898                         mm_player_dump_t *dump_s;
13899                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13900
13901                         if (dump_s == NULL) {
13902                                 LOGE("malloc fail");
13903                                 return FALSE;
13904                         }
13905
13906                         dump_s->dump_element_file = NULL;
13907                         dump_s->dump_pad = NULL;
13908                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13909
13910                         if (dump_s->dump_pad) {
13911                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13912                                 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]);
13913                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13914                                 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);
13915                                 /* add list for removed buffer probe and close FILE */
13916                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13917                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13918                                 return TRUE;
13919                         } else {
13920                                 g_free(dump_s);
13921                                 dump_s = NULL;
13922                                 LOGE("failed to get %s sink pad added", factory_name);
13923                         }
13924
13925
13926                 }
13927         }
13928         return FALSE;
13929 }
13930
13931 static GstPadProbeReturn
13932 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13933 {
13934         FILE *dump_data = (FILE *) u_data;
13935 //      int written = 0;
13936         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13937         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13938
13939         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13940
13941         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13942
13943 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13944
13945         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13946
13947         return GST_PAD_PROBE_OK;
13948 }
13949
13950 static void
13951 __mmplayer_release_dump_list(GList *dump_list)
13952 {
13953         if (dump_list) {
13954                 GList *d_list = dump_list;
13955                 for (; d_list; d_list = g_list_next(d_list)) {
13956                         mm_player_dump_t *dump_s = d_list->data;
13957                         if (dump_s->dump_pad) {
13958                                 if (dump_s->probe_handle_id)
13959                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13960                         }
13961                         if (dump_s->dump_element_file) {
13962                                 fclose(dump_s->dump_element_file);
13963                                 dump_s->dump_element_file = NULL;
13964                         }
13965                         MMPLAYER_FREEIF(dump_s);
13966                 }
13967                 g_list_free(dump_list);
13968                 dump_list = NULL;
13969         }
13970 }
13971
13972 int
13973 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13974 {
13975         mm_player_t* player = (mm_player_t*) hplayer;
13976
13977         MMPLAYER_FENTER();
13978
13979         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13980         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13981
13982         *exist = player->has_closed_caption;
13983
13984         MMPLAYER_FLEAVE();
13985
13986         return MM_ERROR_NONE;
13987 }
13988
13989 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13990 {
13991         MMPLAYER_FENTER();
13992         if (buffer) {
13993                 // LOGD("unref internal gst buffer %p", buffer);
13994                 gst_buffer_unref((GstBuffer *)buffer);
13995                 buffer = NULL;
13996         }
13997         MMPLAYER_FLEAVE();
13998 }
13999
14000 void
14001 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14002 {
14003         mm_player_t *player  = (mm_player_t*)user_data;
14004         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14005         guint64 current_level_bytes = 0;
14006
14007         MMPLAYER_RETURN_IF_FAIL(player);
14008
14009         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14010
14011         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14012         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14013
14014         if (player->media_stream_buffer_status_cb[type])
14015                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14016         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14017
14018 }
14019
14020 void
14021 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
14022 {
14023         mm_player_t *player  = (mm_player_t*)user_data;
14024         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14025         guint64 current_level_bytes = 0;
14026
14027         MMPLAYER_RETURN_IF_FAIL(player);
14028
14029         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14030
14031         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
14032
14033         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14034         if (player->media_stream_buffer_status_cb[type])
14035                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14036         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14037 }
14038
14039 void
14040 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
14041 {
14042         mm_player_t *player  = (mm_player_t*)user_data;
14043         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14044         guint64 current_level_bytes = 0;
14045
14046         MMPLAYER_RETURN_IF_FAIL(player);
14047
14048         LOGI("app-src: feed subtitle\n");
14049
14050         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14051
14052         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14053         if (player->media_stream_buffer_status_cb[type])
14054                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14055
14056         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14057 }
14058
14059 void
14060 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
14061 {
14062         mm_player_t *player  = (mm_player_t*)user_data;
14063         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14064         guint64 current_level_bytes = 0;
14065
14066         MMPLAYER_RETURN_IF_FAIL(player);
14067
14068         LOGI("app-src: audio buffer is full.\n");
14069
14070         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14071
14072         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14073
14074         if (player->media_stream_buffer_status_cb[type])
14075                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
14076
14077         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14078 }
14079
14080 void
14081 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
14082 {
14083         mm_player_t *player  = (mm_player_t*)user_data;
14084         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14085         guint64 current_level_bytes = 0;
14086
14087         MMPLAYER_RETURN_IF_FAIL(player);
14088
14089         LOGI("app-src: video buffer is full.\n");
14090
14091         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14092
14093         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14094         if (player->media_stream_buffer_status_cb[type])
14095                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
14096
14097         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14098 }
14099
14100 gboolean
14101 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
14102 {
14103         mm_player_t *player  = (mm_player_t*)user_data;
14104         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14105
14106         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14107
14108         LOGD("app-src: seek audio data %llu\n", position);
14109         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14110
14111         if (player->media_stream_seek_data_cb[type])
14112                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14113         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14114
14115         return TRUE;
14116 }
14117
14118 gboolean
14119 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
14120 {
14121         mm_player_t *player  = (mm_player_t*)user_data;
14122         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14123
14124         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14125
14126         LOGD("app-src: seek video data %llu\n", position);
14127         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14128         if (player->media_stream_seek_data_cb[type])
14129                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14130         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14131
14132         return TRUE;
14133 }
14134
14135 gboolean
14136 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
14137 {
14138         mm_player_t *player  = (mm_player_t*)user_data;
14139         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14140
14141         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14142
14143         LOGD("app-src: seek subtitle data\n");
14144         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14145
14146         if (player->media_stream_seek_data_cb[type])
14147                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14148         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14149
14150         return TRUE;
14151 }
14152
14153 int
14154 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
14155 {
14156         mm_player_t* player = (mm_player_t*) hplayer;
14157
14158         MMPLAYER_FENTER();
14159
14160         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14161
14162         player->pcm_samplerate = samplerate;
14163         player->pcm_channel = channel;
14164
14165         MMPLAYER_FLEAVE();
14166         return MM_ERROR_NONE;
14167 }
14168
14169 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
14170 {
14171         mm_player_t* player = (mm_player_t*) hplayer;
14172
14173         MMPLAYER_FENTER();
14174
14175         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14176         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
14177
14178         if (MMPLAYER_IS_STREAMING(player))
14179                 *timeout = player->ini.live_state_change_timeout;
14180         else
14181                 *timeout = player->ini.localplayback_state_change_timeout;
14182
14183         LOGD("timeout = %d\n", *timeout);
14184
14185         MMPLAYER_FLEAVE();
14186         return MM_ERROR_NONE;
14187 }
14188
14189 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
14190 {
14191         mm_player_t* player = (mm_player_t*) hplayer;
14192
14193         MMPLAYER_FENTER();
14194
14195         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14196         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
14197
14198         *num = player->video_num_buffers;
14199         *extra_num = player->video_extra_num_buffers;
14200
14201         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
14202
14203         MMPLAYER_FLEAVE();
14204         return MM_ERROR_NONE;
14205 }
14206
14207 static void
14208 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
14209 {
14210         int i = 0;
14211         MMPLAYER_FENTER();
14212         MMPLAYER_RETURN_IF_FAIL(player);
14213
14214         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
14215
14216                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
14217                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
14218                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
14219                         player->storage_info[i].id = -1;
14220                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
14221
14222                         if (path_type != MMPLAYER_PATH_MAX)
14223                                 break;
14224                 }
14225         }
14226
14227         MMPLAYER_FLEAVE();
14228 }
14229
14230 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
14231 {
14232         int ret = MM_ERROR_NONE;
14233         mm_player_t* player = (mm_player_t*)hplayer;
14234         MMMessageParamType msg_param = {0, };
14235
14236         MMPLAYER_FENTER();
14237         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14238
14239         LOGW("state changed storage %d:%d", id, state);
14240
14241         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
14242                 return MM_ERROR_NONE;
14243
14244         /* FIXME: text path should be handled seperately. */
14245         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
14246                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
14247                 LOGW("external storage is removed");
14248
14249                 if (player->msg_posted == FALSE) {
14250                         memset(&msg_param, 0, sizeof(MMMessageParamType));
14251                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
14252                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
14253                         player->msg_posted = TRUE;
14254                 }
14255
14256                 /* unrealize the player */
14257                 ret = _mmplayer_unrealize(hplayer);
14258                 if (ret != MM_ERROR_NONE)
14259                         LOGE("failed to unrealize");
14260         }
14261
14262         MMPLAYER_FLEAVE();
14263         return ret;
14264 }
14265
14266 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
14267 {
14268         int ret = MM_ERROR_NONE;
14269         mm_player_t* player = (mm_player_t*) hplayer;
14270         int idx = 0, total = 0;
14271         gchar *result = NULL, *tmp = NULL;
14272
14273         MMPLAYER_FENTER();
14274         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14275         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
14276
14277         total = *num = g_list_length(player->adaptive_info.var_list);
14278         if (total <= 0) {
14279                 LOGW("There is no stream variant info.");
14280                 return ret;
14281         }
14282
14283         result = g_strdup("");
14284         for (idx = 0 ; idx < total ; idx++) {
14285                 VariantData *v_data = NULL;
14286                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
14287
14288                 if (v_data) {
14289                         gchar data[64] = {0};
14290                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
14291
14292                         tmp = g_strconcat(result, data, NULL);
14293                         g_free(result);
14294                         result = tmp;
14295                 } else {
14296                         LOGW("There is no variant data in %d", idx);
14297                         (*num)--;
14298                 }
14299         }
14300
14301         *var_info = (char *)result;
14302
14303         LOGD("variant info %d:%s", *num, *var_info);
14304         MMPLAYER_FLEAVE();
14305         return ret;
14306 }
14307
14308 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
14309 {
14310         int ret = MM_ERROR_NONE;
14311         mm_player_t* player = (mm_player_t*) hplayer;
14312
14313         MMPLAYER_FENTER();
14314         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14315
14316         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
14317
14318         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14319         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14320         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14321
14322         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
14323                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
14324                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
14325                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
14326
14327                 /* FIXME: seek to current position for applying new variant limitation */
14328         }
14329
14330         MMPLAYER_FLEAVE();
14331         return ret;
14332
14333 }
14334
14335 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
14336 {
14337         int ret = MM_ERROR_NONE;
14338         mm_player_t* player = (mm_player_t*) hplayer;
14339
14340         MMPLAYER_FENTER();
14341         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14342         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
14343
14344         *bandwidth = player->adaptive_info.limit.bandwidth;
14345         *width = player->adaptive_info.limit.width;
14346         *height = player->adaptive_info.limit.height;
14347
14348         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
14349
14350         MMPLAYER_FLEAVE();
14351         return ret;
14352 }
14353
14354 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
14355 {
14356         int ret = MM_ERROR_NONE;
14357         mm_player_t* player = (mm_player_t*) hplayer;
14358
14359         MMPLAYER_FENTER();
14360         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14361
14362         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
14363                 LOGW("buffer_ms will not be applied.");
14364
14365
14366         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
14367
14368         if (player->streamer == NULL) {
14369                 player->streamer = __mm_player_streaming_create();
14370                 __mm_player_streaming_initialize(player->streamer);
14371         }
14372
14373         if (buffer_ms >= 0)
14374                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
14375
14376         if (rebuffer_ms >= 0)
14377                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
14378
14379         MMPLAYER_FLEAVE();
14380         return ret;
14381
14382 }
14383
14384 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
14385 {
14386         int ret = MM_ERROR_NONE;
14387         mm_player_t* player = (mm_player_t*) hplayer;
14388
14389         MMPLAYER_FENTER();
14390         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14391         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
14392
14393         if (player->streamer == NULL) {
14394                 player->streamer = __mm_player_streaming_create();
14395                 __mm_player_streaming_initialize(player->streamer);
14396         }
14397
14398         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
14399         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
14400
14401         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
14402
14403         MMPLAYER_FLEAVE();
14404         return ret;
14405 }
14406
14407 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
14408 {
14409 #define IDX_FIRST_SW_CODEC 0
14410         mm_player_t* player = (mm_player_t*) hplayer;
14411         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
14412         MMHandleType attrs = 0;
14413
14414         MMPLAYER_FENTER();
14415         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14416
14417         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
14418                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
14419                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
14420
14421         switch (stream_type) {
14422         case MM_PLAYER_STREAM_TYPE_AUDIO:
14423                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
14424                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
14425                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
14426                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
14427                         LOGE("There is no a codec for codec_type %d", codec_type);
14428                         return MM_ERROR_PLAYER_NO_OP;
14429                 }
14430         break;
14431         case MM_PLAYER_STREAM_TYPE_VIDEO:
14432                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
14433                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
14434                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
14435                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
14436                         LOGE("There is no v codec for codec_type %d", codec_type);
14437                         return MM_ERROR_PLAYER_NO_OP;
14438                 }
14439
14440         break;
14441         default:
14442                 LOGE("Invalid stream type %d", stream_type);
14443                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14444         break;
14445         }
14446
14447         LOGD("update %s codec_type to %d", attr_name, codec_type);
14448
14449         attrs = MMPLAYER_GET_ATTRS(player);
14450         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
14451
14452         if (mmf_attrs_commit(player->attrs)) {
14453                 LOGE("failed to commit codec_type attributes");
14454                 return MM_ERROR_PLAYER_INTERNAL;
14455         }
14456
14457         MMPLAYER_FLEAVE();
14458         return MM_ERROR_NONE;
14459 }