Use gst_video_overlay_set_roi_area interface instead of old interface
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
58 |                                                                                                                                                                                       |
59 ========================================================================================== */
60
61 /*---------------------------------------------------------------------------
62 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
63 ---------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------
66 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
67 ---------------------------------------------------------------------------*/
68
69 /*---------------------------------------------------------------------------
70 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
71 ---------------------------------------------------------------------------*/
72
73 /*---------------------------------------------------------------------------
74 |    LOCAL #defines:                                                                                                            |
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
78
79 #define MM_VOLUME_FACTOR_DEFAULT                1.0
80 #define MM_VOLUME_FACTOR_MIN                    0
81 #define MM_VOLUME_FACTOR_MAX                    1.0
82
83 /* Don't need to sleep for sound fadeout
84  * fadeout related fucntion will be deleted(Deprecated)
85  */
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
87
88 #define DEFAULT_PLAYBACK_RATE                   1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
90
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93         (player->ini.http_use_file_buffer) && \
94         (player->http_file_buffering_path) && \
95         (strlen(player->http_file_buffering_path) > 0))
96
97 #define PLAYER_DISPLAY_MODE_DST_ROI             5
98
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
100
101 /* For PD mode */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE             1024 * 1024 * 3
103
104 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
108
109 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
139
140 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
146 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157
158 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
159 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
175
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
189
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
193
194 static int              __gst_realize(mm_player_t* player);
195 static int              __gst_unrealize(mm_player_t* player);
196 static int              __gst_start(mm_player_t* player);
197 static int              __gst_stop(mm_player_t* player);
198 static int              __gst_pause(mm_player_t* player, gboolean async);
199 static int              __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202                                         gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
204
205 static int              __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int              __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
210
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
212
213 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
214
215 /* util */
216 static gboolean __is_ms_buff_src(mm_player_t* player);
217 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
218
219 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
220 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
221 static int __mmplayer_start_streaming_ext(mm_player_t *player);
222 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
223 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
224
225 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
226 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
227 static void __mmplayer_check_pipeline(mm_player_t* player);
228 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
229 static void __mmplayer_deactivate_old_path(mm_player_t *player);
230
231 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
232 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
233
234 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
235 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
236 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
237 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
238 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
239 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
240 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
241 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
242 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
245 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
246 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
247 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
248 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
249 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
250 static void             __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type);
251
252 /*===========================================================================================
253 |                                                                                                                                                                                       |
254 |  FUNCTION DEFINITIONS                                                                                                                                         |
255 |                                                                                                                                                                                       |
256 ========================================================================================== */
257
258 #if 0 //debug
259 static void
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
261 {
262         gint i, count;
263
264         count = gst_tag_list_get_tag_size(list, tag);
265
266         LOGD("count = %d", count);
267
268         for (i = 0; i < count; i++) {
269                 gchar *str;
270
271                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
273                                 g_assert_not_reached();
274                 } else
275                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
276
277                 if (i == 0)
278                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
279                 else
280                         g_print("                 : %s\n", str);
281
282                 g_free(str);
283         }
284 }
285 #endif
286
287 /* This function should be called after the pipeline goes PAUSED or higher
288 state. */
289 gboolean
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
291 {
292         static gboolean has_duration = FALSE;
293         static gboolean has_video_attrs = FALSE;
294         static gboolean has_audio_attrs = FALSE;
295         static gboolean has_bitrate = FALSE;
296         gboolean missing_only = FALSE;
297         gboolean all = FALSE;
298         gint64 dur_nsec = 0;
299         GstStructure* p = NULL;
300         MMHandleType attrs = 0;
301         gchar *path = NULL;
302         struct stat sb;
303
304         MMPLAYER_FENTER();
305
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
307
308         /* check player state here */
309         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311                 /* give warning now only */
312                 LOGW("be careful. content attributes may not available in this state ");
313         }
314
315         /* get content attribute first */
316         attrs = MMPLAYER_GET_ATTRS(player);
317         if (!attrs) {
318                 LOGE("cannot get content attribute");
319                 return FALSE;
320         }
321
322         /* get update flag */
323
324         if (flag & ATTR_MISSING_ONLY) {
325                 missing_only = TRUE;
326                 LOGD("updating missed attr only");
327         }
328
329         if (flag & ATTR_ALL) {
330                 all = TRUE;
331                 has_duration = FALSE;
332                 has_video_attrs = FALSE;
333                 has_audio_attrs = FALSE;
334                 has_bitrate = FALSE;
335
336                 LOGD("updating all attrs");
337         }
338
339         if (missing_only && all) {
340                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341                 missing_only = FALSE;
342         }
343
344         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345                 LOGD("try to update duration");
346                 has_duration = FALSE;
347
348                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349                         player->duration = dur_nsec;
350                         LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
351                         has_duration = TRUE;
352                 }
353
354                 if (player->duration < 0) {
355                         LOGW("duration is Non-Initialized !!!");
356                         player->duration = 0;
357                 }
358
359                 /* update streaming service type */
360                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
361
362                 /* check duration is OK */
363                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364                         /* FIXIT : find another way to get duration here. */
365                         LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
366                 }
367         }
368
369         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370                 /* update audio params
371                 NOTE : We need original audio params and it can be only obtained from src pad of audio
372                 decoder. Below code only valid when we are not using 'resampler' just before
373                 'audioconverter'. */
374
375                 LOGD("try to update audio attrs");
376                 has_audio_attrs = FALSE;
377
378                 if (player->pipeline->audiobin &&
379                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380                         GstCaps *caps_a = NULL;
381                         GstPad* pad = NULL;
382                         gint samplerate = 0, channels = 0;
383
384                         pad = gst_element_get_static_pad(
385                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
386
387                         if (pad) {
388                                 caps_a = gst_pad_get_current_caps(pad);
389
390                                 if (caps_a) {
391                                         p = gst_caps_get_structure(caps_a, 0);
392
393                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
394
395                                         gst_structure_get_int(p, "rate", &samplerate);
396                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
397
398                                         gst_structure_get_int(p, "channels", &channels);
399                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
400
401                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
402
403                                         gst_caps_unref(caps_a);
404                                         caps_a = NULL;
405
406                                         has_audio_attrs = TRUE;
407                                 } else
408                                         LOGW("not ready to get audio caps");
409
410                                 gst_object_unref(pad);
411                         } else
412                                 LOGW("failed to get pad from audiosink");
413                 }
414         }
415
416         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417                 LOGD("try to update video attrs");
418                 has_video_attrs = FALSE;
419
420                 if (player->pipeline->videobin &&
421                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422                         GstCaps *caps_v = NULL;
423                         GstPad* pad = NULL;
424                         gint tmpNu, tmpDe;
425                         gint width, height;
426
427                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
428                         if (pad) {
429                                 caps_v = gst_pad_get_current_caps(pad);
430
431                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432                                 if (!caps_v && player->v_stream_caps) {
433                                         caps_v = player->v_stream_caps;
434                                         gst_caps_ref(caps_v);
435                                 }
436
437                                 if (caps_v) {
438                                         p = gst_caps_get_structure(caps_v, 0);
439                                         gst_structure_get_int(p, "width", &width);
440                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
441
442                                         gst_structure_get_int(p, "height", &height);
443                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
444
445                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
446
447                                         SECURE_LOGD("width : %d     height : %d", width, height);
448
449                                         gst_caps_unref(caps_v);
450                                         caps_v = NULL;
451
452                                         if (tmpDe > 0) {
453                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
455                                         }
456
457                                         has_video_attrs = TRUE;
458                                 } else
459                                         LOGD("no negitiated caps from videosink");
460                                 gst_object_unref(pad);
461                                 pad = NULL;
462                         } else {
463                                 LOGD("no videosink sink pad");
464                         }
465                 }
466         }
467
468
469         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
470                 has_bitrate = FALSE;
471
472                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473                 if (player->duration) {
474                         guint64 data_size = 0;
475
476                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
478
479                                 if (stat(path, &sb) == 0)
480                                         data_size = (guint64)sb.st_size;
481                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482                                 data_size = player->http_content_size;
483                         }
484                         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
485
486                         if (data_size) {
487                                 guint64 bitrate = 0;
488                                 guint64 msec_dur = 0;
489
490                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
491                                 if (msec_dur > 0) {
492                                         bitrate = data_size * 8 * 1000 / msec_dur;
493                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
495
496                                         has_bitrate = TRUE;
497                                 } else {
498                                         LOGD("player duration is less than 0");
499                                 }
500                         }
501
502                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503                                 if (player->total_bitrate) {
504                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
505                                         has_bitrate = TRUE;
506                                 }
507                         }
508                 }
509         }
510
511         /* validate all */
512         if (mmf_attrs_commit(attrs)) {
513                 LOGE("failed to update attributes\n");
514                 return FALSE;
515         }
516
517         MMPLAYER_FLEAVE();
518
519         return TRUE;
520 }
521
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
523 {
524         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
525
526         MMPLAYER_FENTER();
527
528         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
529                         player->pipeline &&
530                         player->pipeline->mainbin &&
531                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532                         STREAMING_SERVICE_NONE);
533
534         /* streaming service type if streaming */
535         if (!MMPLAYER_IS_STREAMING(player))
536                 return STREAMING_SERVICE_NONE;
537
538         if (MMPLAYER_IS_HTTP_STREAMING(player))
539                 streaming_type = (player->duration == 0) ?
540                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
541
542         switch (streaming_type) {
543         case STREAMING_SERVICE_LIVE:
544                 LOGD("it's live streaming");
545                 break;
546         case STREAMING_SERVICE_VOD:
547                 LOGD("it's vod streaming");
548                 break;
549         default:
550                 LOGE("should not get here");
551                 break;
552         }
553
554         MMPLAYER_FLEAVE();
555
556         return streaming_type;
557 }
558
559
560 /* this function sets the player state and also report
561  * it to applicaton by calling callback function
562  */
563 void
564 __mmplayer_set_state(mm_player_t* player, int state)
565 {
566         MMMessageParamType msg = {0, };
567         gboolean post_bos = FALSE;
568
569         MMPLAYER_RETURN_IF_FAIL(player);
570
571         if (MMPLAYER_CURRENT_STATE(player) == state) {
572                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
574                 return;
575         }
576
577         /* update player states */
578         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579         MMPLAYER_CURRENT_STATE(player) = state;
580
581         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
583
584         /* print state */
585         MMPLAYER_PRINT_STATE(player);
586
587         switch (MMPLAYER_CURRENT_STATE(player)) {
588         case MM_PLAYER_STATE_NULL:
589         case MM_PLAYER_STATE_READY:
590                 break;
591
592         case MM_PLAYER_STATE_PAUSED:
593                 {
594                         if (!player->sent_bos) {
595                                 /* rtsp case, get content attrs by GstMessage */
596                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597                                         /* it's first time to update all content attrs. */
598                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
599                                 }
600                         }
601
602                         /* add audio callback probe if condition is satisfied */
603                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604                                 __mmplayer_configure_audio_callback(player);
605
606                         /* FIXIT : handle return value */
607                 }
608                 break;
609
610         case MM_PLAYER_STATE_PLAYING:
611                 {
612                         /* try to get content metadata */
613                         if (!player->sent_bos) {
614                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
616                                  * legacy mmfw-player api */
617                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
618                         }
619
620                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621                                 if (!player->sent_bos)
622                                         __mmplayer_handle_missed_plugin(player);
623                         }
624
625                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626                                 /* initialize because auto resume is done well. */
627                                 player->resumed_by_rewind = FALSE;
628                                 player->playback_rate = 1.0;
629                         }
630
631                         if (!player->sent_bos) {
632                                 /* check audio codec field is set or not
633                                  * we can get it from typefinder or codec's caps.
634                                  */
635                                 gchar *audio_codec = NULL;
636                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
637
638                                 /* The codec format can't be sent for audio only case like amr, mid etc.
639                                  * Because, parser don't make related TAG.
640                                  * So, if it's not set yet, fill it with found data.
641                                  */
642                                 if (!audio_codec) {
643                                         if (g_strrstr(player->type, "audio/midi"))
644                                                 audio_codec = g_strdup("MIDI");
645                                         else if (g_strrstr(player->type, "audio/x-amr"))
646                                                 audio_codec = g_strdup("AMR");
647                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648                                                 audio_codec = g_strdup("AAC");
649                                         else
650                                                 audio_codec = g_strdup("unknown");
651                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
652
653                                         MMPLAYER_FREEIF(audio_codec);
654                                         if (mmf_attrs_commit(player->attrs))
655                                                 LOGE("failed to update attributes\n");
656
657                                         LOGD("set audio codec type with caps\n");
658                                 }
659
660                                 post_bos = TRUE;
661                         }
662                 }
663                 break;
664
665         case MM_PLAYER_STATE_NONE:
666         default:
667                 LOGW("invalid target state, there is nothing to do.\n");
668                 break;
669         }
670
671
672         /* post message to application */
673         if (MMPLAYER_TARGET_STATE(player) == state) {
674                 /* fill the message with state of player */
675                 msg.union_type = MM_MSG_UNION_STATE;
676                 msg.state.previous = MMPLAYER_PREV_STATE(player);
677                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
678
679                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
680
681                 /* state changed by resource callback */
682                 if (player->interrupted_by_resource) {
683                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
684                 } else { /* state changed by usecase */
685                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
686                 }
687         } else {
688                 LOGD("intermediate state, do nothing.\n");
689                 MMPLAYER_PRINT_STATE(player);
690                 return;
691         }
692
693         if (post_bos) {
694                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
695                 player->sent_bos = TRUE;
696         }
697
698         return;
699 }
700
701 static gpointer __mmplayer_next_play_thread(gpointer data)
702 {
703         mm_player_t* player = (mm_player_t*) data;
704         MMPlayerGstElement *mainbin = NULL;
705
706         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
707
708         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
709         while (!player->next_play_thread_exit) {
710                 LOGD("next play thread started. waiting for signal.\n");
711                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
712
713                 LOGD("reconfigure pipeline for gapless play.\n");
714
715                 if (player->next_play_thread_exit) {
716                         if (player->gapless.reconfigure) {
717                                 player->gapless.reconfigure = false;
718                                 MMPLAYER_PLAYBACK_UNLOCK(player);
719                         }
720                         LOGD("exiting gapless play thread\n");
721                         break;
722                 }
723
724                 mainbin = player->pipeline->mainbin;
725
726                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
731
732                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
733         }
734         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
735
736         return NULL;
737 }
738
739 static void
740 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
741 {
742         MMHandleType attrs = 0;
743         guint64 data_size = 0;
744         gchar* path = NULL;
745         gint64 pos_nsec = 0;
746         struct stat sb;
747
748         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
749
750         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec);       /* to update player->last_position */
751
752         attrs = MMPLAYER_GET_ATTRS(player);
753         if (!attrs) {
754                 LOGE("fail to get attributes.\n");
755                 return;
756         }
757
758         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
759                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
760
761                 if (stat(path, &sb) == 0)
762                         data_size = (guint64)sb.st_size;
763         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
764                 data_size = player->http_content_size;
765
766         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
767         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
768
769         return;
770 }
771
772 static int
773 __mmplayer_handle_buffering_message(mm_player_t* player)
774 {
775         int ret = MM_ERROR_NONE;
776         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
777         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
778         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
779         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
780
781         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
782                 LOGW("do nothing for buffering msg\n");
783                 ret = MM_ERROR_PLAYER_INVALID_STATE;
784                 goto exit;
785         }
786
787         prev_state = MMPLAYER_PREV_STATE(player);
788         current_state = MMPLAYER_CURRENT_STATE(player);
789         target_state = MMPLAYER_TARGET_STATE(player);
790         pending_state = MMPLAYER_PENDING_STATE(player);
791
792         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
793                 MMPLAYER_STATE_GET_NAME(prev_state),
794                 MMPLAYER_STATE_GET_NAME(current_state),
795                 MMPLAYER_STATE_GET_NAME(pending_state),
796                 MMPLAYER_STATE_GET_NAME(target_state),
797                 player->streamer->buffering_state);
798
799         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
800                 /* NOTE : if buffering has done, player has to go to target state. */
801                 switch (target_state) {
802                 case MM_PLAYER_STATE_PAUSED:
803                         {
804                                 switch (pending_state) {
805                                 case MM_PLAYER_STATE_PLAYING:
806                                         __gst_pause(player, TRUE);
807                                         break;
808
809                                 case MM_PLAYER_STATE_PAUSED:
810                                         LOGD("player is already going to paused state, there is nothing to do.\n");
811                                         break;
812
813                                 case MM_PLAYER_STATE_NONE:
814                                 case MM_PLAYER_STATE_NULL:
815                                 case MM_PLAYER_STATE_READY:
816                                 default:
817                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
818                                         break;
819                                 }
820                         }
821                         break;
822
823                 case MM_PLAYER_STATE_PLAYING:
824                         {
825                                 switch (pending_state) {
826                                 case MM_PLAYER_STATE_NONE:
827                                         {
828                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
829                                                         __gst_resume(player, TRUE);
830                                         }
831                                         break;
832
833                                 case MM_PLAYER_STATE_PAUSED:
834                                         /* NOTE: It should be worked as asynchronously.
835                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
836                                          */
837                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
838                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
839                                                  * The current state should be changed to paused purposely to prevent state conflict.
840                                                  */
841                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
842                                         }
843                                         __gst_resume(player, TRUE);
844                                         break;
845
846                                 case MM_PLAYER_STATE_PLAYING:
847                                         LOGD("player is already going to playing state, there is nothing to do.\n");
848                                         break;
849
850                                 case MM_PLAYER_STATE_NULL:
851                                 case MM_PLAYER_STATE_READY:
852                                 default:
853                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
854                                         break;
855                                 }
856                         }
857                         break;
858
859                 case MM_PLAYER_STATE_NULL:
860                 case MM_PLAYER_STATE_READY:
861                 case MM_PLAYER_STATE_NONE:
862                 default:
863                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
864                         break;
865                 }
866         } else {
867                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
868                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
869                  */
870                 switch (pending_state) {
871                 case MM_PLAYER_STATE_NONE:
872                         {
873                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
874                                         /* rtsp streaming pause makes rtsp server stop sending data. */
875                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
876                                                 LOGD("set pause state during buffering\n");
877                                                 __gst_pause(player, TRUE);
878                                         }
879                                 }
880                         }
881                         break;
882
883                 case MM_PLAYER_STATE_PLAYING:
884                         /* rtsp streaming pause makes rtsp server stop sending data. */
885                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
886                                 __gst_pause(player, TRUE);
887                         break;
888
889                 case MM_PLAYER_STATE_PAUSED:
890                         break;
891
892                 case MM_PLAYER_STATE_NULL:
893                 case MM_PLAYER_STATE_READY:
894                 default:
895                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
896                         break;
897                 }
898         }
899
900 exit:
901         return ret;
902 }
903
904 static void
905 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
906 {
907         MMPlayerGstElement *textbin;
908         MMPLAYER_FENTER();
909
910         MMPLAYER_RETURN_IF_FAIL(player &&
911                                         player->pipeline &&
912                                         player->pipeline->textbin);
913
914         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
915
916         textbin = player->pipeline->textbin;
917
918         if (is_drop) {
919                 LOGD("Drop subtitle text after getting EOS\n");
920
921                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
922                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
923
924                 player->is_subtitle_force_drop = TRUE;
925         } else {
926                 if (player->is_subtitle_force_drop == TRUE) {
927                         LOGD("Enable subtitle data path without drop\n");
928
929                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
930                         __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
931
932                         LOGD("non-connected with external display");
933
934                         player->is_subtitle_force_drop = FALSE;
935                 }
936         }
937 }
938
939 static VariantData *
940 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
941 {
942         VariantData *var_info = NULL;
943         g_return_val_if_fail(self != NULL, NULL);
944
945         var_info = g_new0(VariantData, 1);
946         if (!var_info) return NULL;
947         var_info->bandwidth = self->bandwidth;
948         var_info->width = self->width;
949         var_info->height = self->height;
950         return var_info;
951 }
952
953 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
954 {
955         mm_player_t* player = (mm_player_t*)hplayer;
956         GstMessage *msg = NULL;
957         GQueue *queue = NULL;
958
959         MMPLAYER_FENTER();
960         MMPLAYER_RETURN_IF_FAIL(player);
961
962         /* disconnecting bus watch */
963         if (player->bus_watcher)
964                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
965         player->bus_watcher = 0;
966
967         /* destroy the gst bus msg thread */
968         if (player->bus_msg_thread) {
969                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
970                 player->bus_msg_thread_exit = TRUE;
971                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
972                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
973
974                 LOGD("gst bus msg thread exit.");
975                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
976                 player->bus_msg_thread = NULL;
977
978                 g_mutex_clear(&player->bus_msg_thread_mutex);
979                 g_cond_clear(&player->bus_msg_thread_cond);
980         }
981
982         g_mutex_lock(&player->bus_msg_q_lock);
983         queue = player->bus_msg_q;
984         while (!g_queue_is_empty(queue)) {
985                 msg = (GstMessage *)g_queue_pop_head(queue);
986                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
987                 gst_message_unref(msg);
988         }
989         g_mutex_unlock(&player->bus_msg_q_lock);
990
991         MMPLAYER_FLEAVE();
992 }
993
994 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
995 {
996         mm_player_t *player = (mm_player_t *) data;
997
998         g_return_val_if_fail(player, FALSE);
999         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1000
1001         gst_message_ref(msg);
1002
1003         g_mutex_lock(&player->bus_msg_q_lock);
1004         g_queue_push_tail(player->bus_msg_q, msg);
1005         g_mutex_unlock(&player->bus_msg_q_lock);
1006
1007         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1008         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1009         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1010         return TRUE;
1011 }
1012
1013 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1014 {
1015         mm_player_t *player = (mm_player_t*)(data);
1016         GstMessage *msg = NULL;
1017         GstBus *bus = NULL;
1018
1019         MMPLAYER_FENTER();
1020         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1021                                                 player->pipeline &&
1022                                                 player->pipeline->mainbin &&
1023                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1024                                                 NULL);
1025
1026         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1027         if (!bus) {
1028                 LOGE("cannot get BUS from the pipeline");
1029                 return NULL;
1030         }
1031
1032         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1033
1034         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1035         while (!player->bus_msg_thread_exit) {
1036                 g_mutex_lock(&player->bus_msg_q_lock);
1037                 msg = g_queue_pop_head(player->bus_msg_q);
1038                 g_mutex_unlock(&player->bus_msg_q_lock);
1039                 if (msg == NULL) {
1040                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1041                         continue;
1042                 }
1043                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1044                 /* handle the gst msg */
1045                 __mmplayer_gst_callback(msg, player);
1046                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1047                 gst_message_unref(msg);
1048         }
1049
1050         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1051         gst_object_unref(GST_OBJECT(bus));
1052
1053         MMPLAYER_FLEAVE();
1054         return NULL;
1055 }
1056
1057 static void
1058 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1059 {
1060         mm_player_t* player = (mm_player_t*)(data);
1061
1062         MMPLAYER_RETURN_IF_FAIL(player);
1063         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1064
1065         switch (GST_MESSAGE_TYPE(msg)) {
1066         case GST_MESSAGE_UNKNOWN:
1067                 LOGD("unknown message received\n");
1068                 break;
1069
1070         case GST_MESSAGE_EOS:
1071                 {
1072                         MMHandleType attrs = 0;
1073                         gint count = 0;
1074
1075                         LOGD("GST_MESSAGE_EOS received\n");
1076
1077                         /* NOTE : EOS event is comming multiple time. watch out it */
1078                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1079                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1080                                 LOGD("EOS received on non-playing state. ignoring it\n");
1081                                 break;
1082                         }
1083
1084                         if (player->pipeline) {
1085                                 if (player->pipeline->textbin)
1086                                         __mmplayer_drop_subtitle(player, TRUE);
1087
1088                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1089                                         GstPad *pad = NULL;
1090
1091                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1092
1093                                         LOGD("release audio callback\n");
1094
1095                                         /* release audio callback */
1096                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1097                                         player->audio_cb_probe_id = 0;
1098                                         /* audio callback should be free because it can be called even though probe remove.*/
1099                                         player->audio_stream_cb = NULL;
1100                                         player->audio_stream_cb_user_param = NULL;
1101
1102                                 }
1103                         }
1104                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1105                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1106
1107                         /* rewind if repeat count is greater then zero */
1108                         /* get play count */
1109                         attrs = MMPLAYER_GET_ATTRS(player);
1110
1111                         if (attrs) {
1112                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1113
1114                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1115
1116                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1117                                         if (player->playback_rate < 0.0) {
1118                                                 player->resumed_by_rewind = TRUE;
1119                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1120                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1121                                         }
1122
1123                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1124
1125                                         /* initialize */
1126                                         player->sent_bos = FALSE;
1127
1128                                         /* not posting eos when repeating */
1129                                         break;
1130                                 }
1131                         }
1132
1133                         if (player->pipeline)
1134                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1135
1136                         /* post eos message to application */
1137                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1138
1139                         /* reset last position */
1140                         player->last_position = 0;
1141                 }
1142                 break;
1143
1144         case GST_MESSAGE_ERROR:
1145                 {
1146                         GError *error = NULL;
1147                         gchar* debug = NULL;
1148
1149                         /* generating debug info before returning error */
1150                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1151
1152                         /* get error code */
1153                         gst_message_parse_error(msg, &error, &debug);
1154
1155                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1156                                 /* Note : the streaming error from the streaming source is handled
1157                                  *   using __mmplayer_handle_streaming_error.
1158                                  */
1159                                 __mmplayer_handle_streaming_error(player, msg);
1160
1161                                 /* dump state of all element */
1162                                 __mmplayer_dump_pipeline_state(player);
1163                         } else {
1164                                 /* traslate gst error code to msl error code. then post it
1165                                  * to application if needed
1166                                  */
1167                                 __mmplayer_handle_gst_error(player, msg, error);
1168
1169                                 if (debug)
1170                                         LOGE("error debug : %s", debug);
1171                         }
1172
1173                         if (MMPLAYER_IS_HTTP_PD(player))
1174                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1175
1176                         MMPLAYER_FREEIF(debug);
1177                         g_error_free(error);
1178                 }
1179                 break;
1180
1181         case GST_MESSAGE_WARNING:
1182                 {
1183                         char* debug = NULL;
1184                         GError* error = NULL;
1185
1186                         gst_message_parse_warning(msg, &error, &debug);
1187
1188                         LOGD("warning : %s\n", error->message);
1189                         LOGD("debug : %s\n", debug);
1190
1191                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1192
1193                         MMPLAYER_FREEIF(debug);
1194                         g_error_free(error);
1195                 }
1196                 break;
1197
1198         case GST_MESSAGE_TAG:
1199                 {
1200                         LOGD("GST_MESSAGE_TAG\n");
1201                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1202                                 LOGW("failed to extract tags from gstmessage\n");
1203                 }
1204                 break;
1205
1206         case GST_MESSAGE_BUFFERING:
1207                 {
1208                         MMMessageParamType msg_param = {0, };
1209                         int bRet = MM_ERROR_NONE;
1210
1211                         if (!(player->pipeline && player->pipeline->mainbin)) {
1212                                 LOGE("Pipeline is not initialized");
1213                                 break;
1214                         }
1215
1216                         if (!MMPLAYER_IS_STREAMING(player))
1217                                 break;
1218
1219                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1220                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1221                                         /* skip the playback control by buffering msg while user request is handled. */
1222                                         gint per = 0;
1223
1224                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1225
1226                                         gst_message_parse_buffering(msg, &per);
1227                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1228
1229                                         msg_param.connection.buffering = per;
1230                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1231                                         break;
1232                                 }
1233                         } else {
1234                                 MMPLAYER_CMD_LOCK(player);
1235                         }
1236
1237                         if (!player->streamer) {
1238                                 LOGW("Pipeline is shutting down");
1239                                 MMPLAYER_CMD_UNLOCK(player);
1240                                 break;
1241                         }
1242
1243                         /* ignore the remained buffering message till getting 100% msg */
1244                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1245                                 gint buffer_percent = 0;
1246
1247                                 gst_message_parse_buffering(msg, &buffer_percent);
1248
1249                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1250                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1251                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1252                                 }
1253                                 MMPLAYER_CMD_UNLOCK(player);
1254                                 break;
1255                         }
1256
1257                         /* ignore the remained buffering message */
1258                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1259                                 gint buffer_percent = 0;
1260
1261                                 gst_message_parse_buffering(msg, &buffer_percent);
1262
1263                                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1264                                                         player->streamer->buffering_percent, buffer_percent);
1265
1266                                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1267                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1268                                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1269
1270                                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1271                                 } else {
1272                                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1273                                         MMPLAYER_CMD_UNLOCK(player);
1274                                         break;
1275                                 }
1276                         }
1277
1278                         __mmplayer_update_buffer_setting(player, msg);
1279
1280                         bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1281
1282                         if (bRet == MM_ERROR_NONE) {
1283                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1284                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1285
1286                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1287                                         player->pending_resume &&
1288                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1289
1290                                         player->is_external_subtitle_added_now = FALSE;
1291                                         player->pending_resume = FALSE;
1292                                         _mmplayer_resume((MMHandleType)player);
1293                                 }
1294
1295                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1296                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1297
1298                                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1299                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1300                                                         player->seek_state = MMPLAYER_SEEK_NONE;
1301                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1302                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1303                                                         /* Considering the async state trasition in case of RTSP.
1304                                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1305                                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1306                                                 }
1307                                         }
1308                                 }
1309                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310                                 if (!player->streamer) {
1311                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312                                         MMPLAYER_CMD_UNLOCK(player);
1313                                         break;
1314                                 }
1315
1316                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1317
1318                                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1320
1321                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1323                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1324                                         } else {
1325                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1326                                         }
1327                                 } else {
1328                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1329                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1330                                 }
1331                         }
1332                         MMPLAYER_CMD_UNLOCK(player);
1333                 }
1334                 break;
1335
1336         case GST_MESSAGE_STATE_CHANGED:
1337                 {
1338                         MMPlayerGstElement *mainbin;
1339                         const GValue *voldstate, *vnewstate, *vpending;
1340                         GstState oldstate = GST_STATE_NULL;
1341                         GstState newstate = GST_STATE_NULL;
1342                         GstState pending = GST_STATE_NULL;
1343
1344                         if (!(player->pipeline && player->pipeline->mainbin)) {
1345                                 LOGE("player pipeline handle is null");
1346                                 break;
1347                         }
1348
1349                         mainbin = player->pipeline->mainbin;
1350
1351                         /* we only handle messages from pipeline */
1352                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1353                                 break;
1354
1355                         /* get state info from msg */
1356                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1359
1360                         if (!voldstate || !vnewstate) {
1361                                 LOGE("received msg has wrong format.");
1362                                 break;
1363                         }
1364
1365                         oldstate = (GstState)voldstate->data[0].v_int;
1366                         newstate = (GstState)vnewstate->data[0].v_int;
1367                         if (vpending)
1368                                 pending = (GstState)vpending->data[0].v_int;
1369
1370                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1371                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372                                 gst_element_state_get_name((GstState)oldstate),
1373                                 gst_element_state_get_name((GstState)newstate),
1374                                 gst_element_state_get_name((GstState)pending));
1375
1376                         if (newstate == GST_STATE_PLAYING) {
1377                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1378
1379                                         int retVal = MM_ERROR_NONE;
1380                                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1381
1382                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1383
1384                                         if (MM_ERROR_NONE != retVal)
1385                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1386
1387                                         player->pending_seek.is_pending = FALSE;
1388                                 }
1389                         }
1390
1391                         if (oldstate == newstate) {
1392                                 LOGD("pipeline reports state transition to old state");
1393                                 break;
1394                         }
1395
1396                         switch (newstate) {
1397                         case GST_STATE_VOID_PENDING:
1398                                 break;
1399
1400                         case GST_STATE_NULL:
1401                                 break;
1402
1403                         case GST_STATE_READY:
1404                                 break;
1405
1406                         case GST_STATE_PAUSED:
1407                                 {
1408                                         gboolean prepare_async = FALSE;
1409
1410                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411                                                 __mmplayer_configure_audio_callback(player);
1412
1413                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414                                                 // managed prepare async case
1415                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1417                                         }
1418
1419                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1421
1422                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1424                                                                 player->total_maximum_bitrate, player->total_bitrate);
1425
1426                                                 if (player->pending_seek.is_pending) {
1427                                                         LOGW("trying to do pending seek");
1428                                                         MMPLAYER_CMD_LOCK(player);
1429                                                         __gst_pending_seek(player);
1430                                                         MMPLAYER_CMD_UNLOCK(player);
1431                                                 }
1432                                         }
1433                                 }
1434                                 break;
1435
1436                         case GST_STATE_PLAYING:
1437                                 {
1438                                         if (MMPLAYER_IS_STREAMING(player)) {
1439                                                 // managed prepare async case when buffering is completed
1440                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1444
1445                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1446
1447                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448                                                         if (player->streamer->buffering_percent < 100) {
1449
1450                                                                 MMMessageParamType msg_param = {0, };
1451                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1452
1453                                                                 msg_param.connection.buffering = 100;
1454                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1455                                                         }
1456                                                 }
1457                                         }
1458
1459                                         if (player->gapless.stream_changed) {
1460                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461                                                 player->gapless.stream_changed = FALSE;
1462                                         }
1463
1464                                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1465                                                 player->seek_state = MMPLAYER_SEEK_NONE;
1466                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1467                                         }
1468                                 }
1469                                 break;
1470
1471                         default:
1472                                 break;
1473                         }
1474                 }
1475                 break;
1476
1477         case GST_MESSAGE_CLOCK_LOST:
1478                         {
1479                                 GstClock *clock = NULL;
1480                                 gboolean need_new_clock = FALSE;
1481
1482                                 gst_message_parse_clock_lost(msg, &clock);
1483                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1484
1485                                 if (!player->videodec_linked)
1486                                         need_new_clock = TRUE;
1487                                 else if (!player->ini.use_system_clock)
1488                                         need_new_clock = TRUE;
1489
1490                                 if (need_new_clock) {
1491                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1492                                         __gst_pause(player, FALSE);
1493                                         __gst_resume(player, FALSE);
1494                                 }
1495                         }
1496                         break;
1497
1498         case GST_MESSAGE_NEW_CLOCK:
1499                         {
1500                                 GstClock *clock = NULL;
1501                                 gst_message_parse_new_clock(msg, &clock);
1502                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1503                         }
1504                         break;
1505
1506         case GST_MESSAGE_ELEMENT:
1507                         {
1508                                 const gchar *structure_name;
1509                                 gint count = 0, idx = 0;
1510                                 MMHandleType attrs = 0;
1511
1512                                 attrs = MMPLAYER_GET_ATTRS(player);
1513                                 if (!attrs) {
1514                                         LOGE("cannot get content attribute");
1515                                         break;
1516                                 }
1517
1518                                 if (gst_message_get_structure(msg) == NULL)
1519                                         break;
1520
1521                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1522                                 if (!structure_name)
1523                                         break;
1524
1525                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1526
1527                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1528                                         const GValue *var_info = NULL;
1529
1530                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1531                                         if (var_info != NULL) {
1532                                                 if (player->adaptive_info.var_list)
1533                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1534
1535                                                 /* share addr or copy the list */
1536                                                 player->adaptive_info.var_list =
1537                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1538
1539                                                 count = g_list_length(player->adaptive_info.var_list);
1540                                                 if (count > 0) {
1541                                                         VariantData *temp = NULL;
1542
1543                                                         /* print out for debug */
1544                                                         LOGD("num of variant_info %d", count);
1545                                                         for (idx = 0; idx < count; idx++) {
1546                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1547                                                                 if (temp)
1548                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1549                                                         }
1550                                                 }
1551                                         }
1552                                 }
1553
1554                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1555                                         gint num_buffers = 0;
1556                                         gint extra_num_buffers = 0;
1557
1558                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1559                                                 player->video_num_buffers = num_buffers;
1560                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1561                                         }
1562
1563                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1564                                                 player->video_extra_num_buffers = extra_num_buffers;
1565                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1566                                         }
1567                                         break;
1568                                 }
1569
1570                                 if (!strcmp(structure_name, "Language_list")) {
1571                                         const GValue *lang_list = NULL;
1572                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1573                                         if (lang_list != NULL) {
1574                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1575                                                 if (count > 1)
1576                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1577                                         }
1578                                 }
1579
1580                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1581                                         const GValue *lang_list = NULL;
1582                                         MMPlayerLangStruct *temp = NULL;
1583
1584                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1585                                         if (lang_list != NULL) {
1586                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1587                                                 if (count) {
1588                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1589                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1590                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1591                                                         if (mmf_attrs_commit(attrs))
1592                                                                 LOGE("failed to commit.\n");
1593                                                         LOGD("Total subtitle tracks = %d \n", count);
1594
1595                                                         while (count) {
1596                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1597                                                                 if (temp)
1598                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1599                                                                                                 temp->language_key, temp->language_code);
1600                                                                 count--;
1601                                                         }
1602                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1603                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1604                                                 }
1605                                         }
1606                                 }
1607
1608                                 /* custom message */
1609                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1610                                         MMMessageParamType msg_param = {0,};
1611                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1612                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1613                                 }
1614
1615                                 /* custom message for RTSP attribute :
1616                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1617                                     sdp which has contents info is received when rtsp connection is opened.
1618                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1619                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1620
1621                                         gchar *audio_codec = NULL;
1622                                         gchar *video_codec = NULL;
1623                                         gchar *video_frame_size = NULL;
1624
1625                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1626                                         LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1627                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1628
1629                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1630                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1631                                         if (audio_codec)
1632                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1633
1634                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1635                                         LOGD("rtsp_video_codec : %s", video_codec);
1636                                         if (video_codec)
1637                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1638
1639                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1640                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1641                                         if (video_frame_size) {
1642
1643                                                 char *seperator = strchr(video_frame_size, '-');
1644                                                 if (seperator) {
1645
1646                                                         char video_width[10] = {0,};
1647                                                         int frame_size_len = strlen(video_frame_size);
1648                                                         int separtor_len = strlen(seperator);
1649
1650                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1651                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1652
1653                                                         seperator++;
1654                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1655                                                 }
1656                                         }
1657
1658                                         if (mmf_attrs_commit(attrs))
1659                                                 LOGE("failed to commit.\n");
1660                                 }
1661                         }
1662                         break;
1663
1664         case GST_MESSAGE_DURATION_CHANGED:
1665                 {
1666                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1667                         if (!__mmplayer_gst_handle_duration(player, msg))
1668                                 LOGW("failed to update duration");
1669                 }
1670
1671                 break;
1672
1673         case GST_MESSAGE_ASYNC_START:
1674                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1675                 break;
1676
1677         case GST_MESSAGE_ASYNC_DONE:
1678                 {
1679                         MMPlayerGstElement *mainbin;
1680
1681                         if (!(player->pipeline && player->pipeline->mainbin)) {
1682                                 LOGE("player pipeline handle is null");
1683                                 break;
1684                         }
1685
1686                         mainbin = player->pipeline->mainbin;
1687
1688                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1689
1690                         /* we only handle messages from pipeline */
1691                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1692                                 break;
1693
1694                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1695                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1696                                         player->seek_state = MMPLAYER_SEEK_NONE;
1697                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1698                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1699                                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1700                                                 LOGD("sync %s state(%s) with parent state(%s)",
1701                                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1702                                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1703                                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1704
1705                                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1706                                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1707                                                    Because the buffering state is controlled according to the state transition for force resume,
1708                                                    the decodebin state should be paused as player state. */
1709                                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1710                                         }
1711
1712                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1713                                                 (player->streamer) &&
1714                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1715                                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1716                                                 GstQuery *query = NULL;
1717                                                 gboolean busy = FALSE;
1718                                                 gint percent = 0;
1719
1720                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1721                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1722                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1723                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1724                                                         gst_query_unref(query);
1725
1726                                                         LOGD("buffered percent(%s): %d\n",
1727                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1728                                                 }
1729
1730                                                 if (percent >= 100)
1731                                                         __mmplayer_handle_buffering_message(player);
1732                                         }
1733
1734                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1735                                 }
1736                         }
1737                 }
1738                 break;
1739
1740         #if 0 /* delete unnecessary logs */
1741         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1742         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1743         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1744         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1745         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1746         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1747         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1748         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1749         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1750         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1751         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1752         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1753         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1754         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1755         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1756         #endif
1757
1758         default:
1759                 break;
1760         }
1761
1762         /* should not call 'gst_message_unref(msg)' */
1763         return;
1764 }
1765
1766 static gboolean
1767 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1768 {
1769         gint64 bytes = 0;
1770
1771         MMPLAYER_FENTER();
1772
1773         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1774         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1775
1776         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1777                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1778                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1779
1780                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1781                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1782                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1783                 }
1784         } else {
1785                 /* handling audio clip which has vbr. means duration is keep changing */
1786                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1787         }
1788
1789         MMPLAYER_FLEAVE();
1790
1791         return TRUE;
1792 }
1793
1794 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1795                 mm_player_spherical_metadata_t *metadata) {
1796         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1797         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1798         gst_tag_list_get_string(tags, "stitching_software",
1799                         &metadata->stitching_software);
1800         gst_tag_list_get_string(tags, "projection_type",
1801                         &metadata->projection_type_string);
1802         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1803         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1804         gst_tag_list_get_int(tags, "init_view_heading",
1805                         &metadata->init_view_heading);
1806         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1807         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1808         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1809         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1810                         &metadata->full_pano_width_pixels);
1811         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1812                         &metadata->full_pano_height_pixels);
1813         gst_tag_list_get_int(tags, "cropped_area_image_width",
1814                         &metadata->cropped_area_image_width);
1815         gst_tag_list_get_int(tags, "cropped_area_image_height",
1816                         &metadata->cropped_area_image_height);
1817         gst_tag_list_get_int(tags, "cropped_area_left",
1818                         &metadata->cropped_area_left);
1819         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1820         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1821         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1822         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1823 }
1824
1825 static gboolean
1826 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1827 {
1828
1829 /* macro for better code readability */
1830 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1832         if (string != NULL) { \
1833                 SECURE_LOGD("update tag string : %s\n", string); \
1834                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1835                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1836                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1837                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1838                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1839                         g_free(new_string); \
1840                         new_string = NULL; \
1841                 } else { \
1842                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1843                 } \
1844                 g_free(string); \
1845                 string = NULL; \
1846         } \
1847 }
1848
1849 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1850 do {    \
1851         GstSample *sample = NULL;\
1852         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1853                 GstMapInfo info = GST_MAP_INFO_INIT;\
1854                 buffer = gst_sample_get_buffer(sample);\
1855                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1856                         LOGD("failed to get image data from tag");\
1857                         gst_sample_unref(sample);\
1858                         return FALSE;\
1859                 } \
1860                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1861                 MMPLAYER_FREEIF(player->album_art);\
1862                 player->album_art = (gchar *)g_malloc(info.size);\
1863                 if (player->album_art) {\
1864                         memcpy(player->album_art, info.data, info.size);\
1865                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1866                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1867                                 msg_param.data = (void *)player->album_art;\
1868                                 msg_param.size = info.size;\
1869                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1870                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1871                         } \
1872                 } \
1873                 gst_buffer_unmap(buffer, &info);\
1874                 gst_sample_unref(sample);\
1875         }       \
1876 } while (0)
1877
1878 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1879 do {    \
1880         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1881                 if (v_uint) { \
1882                         int i = 0; \
1883                         gchar *tag_list_str = NULL; \
1884                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1885                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1886                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1887                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1888                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1889                         else \
1890                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1891                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1892                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1893                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1894                                 player->bitrate[track_type] = v_uint; \
1895                                 player->total_bitrate = 0; \
1896                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1897                                         player->total_bitrate += player->bitrate[i]; \
1898                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1899                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1900                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1901                                 player->maximum_bitrate[track_type] = v_uint; \
1902                                 player->total_maximum_bitrate = 0; \
1903                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1904                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1905                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1906                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1907                         } else { \
1908                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1909                         } \
1910                         v_uint = 0;\
1911                         g_free(tag_list_str); \
1912                 } \
1913         } \
1914 } while (0)
1915
1916 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1917 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1918         if (date != NULL) {\
1919                 string = g_strdup_printf("%d", g_date_get_year(date));\
1920                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1921                 SECURE_LOGD("metainfo year : %s\n", string);\
1922                 MMPLAYER_FREEIF(string);\
1923                 g_date_free(date);\
1924         } \
1925 }
1926
1927 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1928 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1929         if (datetime != NULL) {\
1930                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1931                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1932                 SECURE_LOGD("metainfo year : %s\n", string);\
1933                 MMPLAYER_FREEIF(string);\
1934                 gst_date_time_unref(datetime);\
1935         } \
1936 }
1937
1938 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1939 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1940         if (v_uint64) {\
1941                 /* FIXIT : don't know how to store date */\
1942                 g_assert(1);\
1943                 v_uint64 = 0;\
1944         } \
1945 }
1946
1947 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1948 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1949         if (v_double) {\
1950                 /* FIXIT : don't know how to store date */\
1951                 g_assert(1);\
1952                 v_double = 0;\
1953         } \
1954 }
1955
1956         /* function start */
1957         GstTagList* tag_list = NULL;
1958
1959         MMHandleType attrs = 0;
1960
1961         char *string = NULL;
1962         guint v_uint = 0;
1963         GDate *date = NULL;
1964         GstDateTime *datetime = NULL;
1965         /* album cover */
1966         GstBuffer *buffer = NULL;
1967         gint index = 0;
1968         MMMessageParamType msg_param = {0, };
1969
1970         /* currently not used. but those are needed for above macro */
1971         //guint64 v_uint64 = 0;
1972         //gdouble v_double = 0;
1973
1974         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1975
1976         attrs = MMPLAYER_GET_ATTRS(player);
1977
1978         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1979
1980         /* get tag list from gst message */
1981         gst_message_parse_tag(msg, &tag_list);
1982
1983         /* store tags to player attributes */
1984         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1985         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1986         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1987         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1988         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1989         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1990         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1991         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1992         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1993         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1994         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1995         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1996         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1997         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1998         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1999         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2000         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2001         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2002         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2003         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2004         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2005         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2006         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2007         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2008         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2009         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2010         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2011         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2012         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2013         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2014         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2015         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2016         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2017         MMPLAYER_UPDATE_TAG_LOCK(player);
2018         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2019         MMPLAYER_UPDATE_TAG_UNLOCK(player);
2020         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2021         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2022         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2023         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2024         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2025         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2026         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2027         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2028         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2029         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2030         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2031         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2032         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2033
2034         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2035                 if (player->video360_metadata.is_spherical == -1) {
2036                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2037                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2038                                         player->video360_metadata.is_spherical);
2039                         if (player->video360_metadata.is_spherical == 1) {
2040                                 LOGD("This is spherical content for 360 playback.");
2041                                 player->is_content_spherical = TRUE;
2042                         } else {
2043                                 LOGD("This is not spherical content");
2044                                 player->is_content_spherical = FALSE;
2045                         }
2046
2047                         if (player->video360_metadata.projection_type_string) {
2048                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2049                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2050                                 } else {
2051                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2052                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2053                                 }
2054                         }
2055
2056                         if (player->video360_metadata.stereo_mode_string) {
2057                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2058                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2059                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2060                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2061                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2062                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2063                                 } else {
2064                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2065                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2066                                 }
2067                         }
2068                 }
2069         }
2070
2071         if (mmf_attrs_commit(attrs))
2072                 LOGE("failed to commit.\n");
2073
2074         gst_tag_list_free(tag_list);
2075
2076         return TRUE;
2077 }
2078
2079 static void
2080 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2081 {
2082         mm_player_t* player = (mm_player_t*) data;
2083
2084         MMPLAYER_FENTER();
2085
2086         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2087           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2088           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2089           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2090
2091           * [1] audio and video will be dumped with filesink.
2092           * [2] autoplugging is done by just using pad caps.
2093           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2094           * and the video will be dumped via filesink.
2095           */
2096         if (player->num_dynamic_pad == 0) {
2097                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2098
2099                 if (!__mmplayer_gst_remove_fakesink(player,
2100                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2101                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2102                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2103                          * source element are not same. To overcome this situation, this function will called
2104                          * several places and several times. Therefore, this is not an error case.
2105                          */
2106                         return;
2107         }
2108
2109         /* create dot before error-return. for debugging */
2110         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2111
2112         player->no_more_pad = TRUE;
2113
2114         MMPLAYER_FLEAVE();
2115 }
2116
2117 static gboolean
2118 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2119 {
2120         GstElement* parent = NULL;
2121
2122         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2123
2124         /* if we have no fakesink. this meas we are using decodebin which doesn'
2125         t need to add extra fakesink */
2126         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2127
2128         /* lock */
2129         MMPLAYER_FSINK_LOCK(player);
2130
2131         if (!fakesink->gst)
2132                 goto ERROR;
2133
2134         /* get parent of fakesink */
2135         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2136         if (!parent) {
2137                 LOGD("fakesink already removed\n");
2138                 goto ERROR;
2139         }
2140
2141         gst_element_set_locked_state(fakesink->gst, TRUE);
2142
2143         /* setting the state to NULL never returns async
2144          * so no need to wait for completion of state transiton
2145          */
2146         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2147                 LOGE("fakesink state change failure!\n");
2148                 /* FIXIT : should I return here? or try to proceed to next? */
2149                 /* return FALSE; */
2150
2151         /* remove fakesink from it's parent */
2152         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2153                 LOGE("failed to remove fakesink\n");
2154
2155                 gst_object_unref(parent);
2156
2157                 goto ERROR;
2158         }
2159
2160         gst_object_unref(parent);
2161
2162         LOGD("state-holder removed\n");
2163
2164         gst_element_set_locked_state(fakesink->gst, FALSE);
2165
2166         MMPLAYER_FSINK_UNLOCK(player);
2167         return TRUE;
2168
2169 ERROR:
2170         if (fakesink->gst)
2171                 gst_element_set_locked_state(fakesink->gst, FALSE);
2172
2173         MMPLAYER_FSINK_UNLOCK(player);
2174         return FALSE;
2175 }
2176
2177
2178 static void
2179 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2180 {
2181         GstPad *sinkpad = NULL;
2182         GstCaps* caps = NULL;
2183         GstElement* new_element = NULL;
2184         GstStructure* str = NULL;
2185         const gchar* name = NULL;
2186
2187         mm_player_t* player = (mm_player_t*) data;
2188
2189         MMPLAYER_FENTER();
2190
2191         MMPLAYER_RETURN_IF_FAIL(element && pad);
2192         MMPLAYER_RETURN_IF_FAIL(player &&
2193                                         player->pipeline &&
2194                                         player->pipeline->mainbin);
2195
2196
2197         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2198          * num_dynamic_pad will decreased after creating a sinkbin.
2199          */
2200         player->num_dynamic_pad++;
2201         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2202
2203         caps = gst_pad_query_caps(pad, NULL);
2204
2205         MMPLAYER_CHECK_NULL(caps);
2206
2207         /* clear  previous result*/
2208         player->have_dynamic_pad = FALSE;
2209
2210         str = gst_caps_get_structure(caps, 0);
2211
2212         if (!str) {
2213                 LOGE("cannot get structure from caps.\n");
2214                 goto ERROR;
2215         }
2216
2217         name = gst_structure_get_name(str);
2218         if (!name) {
2219                 LOGE("cannot get mimetype from structure.\n");
2220                 goto ERROR;
2221         }
2222
2223         if (strstr(name, "video")) {
2224                 gint stype = 0;
2225                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2226
2227                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2228                         if (player->v_stream_caps) {
2229                                 gst_caps_unref(player->v_stream_caps);
2230                                 player->v_stream_caps = NULL;
2231                         }
2232
2233                         new_element = gst_element_factory_make("fakesink", NULL);
2234                         player->num_dynamic_pad--;
2235                         goto NEW_ELEMENT;
2236                 }
2237         }
2238
2239         /* clear  previous result*/
2240         player->have_dynamic_pad = FALSE;
2241
2242         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2243                 LOGE("failed to autoplug for caps");
2244                 goto ERROR;
2245         }
2246
2247         /* check if there's dynamic pad*/
2248         if (player->have_dynamic_pad) {
2249                 LOGE("using pad caps assums there's no dynamic pad !\n");
2250                 goto ERROR;
2251         }
2252
2253         gst_caps_unref(caps);
2254         caps = NULL;
2255
2256 NEW_ELEMENT:
2257
2258         /* excute new_element if created*/
2259         if (new_element) {
2260                 LOGD("adding new element to pipeline\n");
2261
2262                 /* set state to READY before add to bin */
2263                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2264
2265                 /* add new element to the pipeline */
2266                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2267                         LOGE("failed to add autoplug element to bin\n");
2268                         goto ERROR;
2269                 }
2270
2271                 /* get pad from element */
2272                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2273                 if (!sinkpad) {
2274                         LOGE("failed to get sinkpad from autoplug element\n");
2275                         goto ERROR;
2276                 }
2277
2278                 /* link it */
2279                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2280                         LOGE("failed to link autoplug element\n");
2281                         goto ERROR;
2282                 }
2283
2284                 gst_object_unref(sinkpad);
2285                 sinkpad = NULL;
2286
2287                 /* run. setting PLAYING here since streamming source is live source */
2288                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2289         }
2290
2291         if (caps)
2292                 gst_caps_unref(caps);
2293
2294         MMPLAYER_FLEAVE();
2295
2296         return;
2297
2298 STATE_CHANGE_FAILED:
2299 ERROR:
2300         /* FIXIT : take care if new_element has already added to pipeline */
2301         if (new_element)
2302                 gst_object_unref(GST_OBJECT(new_element));
2303
2304         if (sinkpad)
2305                 gst_object_unref(GST_OBJECT(sinkpad));
2306
2307         if (caps)
2308                 gst_caps_unref(caps);
2309
2310         /* FIXIT : how to inform this error to MSL ????? */
2311         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2312          * then post an error to application
2313          */
2314 }
2315
2316 static GstPadProbeReturn
2317 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2318 {
2319         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2320         return GST_PAD_PROBE_OK;
2321 }
2322
2323 static GstPadProbeReturn
2324 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2325 {
2326         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2327         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2328         mm_player_t* player = (mm_player_t*)data;
2329         GstCaps* caps = NULL;
2330         GstStructure* str = NULL;
2331         const gchar* name = NULL;
2332         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2333
2334
2335         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2336                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2337                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2338                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2339                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2340                         return ret;
2341         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2342                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2343                         return ret;
2344         }
2345
2346         caps = gst_pad_query_caps(pad, NULL);
2347         if (!caps) {
2348                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2349                 return ret;
2350         }
2351
2352         str = gst_caps_get_structure(caps, 0);
2353         if (!str) {
2354                 LOGE("failed to get structure from caps");
2355                 goto ERROR;
2356         }
2357
2358         name = gst_structure_get_name(str);
2359         if (!name) {
2360                 LOGE("failed to get name from str");
2361                 goto ERROR;
2362         }
2363
2364         if (strstr(name, "audio")) {
2365                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2366         } else if (strstr(name, "video")) {
2367                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2368         } else {
2369                 /* text track is not supportable */
2370                 LOGE("invalid name %s", name);
2371                 goto ERROR;
2372         }
2373
2374         switch (GST_EVENT_TYPE(event)) {
2375         case GST_EVENT_EOS:
2376                 {
2377                         /* in case of gapless, drop eos event not to send it to sink */
2378                         if (player->gapless.reconfigure && !player->msg_posted) {
2379                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2380                                 ret = GST_PAD_PROBE_DROP;
2381                         }
2382                         break;
2383                 }
2384         case GST_EVENT_STREAM_START:
2385                 {
2386                         gint64 stop_running_time = 0;
2387                         gint64 position_running_time = 0;
2388                         gint64 position = 0;
2389                         gint idx = 0;
2390
2391                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2392                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2393                                         !(player->selector[idx].event_probe_id)) {
2394                                         /* LOGW("[%d] skip", idx); */
2395                                         continue;
2396                                 }
2397
2398                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2399                                         stop_running_time =
2400                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2401                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2402                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2403                                         stop_running_time =
2404                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2405                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2406                                 } else {
2407                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2408                                         stop_running_time =
2409                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2410                                                                 GST_FORMAT_TIME, player->duration);
2411                                 }
2412
2413                                 position_running_time =
2414                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2415                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2416
2417                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2418                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2419                                         idx,
2420                                         GST_TIME_ARGS(stop_running_time),
2421                                         GST_TIME_ARGS(position_running_time),
2422                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2423                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2424
2425                                 position_running_time = MAX(position_running_time, stop_running_time);
2426                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2427                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2428                                 position_running_time = MAX(0, position_running_time);
2429                                 position = MAX(position, position_running_time);
2430                         }
2431
2432                         if (position != 0) {
2433                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2434                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2435                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2436
2437                                 player->gapless.start_time[stream_type] += position;
2438                         }
2439                         break;
2440                 }
2441         case GST_EVENT_FLUSH_STOP:
2442                 {
2443                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2444                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2445                         player->gapless.start_time[stream_type] = 0;
2446                         break;
2447                 }
2448         case GST_EVENT_SEGMENT:
2449                 {
2450                         GstSegment segment;
2451                         GstEvent *tmpev;
2452
2453                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2454                         gst_event_copy_segment(event, &segment);
2455
2456                         if (segment.format == GST_FORMAT_TIME) {
2457                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2458                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2459                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2460                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2461                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2462                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2463
2464                                 /* keep the all the segment ev to cover the seeking */
2465                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2466                                 player->gapless.update_segment[stream_type] = TRUE;
2467
2468                                 if (!player->gapless.running)
2469                                         break;
2470
2471                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2472
2473                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2474
2475                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2476                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2477                                 gst_event_unref(event);
2478                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2479                         }
2480                         break;
2481                 }
2482         case GST_EVENT_QOS:
2483                 {
2484                         gdouble proportion = 0.0;
2485                         GstClockTimeDiff diff = 0;
2486                         GstClockTime timestamp = 0;
2487                         gint64 running_time_diff = -1;
2488                         GstQOSType type = 0;
2489                         GstEvent *tmpev = NULL;
2490
2491                         running_time_diff = player->gapless.segment[stream_type].base;
2492
2493                         if (running_time_diff <= 0) /* don't need to adjust */
2494                                 break;
2495
2496                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2497                         gst_event_unref(event);
2498
2499                         if (timestamp < running_time_diff) {
2500                                 LOGW("QOS event from previous group");
2501                                 ret = GST_PAD_PROBE_DROP;
2502                                 break;
2503                         }
2504
2505                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2506                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2507                                                 stream_type, GST_TIME_ARGS(timestamp),
2508                                                 GST_TIME_ARGS(running_time_diff),
2509                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2510
2511                         timestamp -= running_time_diff;
2512
2513                         /* That case is invalid for QoS events */
2514                         if (diff < 0 && -diff > timestamp) {
2515                                 LOGW("QOS event from previous group");
2516                                 ret = GST_PAD_PROBE_DROP;
2517                                 break;
2518                         }
2519
2520                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2521                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2522
2523                         break;
2524                 }
2525         default:
2526                 break;
2527         }
2528
2529 ERROR:
2530         if (caps)
2531                 gst_caps_unref(caps);
2532         return ret;
2533 }
2534
2535 static void
2536 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2537 {
2538         mm_player_t* player = NULL;
2539         GstElement* pipeline = NULL;
2540         GstElement* selector = NULL;
2541         GstElement* fakesink = NULL;
2542         GstCaps* caps = NULL;
2543         GstStructure* str = NULL;
2544         const gchar* name = NULL;
2545         GstPad* sinkpad = NULL;
2546         GstPad* srcpad = NULL;
2547         gboolean first_track = FALSE;
2548
2549         enum MainElementID elemId = MMPLAYER_M_NUM;
2550         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2551
2552         /* check handles */
2553         player = (mm_player_t*)data;
2554
2555         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2556         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2557
2558         //LOGD("pad-added signal handling\n");
2559
2560         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2561
2562         /* get mimetype from caps */
2563         caps = gst_pad_query_caps(pad, NULL);
2564         if (!caps) {
2565                 LOGE("cannot get caps from pad.\n");
2566                 goto ERROR;
2567         }
2568
2569         str = gst_caps_get_structure(caps, 0);
2570         if (!str) {
2571                 LOGE("cannot get structure from caps.\n");
2572                 goto ERROR;
2573         }
2574
2575         name = gst_structure_get_name(str);
2576         if (!name) {
2577                 LOGE("cannot get mimetype from structure.\n");
2578                 goto ERROR;
2579         }
2580
2581         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2582         //LOGD("detected mimetype : %s\n", name);
2583
2584         if (strstr(name, "video")) {
2585                 gint stype = 0;
2586
2587                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2588                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2589
2590                 /* don't make video because of not required, and not support multiple track */
2591                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2592                         LOGD("no video sink by null surface");
2593
2594                         gchar *caps_str = gst_caps_to_string(caps);
2595                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2596                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2597                                 player->set_mode.video_zc = TRUE;
2598
2599                         MMPLAYER_FREEIF(caps_str);
2600
2601                         if (player->v_stream_caps) {
2602                                 gst_caps_unref(player->v_stream_caps);
2603                                 player->v_stream_caps = NULL;
2604                         }
2605
2606                         LOGD("create fakesink instead of videobin");
2607
2608                         /* fake sink */
2609                         fakesink = gst_element_factory_make("fakesink", NULL);
2610                         if (fakesink == NULL) {
2611                                 LOGE("ERROR : fakesink create error\n");
2612                                 goto ERROR;
2613                         }
2614
2615                         if (player->ini.set_dump_element_flag)
2616                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2617
2618                         player->video_fakesink = fakesink;
2619
2620                         /* store it as it's sink element */
2621                         __mmplayer_add_sink(player, player->video_fakesink);
2622
2623                         gst_bin_add(GST_BIN(pipeline), fakesink);
2624
2625                         // link
2626                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2627
2628                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2629                                 LOGW("failed to link fakesink\n");
2630                                 gst_object_unref(GST_OBJECT(fakesink));
2631                                 goto ERROR;
2632                         }
2633
2634                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2635                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2636                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2637                         }
2638
2639                         if (player->set_mode.media_packet_video_stream) {
2640                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2641
2642                                 MMPLAYER_SIGNAL_CONNECT(player,
2643                                                                                 G_OBJECT(fakesink),
2644                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2645                                                                                 "handoff",
2646                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2647                                                                                 (gpointer)player);
2648
2649                                 MMPLAYER_SIGNAL_CONNECT(player,
2650                                                                                 G_OBJECT(fakesink),
2651                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2652                                                                                 "preroll-handoff",
2653                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2654                                                                                 (gpointer)player);
2655                         }
2656
2657                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2658                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2659                         goto DONE;
2660                 }
2661
2662                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2663                         __mmplayer_gst_decode_callback(elem, pad, player);
2664                         goto DONE;
2665                 }
2666
2667                 LOGD("video selector \n");
2668                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2669                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2670         } else {
2671                 if (strstr(name, "audio")) {
2672                         gint samplerate = 0;
2673                         gint channels = 0;
2674
2675                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2676                                 __mmplayer_gst_decode_callback(elem, pad, player);
2677                                 goto DONE;
2678                         }
2679
2680                         LOGD("audio selector \n");
2681                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2682                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2683
2684                         gst_structure_get_int(str, "rate", &samplerate);
2685                         gst_structure_get_int(str, "channels", &channels);
2686
2687                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2688                                 /* fake sink */
2689                                 fakesink = gst_element_factory_make("fakesink", NULL);
2690                                 if (fakesink == NULL) {
2691                                         LOGE("ERROR : fakesink create error\n");
2692                                         goto ERROR;
2693                                 }
2694
2695                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2696
2697                                 /* link */
2698                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2699
2700                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2701                                         LOGW("failed to link fakesink\n");
2702                                         gst_object_unref(GST_OBJECT(fakesink));
2703                                         goto ERROR;
2704                                 }
2705
2706                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2707                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2708
2709                                 goto DONE;
2710                         }
2711                 } else if (strstr(name, "text")) {
2712                         LOGD("text selector \n");
2713                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2714                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2715                 } else {
2716                         LOGE("wrong elem id \n");
2717                         goto ERROR;
2718                 }
2719         }
2720
2721         selector = player->pipeline->mainbin[elemId].gst;
2722         if (selector == NULL) {
2723                 selector = gst_element_factory_make("input-selector", NULL);
2724                 LOGD("Creating input-selector\n");
2725                 if (selector == NULL) {
2726                         LOGE("ERROR : input-selector create error\n");
2727                         goto ERROR;
2728                 }
2729                 g_object_set(selector, "sync-streams", TRUE, NULL);
2730
2731                 player->pipeline->mainbin[elemId].id = elemId;
2732                 player->pipeline->mainbin[elemId].gst = selector;
2733
2734                 first_track = TRUE;
2735                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2736
2737                 srcpad = gst_element_get_static_pad(selector, "src");
2738
2739                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2740                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2741                         __mmplayer_gst_selector_blocked, NULL, NULL);
2742                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2743                         __mmplayer_gst_selector_event_probe, player, NULL);
2744
2745                 gst_element_set_state(selector, GST_STATE_PAUSED);
2746                 gst_bin_add(GST_BIN(pipeline), selector);
2747         } else
2748                 LOGD("input-selector is already created.\n");
2749
2750         // link
2751         LOGD("Calling request pad with selector %p \n", selector);
2752         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2753
2754         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2755
2756         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2757                 LOGW("failed to link selector\n");
2758                 gst_object_unref(GST_OBJECT(selector));
2759                 goto ERROR;
2760         }
2761
2762         if (first_track) {
2763                 LOGD("this is first track --> active track \n");
2764                 g_object_set(selector, "active-pad", sinkpad, NULL);
2765         }
2766
2767         _mmplayer_track_update_info(player, stream_type, sinkpad);
2768
2769
2770 DONE:
2771 ERROR:
2772
2773         if (caps)
2774                 gst_caps_unref(caps);
2775
2776         if (sinkpad) {
2777                 gst_object_unref(GST_OBJECT(sinkpad));
2778                 sinkpad = NULL;
2779         }
2780
2781         if (srcpad) {
2782                 gst_object_unref(GST_OBJECT(srcpad));
2783                 srcpad = NULL;
2784         }
2785
2786         return;
2787 }
2788
2789 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2790 {
2791         GstPad* srcpad = NULL;
2792         MMHandleType attrs = 0;
2793         gint active_index = 0;
2794
2795         // [link] input-selector :: textbin
2796         srcpad = gst_element_get_static_pad(text_selector, "src");
2797         if (!srcpad) {
2798                 LOGE("failed to get srcpad from selector\n");
2799                 return;
2800         }
2801
2802         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2803
2804         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2805         if ((active_index != DEFAULT_TRACK) &&
2806                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2807                 LOGW("failed to change text track\n");
2808                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2809         }
2810
2811         player->no_more_pad = TRUE;
2812         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2813
2814         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2815         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2816                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2817                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2818         }
2819
2820         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2821
2822         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2823                 player->has_closed_caption = TRUE;
2824
2825         attrs = MMPLAYER_GET_ATTRS(player);
2826         if (attrs) {
2827                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2828                 if (mmf_attrs_commit(attrs))
2829                         LOGE("failed to commit.\n");
2830         } else
2831                 LOGE("cannot get content attribute");
2832
2833         if (srcpad) {
2834                 gst_object_unref(GST_OBJECT(srcpad));
2835                 srcpad = NULL;
2836         }
2837 }
2838
2839 static void
2840 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2841 {
2842         mm_player_t* player = (mm_player_t*)data;
2843         GstElement* selector = NULL;
2844         GstElement* queue = NULL;
2845
2846         GstPad* srcpad = NULL;
2847         GstPad* sinkpad = NULL;
2848         GstCaps* caps = NULL;
2849         gchar* caps_str = NULL;
2850
2851         MMPLAYER_FENTER();
2852         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2853
2854         caps = gst_pad_get_current_caps(pad);
2855         caps_str = gst_caps_to_string(caps);
2856         LOGD("deinterleave new caps : %s\n", caps_str);
2857         MMPLAYER_FREEIF(caps_str);
2858         gst_caps_unref(caps);
2859
2860         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2861                 LOGE("ERROR : queue create error\n");
2862                 goto ERROR;
2863         }
2864
2865         g_object_set(G_OBJECT(queue),
2866                                 "max-size-buffers", 10,
2867                                 "max-size-bytes", 0,
2868                                 "max-size-time", (guint64)0,
2869                                 NULL);
2870
2871         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2872
2873         if (!selector) {
2874                 LOGE("there is no audio channel selector.\n");
2875                 goto ERROR;
2876         }
2877
2878         srcpad = gst_element_get_static_pad(queue, "src");
2879         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2880
2881         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2882
2883         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2884                 LOGW("failed to link deinterleave - selector\n");
2885                 goto ERROR;
2886         }
2887
2888         gst_element_set_state(queue, GST_STATE_PAUSED);
2889         player->audio_mode.total_track_num++;
2890
2891 ERROR:
2892
2893         if (srcpad) {
2894                 gst_object_unref(GST_OBJECT(srcpad));
2895                 srcpad = NULL;
2896         }
2897
2898         if (sinkpad) {
2899                 gst_object_unref(GST_OBJECT(sinkpad));
2900                 sinkpad = NULL;
2901         }
2902
2903         MMPLAYER_FLEAVE();
2904         return;
2905 }
2906
2907 static void
2908 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2909 {
2910         mm_player_t* player = NULL;
2911         GstElement* selector = NULL;
2912         GstPad* sinkpad = NULL;
2913         gint active_index = 0;
2914         gchar* change_pad_name = NULL;
2915         GstCaps* caps = NULL;   // no need to unref
2916         gint default_audio_ch = 0;
2917
2918         MMPLAYER_FENTER();
2919         player = (mm_player_t*) data;
2920
2921         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2922
2923         if (!selector) {
2924                 LOGE("there is no audio channel selector.\n");
2925                 goto ERROR;
2926         }
2927
2928         active_index = player->audio_mode.active_pad_index;
2929
2930         if (active_index != default_audio_ch) {
2931                 gint audio_ch = default_audio_ch;
2932
2933                 /*To get the new pad from the selector*/
2934                 change_pad_name = g_strdup_printf("sink%d", active_index);
2935                 if (change_pad_name != NULL) {
2936                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2937                         if (sinkpad != NULL) {
2938                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2939                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2940
2941                                 audio_ch = active_index;
2942
2943                                 caps = gst_pad_get_current_caps(sinkpad);
2944                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2945
2946                                 __mmplayer_set_audio_attrs(player, caps);
2947                                 gst_caps_unref(caps);
2948                         }
2949                         MMPLAYER_FREEIF(change_pad_name);
2950                 }
2951
2952                 player->audio_mode.active_pad_index = audio_ch;
2953                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2954         }
2955
2956 ERROR:
2957
2958         if (sinkpad)
2959                 gst_object_unref(sinkpad);
2960
2961         MMPLAYER_FLEAVE();
2962         return;
2963 }
2964
2965 static void
2966 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2967 {
2968         mm_player_t* player = NULL;
2969         MMPlayerGstElement *mainbin = NULL;
2970
2971         GstElement* tee = NULL;
2972         GstElement* stereo_queue = NULL;
2973         GstElement* mono_queue = NULL;
2974         GstElement* conv = NULL;
2975         GstElement* filter = NULL;
2976         GstElement* deinterleave = NULL;
2977         GstElement* selector = NULL;
2978
2979         GstPad* srcpad = NULL;
2980         GstPad* selector_srcpad = NULL;
2981         GstPad* sinkpad = NULL;
2982         GstCaps* caps = NULL;
2983         gulong block_id = 0;
2984
2985         MMPLAYER_FENTER();
2986
2987         /* check handles */
2988         player = (mm_player_t*) data;
2989
2990         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2991         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2992
2993         mainbin = player->pipeline->mainbin;
2994
2995         /* tee */
2996         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2997                 LOGE("ERROR : tee create error\n");
2998                 goto ERROR;
2999         }
3000
3001         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3002         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3003
3004         gst_element_set_state(tee, GST_STATE_PAUSED);
3005
3006         /* queue */
3007         srcpad = gst_element_get_request_pad(tee, "src_%u");
3008         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3009                 LOGE("ERROR : stereo queue create error\n");
3010                 goto ERROR;
3011         }
3012
3013         g_object_set(G_OBJECT(stereo_queue),
3014                                 "max-size-buffers", 10,
3015                                 "max-size-bytes", 0,
3016                                 "max-size-time", (guint64)0,
3017                                 NULL);
3018
3019         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3020         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3021
3022         if (srcpad) {
3023                 gst_object_unref(GST_OBJECT(srcpad));
3024                 srcpad = NULL;
3025         }
3026
3027         srcpad = gst_element_get_request_pad(tee, "src_%u");
3028
3029         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3030                 LOGE("ERROR : mono queue create error\n");
3031                 goto ERROR;
3032         }
3033
3034         g_object_set(G_OBJECT(mono_queue),
3035                                 "max-size-buffers", 10,
3036                                 "max-size-bytes", 0,
3037                                 "max-size-time", (guint64)0,
3038                                 NULL);
3039
3040         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3041         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3042
3043         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3044         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3045
3046         /* audioconvert */
3047         srcpad = gst_element_get_static_pad(mono_queue, "src");
3048         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3049                 LOGE("ERROR : audioconvert create error\n");
3050                 goto ERROR;
3051         }
3052
3053         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3054         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3055
3056         /* caps filter */
3057         if (srcpad) {
3058                 gst_object_unref(GST_OBJECT(srcpad));
3059                 srcpad = NULL;
3060         }
3061         srcpad = gst_element_get_static_pad(conv, "src");
3062
3063         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3064                 LOGE("ERROR : capsfilter create error\n");
3065                 goto ERROR;
3066         }
3067
3068         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3069         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3070
3071         caps = gst_caps_from_string("audio/x-raw-int, "
3072                                 "width = (int) 16, "
3073                                 "depth = (int) 16, "
3074                                 "channels = (int) 2");
3075
3076         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3077         gst_caps_unref(caps);
3078
3079         gst_element_set_state(conv, GST_STATE_PAUSED);
3080         gst_element_set_state(filter, GST_STATE_PAUSED);
3081
3082         /* deinterleave */
3083         if (srcpad) {
3084                 gst_object_unref(GST_OBJECT(srcpad));
3085                 srcpad = NULL;
3086         }
3087         srcpad = gst_element_get_static_pad(filter, "src");
3088
3089         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3090                 LOGE("ERROR : deinterleave create error\n");
3091                 goto ERROR;
3092         }
3093
3094         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3095
3096         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3097                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3098
3099         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3100                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3101
3102         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3103         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3104
3105         /* selector */
3106         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3107         if (selector == NULL) {
3108                 LOGE("ERROR : audio-selector create error\n");
3109                 goto ERROR;
3110         }
3111
3112         g_object_set(selector, "sync-streams", TRUE, NULL);
3113         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3114
3115         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3116         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3117
3118         selector_srcpad = gst_element_get_static_pad(selector, "src");
3119
3120         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3121         block_id =
3122                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3123                         __mmplayer_gst_selector_blocked, NULL, NULL);
3124
3125         if (srcpad) {
3126                 gst_object_unref(GST_OBJECT(srcpad));
3127                 srcpad = NULL;
3128         }
3129
3130         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3131         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3132
3133         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3134                 LOGW("failed to link queue_stereo - selector\n");
3135                 goto ERROR;
3136         }
3137
3138         player->audio_mode.total_track_num++;
3139
3140         g_object_set(selector, "active-pad", sinkpad, NULL);
3141         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3142         gst_element_set_state(selector, GST_STATE_PAUSED);
3143
3144         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3145
3146 ERROR:
3147
3148         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3149         if (block_id != 0) {
3150                 gst_pad_remove_probe(selector_srcpad, block_id);
3151                 block_id = 0;
3152         }
3153
3154         if (sinkpad) {
3155                 gst_object_unref(GST_OBJECT(sinkpad));
3156                 sinkpad = NULL;
3157         }
3158
3159         if (srcpad) {
3160                 gst_object_unref(GST_OBJECT(srcpad));
3161                 srcpad = NULL;
3162         }
3163
3164         if (selector_srcpad) {
3165                 gst_object_unref(GST_OBJECT(selector_srcpad));
3166                 selector_srcpad = NULL;
3167         }
3168
3169         MMPLAYER_FLEAVE();
3170         return;
3171 }
3172
3173 static void
3174 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3175 {
3176         mm_player_t* player = NULL;
3177         GstPad* srcpad = NULL;
3178         GstElement* video_selector = NULL;
3179         GstElement* audio_selector = NULL;
3180         GstElement* text_selector = NULL;
3181         MMHandleType attrs = 0;
3182         gint active_index = 0;
3183         gint64 dur_bytes = 0L;
3184
3185         player = (mm_player_t*) data;
3186
3187         LOGD("no-more-pad signal handling\n");
3188
3189         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3190                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3191                 LOGW("no need to go more");
3192
3193                 if (player->gapless.reconfigure) {
3194                         player->gapless.reconfigure = FALSE;
3195                         MMPLAYER_PLAYBACK_UNLOCK(player);
3196                 }
3197
3198                 return;
3199         }
3200
3201         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3202                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3203                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3204                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3205                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3206
3207                 if (NULL == player->streamer) {
3208                         LOGW("invalid state for buffering");
3209                         goto ERROR;
3210                 }
3211
3212                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3213                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3214
3215                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3216                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3217
3218                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3219
3220                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3221                         LOGE("fail to get duration.\n");
3222
3223                 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3224                  * use file information was already set on Q2 when it was created. */
3225                 __mm_player_streaming_set_queue2(player->streamer,
3226                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3227                                                 TRUE,                               /* use_buffering */
3228                                                 buffer_bytes,
3229                                                 init_buffering_time,
3230                                                 1.0,                                /* low percent */
3231                                                 player->ini.http_buffering_limit,   /* high percent */
3232                                                 MUXED_BUFFER_TYPE_MAX,              /* use previous buffer type setting */
3233                                                 NULL,
3234                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3235         }
3236
3237         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3238         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3239         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3240         if (video_selector) {
3241                 // [link] input-selector :: videobin
3242                 srcpad = gst_element_get_static_pad(video_selector, "src");
3243                 if (!srcpad) {
3244                         LOGE("failed to get srcpad from video selector\n");
3245                         goto ERROR;
3246                 }
3247
3248                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3249                 if (!text_selector && !audio_selector)
3250                         player->no_more_pad = TRUE;
3251
3252                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3253
3254                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3256                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3257                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3258                 }
3259         }
3260
3261         if (audio_selector) {
3262                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3263                 if ((active_index != DEFAULT_TRACK) &&
3264                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3265                         LOGW("failed to change audio track\n");
3266                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3267                 }
3268
3269                 // [link] input-selector :: audiobin
3270                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3271                 if (!srcpad) {
3272                         LOGE("failed to get srcpad from selector\n");
3273                         goto ERROR;
3274                 }
3275
3276                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3277                 if (!text_selector)
3278                         player->no_more_pad = TRUE;
3279
3280                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3281                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3282                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3283                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3284                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3285                         }
3286
3287                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3288                 } else {
3289                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3290
3291                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3292                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3293                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3294                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3295                         }
3296                 }
3297
3298                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3299
3300                 attrs = MMPLAYER_GET_ATTRS(player);
3301                 if (attrs) {
3302                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3303                         if (mmf_attrs_commit(attrs))
3304                                 LOGE("failed to commit.\n");
3305                 } else
3306                         LOGE("cannot get content attribute");
3307         } else {
3308                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3309                         LOGD("There is no audio track : remove audiobin");
3310
3311                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3312                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3313
3314                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3315                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3316                 }
3317
3318                 if (player->num_dynamic_pad == 0)
3319                         __mmplayer_pipeline_complete(NULL, player);
3320         }
3321
3322         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3323                 if (text_selector)
3324                         __mmplayer_handle_text_decode_path(player, text_selector);
3325         }
3326
3327         MMPLAYER_FLEAVE();
3328
3329 ERROR:
3330         if (srcpad) {
3331                 gst_object_unref(GST_OBJECT(srcpad));
3332                 srcpad = NULL;
3333         }
3334
3335         if (player->gapless.reconfigure) {
3336                 player->gapless.reconfigure = FALSE;
3337                 MMPLAYER_PLAYBACK_UNLOCK(player);
3338         }
3339 }
3340
3341 static void
3342 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3343 {
3344         mm_player_t* player = NULL;
3345         MMHandleType attrs = 0;
3346         GstElement* pipeline = NULL;
3347         GstCaps* caps = NULL;
3348         gchar* caps_str = NULL;
3349         GstStructure* str = NULL;
3350         const gchar* name = NULL;
3351         GstPad* sinkpad = NULL;
3352         GstElement* sinkbin = NULL;
3353         gboolean reusing = FALSE;
3354         GstElement *text_selector = NULL;
3355
3356         /* check handles */
3357         player = (mm_player_t*) data;
3358
3359         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3360         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3361
3362         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3363
3364         attrs = MMPLAYER_GET_ATTRS(player);
3365         if (!attrs) {
3366                 LOGE("cannot get content attribute\n");
3367                 goto ERROR;
3368         }
3369
3370         /* get mimetype from caps */
3371         caps = gst_pad_query_caps(pad, NULL);
3372         if (!caps) {
3373                 LOGE("cannot get caps from pad.\n");
3374                 goto ERROR;
3375         }
3376         caps_str = gst_caps_to_string(caps);
3377
3378         str = gst_caps_get_structure(caps, 0);
3379         if (!str) {
3380                 LOGE("cannot get structure from caps.\n");
3381                 goto ERROR;
3382         }
3383
3384         name = gst_structure_get_name(str);
3385         if (!name) {
3386                 LOGE("cannot get mimetype from structure.\n");
3387                 goto ERROR;
3388         }
3389
3390         //LOGD("detected mimetype : %s\n", name);
3391
3392         if (strstr(name, "audio")) {
3393                 if (player->pipeline->audiobin == NULL) {
3394                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3395                                 LOGE("failed to create audiobin. continuing without audio\n");
3396                                 goto ERROR;
3397                         }
3398
3399                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3400                         LOGD("creating audiosink bin success\n");
3401                 } else {
3402                         reusing = TRUE;
3403                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3404                         LOGD("reusing audiobin\n");
3405                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3406                 }
3407
3408                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3409                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3410
3411                 player->audiosink_linked  = 1;
3412
3413                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3414                 if (!sinkpad) {
3415                         LOGE("failed to get pad from sinkbin\n");
3416                         goto ERROR;
3417                 }
3418         } else if (strstr(name, "video")) {
3419                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3420                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3421                         player->set_mode.video_zc = TRUE;
3422
3423                 if (player->pipeline->videobin == NULL) {
3424                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3425                         /* get video surface type */
3426                         int surface_type = 0;
3427                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3428                         LOGD("display_surface_type(%d)\n", surface_type);
3429
3430                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3431                                 LOGD("not make videobin because it dose not want\n");
3432                                 goto ERROR;
3433                         }
3434
3435                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3436                                 /* mark video overlay for acquire */
3437                                 if (player->video_overlay_resource == NULL) {
3438                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3439                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3440                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3441                                                         &player->video_overlay_resource)
3442                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3443                                                 LOGE("could not mark video_overlay resource for acquire\n");
3444                                                 goto ERROR;
3445                                         }
3446                                 }
3447                         }
3448
3449                         player->interrupted_by_resource = FALSE;
3450                         /* acquire resources for video overlay */
3451                         if (mm_resource_manager_commit(player->resource_manager) !=
3452                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3453                                 LOGE("could not acquire resources for video playing\n");
3454                                 goto ERROR;
3455                         }
3456
3457                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3458                                 LOGE("failed to create videobin. continuing without video\n");
3459                                 goto ERROR;
3460                         }
3461
3462                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3463                         LOGD("creating videosink bin success\n");
3464                 } else {
3465                         reusing = TRUE;
3466                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3467                         LOGD("re-using videobin\n");
3468                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3469                 }
3470
3471                 player->videosink_linked  = 1;
3472
3473                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3474                 if (!sinkpad) {
3475                         LOGE("failed to get pad from sinkbin\n");
3476                         goto ERROR;
3477                 }
3478         } else if (strstr(name, "text")) {
3479                 if (player->pipeline->textbin == NULL) {
3480                         MMPlayerGstElement* mainbin = NULL;
3481
3482                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3483                                 LOGE("failed to create text sink bin. continuing without text\n");
3484                                 goto ERROR;
3485                         }
3486
3487                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3488                         LOGD("creating textsink bin success\n");
3489
3490                         /* FIXIT : track number shouldn't be hardcoded */
3491                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3492
3493                         player->textsink_linked  = 1;
3494                         LOGI("player->textsink_linked set to 1\n");
3495
3496                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3497                         if (!sinkpad) {
3498                                 LOGE("failed to get pad from sinkbin\n");
3499                                 goto ERROR;
3500                         }
3501
3502                         mainbin = player->pipeline->mainbin;
3503
3504                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3505                                 /* input selector */
3506                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3507                                 if (!text_selector) {
3508                                         LOGE("failed to create subtitle input selector element\n");
3509                                         goto ERROR;
3510                                 }
3511                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3512
3513                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3514                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3515
3516                                 /* warm up */
3517                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3518                                         LOGE("failed to set state(READY) to sinkbin\n");
3519                                         goto ERROR;
3520                                 }
3521
3522                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3523                                         LOGW("failed to add subtitle input selector\n");
3524                                         goto ERROR;
3525                                 }
3526
3527                                 LOGD("created element input-selector");
3528
3529                         } else {
3530                                 LOGD("already having subtitle input selector");
3531                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3532                         }
3533                 } else {
3534                         if (!player->textsink_linked) {
3535                                 LOGD("re-using textbin\n");
3536
3537                                 reusing = TRUE;
3538                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3539
3540                                 player->textsink_linked  = 1;
3541                                 LOGI("player->textsink_linked set to 1\n");
3542                         } else
3543                                 LOGD("ignoring internal subtutle since external subtitle is available");
3544                 }
3545         } else {
3546                 LOGW("unknown type of elementary stream!ignoring it...\n");
3547                 goto ERROR;
3548         }
3549
3550         if (sinkbin) {
3551                 if (!reusing) {
3552                         /* warm up */
3553                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3554                                 LOGE("failed to set state(READY) to sinkbin\n");
3555                                 goto ERROR;
3556                         }
3557
3558                         /* Added for multi audio support to avoid adding audio bin again*/
3559                         /* add */
3560                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3561                                 LOGE("failed to add sinkbin to pipeline\n");
3562                                 goto ERROR;
3563                         }
3564                 }
3565
3566                 /* link */
3567                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3568                         LOGE("failed to get pad from sinkbin\n");
3569                         goto ERROR;
3570                 }
3571
3572                 if (!reusing) {
3573                         /* run */
3574                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3575                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3576                                 goto ERROR;
3577                         }
3578
3579                         if (text_selector) {
3580                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3581                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3582                                         goto ERROR;
3583                                 }
3584                         }
3585                 }
3586
3587                 gst_object_unref(sinkpad);
3588                 sinkpad = NULL;
3589         }
3590
3591         LOGD("[handle: %p] linking sink bin success", player);
3592
3593         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3594          * streaming task. if the task blocked, then buffer will not flow to the next element
3595          *(autoplugging element). so this is special hack for streaming. please try to remove it
3596          */
3597         /* dec stream count. we can remove fakesink if it's zero */
3598         if (player->num_dynamic_pad)
3599                 player->num_dynamic_pad--;
3600
3601         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3602
3603         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3604                 __mmplayer_pipeline_complete(NULL, player);
3605
3606 ERROR:
3607
3608         MMPLAYER_FREEIF(caps_str);
3609
3610         if (caps)
3611                 gst_caps_unref(caps);
3612
3613         if (sinkpad)
3614                 gst_object_unref(GST_OBJECT(sinkpad));
3615
3616         /* flusing out new attributes */
3617         if (mmf_attrs_commit(attrs))
3618                 LOGE("failed to comit attributes\n");
3619
3620         return;
3621 }
3622
3623 static gboolean
3624 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3625 {
3626         int pro_value = 0; // in the case of expection, default will be returned.
3627         int dest_angle = rotation_angle;
3628         int rotation_type = -1;
3629
3630         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3631         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3632         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3633
3634         if (rotation_angle >= 360)
3635                 dest_angle = rotation_angle - 360;
3636
3637         /* chech if supported or not */
3638         if (dest_angle % 90) {
3639                 LOGD("not supported rotation angle = %d", rotation_angle);
3640                 return FALSE;
3641         }
3642
3643         /*
3644           * tizenwlsink (A)
3645           * custom_convert - none (B)
3646           * videoflip - none (C)
3647           */
3648         if (player->set_mode.video_zc) {
3649                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3650                         rotation_type = ROTATION_USING_CUSTOM;
3651                 else // A
3652                         rotation_type = ROTATION_USING_SINK;
3653         } else {
3654                 int surface_type = 0;
3655                 rotation_type = ROTATION_USING_FLIP;
3656
3657                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3658                 LOGD("check display surface type attribute: %d", surface_type);
3659
3660                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3661                         rotation_type = ROTATION_USING_SINK;
3662                 else
3663                         rotation_type = ROTATION_USING_FLIP; //C
3664
3665                 LOGD("using %d type for rotation", rotation_type);
3666         }
3667
3668         /* get property value for setting */
3669         switch (rotation_type) {
3670         case ROTATION_USING_SINK: // tizenwlsink
3671                 {
3672                         switch (dest_angle) {
3673                         case 0:
3674                                 break;
3675                         case 90:
3676                                 pro_value = 3; // clockwise 90
3677                                 break;
3678                         case 180:
3679                                 pro_value = 2;
3680                                 break;
3681                         case 270:
3682                                 pro_value = 1; // counter-clockwise 90
3683                                 break;
3684                         }
3685                 }
3686                 break;
3687         case ROTATION_USING_CUSTOM:
3688                 {
3689                         gchar *ename = NULL;
3690                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3691
3692                         if (g_strrstr(ename, "fimcconvert")) {
3693                                 switch (dest_angle) {
3694                                 case 0:
3695                                         break;
3696                                 case 90:
3697                                         pro_value = 90; // clockwise 90
3698                                         break;
3699                                 case 180:
3700                                         pro_value = 180;
3701                                         break;
3702                                 case 270:
3703                                         pro_value = 270; // counter-clockwise 90
3704                                         break;
3705                                 }
3706                         }
3707                 }
3708                 break;
3709         case ROTATION_USING_FLIP: // videoflip
3710                 {
3711                                 switch (dest_angle) {
3712                                 case 0:
3713                                         break;
3714                                 case 90:
3715                                         pro_value = 1; // clockwise 90
3716                                         break;
3717                                 case 180:
3718                                         pro_value = 2;
3719                                         break;
3720                                 case 270:
3721                                         pro_value = 3; // counter-clockwise 90
3722                                         break;
3723                                 }
3724                 }
3725                 break;
3726         }
3727
3728         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3729
3730         *value = pro_value;
3731
3732         return TRUE;
3733 }
3734
3735 int
3736 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3737 {
3738         /* check video sinkbin is created */
3739         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3740                 player->pipeline &&
3741                 player->pipeline->videobin &&
3742                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3743                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3744                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3745
3746         return MM_ERROR_NONE;
3747 }
3748
3749 void
3750 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3751 {
3752         int rotation_value = 0;
3753         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3754         int user_angle = 0;
3755         MMPLAYER_FENTER();
3756
3757         /* check video sinkbin is created */
3758         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3759                 return;
3760
3761         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3762
3763         /* get rotation value to set */
3764         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3765         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3766         LOGD("set video param : rotate %d", rotation_value);
3767 }
3768
3769 void
3770 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3771 {
3772         MMHandleType attrs = 0;
3773         int visible = 0;
3774         MMPLAYER_FENTER();
3775
3776         /* check video sinkbin is created */
3777         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3778                 return;
3779
3780         attrs = MMPLAYER_GET_ATTRS(player);
3781         MMPLAYER_RETURN_IF_FAIL(attrs);
3782
3783         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3784         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3785         LOGD("set video param : visible %d", visible);
3786 }
3787
3788 void
3789 __mmplayer_video_param_set_display_method(mm_player_t* player)
3790 {
3791         MMHandleType attrs = 0;
3792         int display_method = 0;
3793         MMPLAYER_FENTER();
3794
3795         /* check video sinkbin is created */
3796         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3797                 return;
3798
3799         attrs = MMPLAYER_GET_ATTRS(player);
3800         MMPLAYER_RETURN_IF_FAIL(attrs);
3801
3802         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3803         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3804         LOGD("set video param : method %d", display_method);
3805 }
3806
3807 void
3808 __mmplayer_video_param_set_roi_area(mm_player_t* player)
3809 {
3810         MMHandleType attrs = 0;
3811         void *handle = NULL;
3812         /*set wl_display*/
3813         int win_roi_x = 0;
3814         int win_roi_y = 0;
3815         int win_roi_width = 0;
3816         int win_roi_height = 0;
3817         MMPLAYER_FENTER();
3818
3819         /* check video sinkbin is created */
3820         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3821                 return;
3822
3823         attrs = MMPLAYER_GET_ATTRS(player);
3824         MMPLAYER_RETURN_IF_FAIL(attrs);
3825
3826         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3827
3828         if (handle) {
3829                 /* It should be set after setting window */
3830                 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
3831                 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
3832                 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
3833                 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
3834
3835                 /* After setting window handle, set display roi area */
3836                 gst_video_overlay_set_display_roi_area(
3837                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3838                          win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3839                 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
3840                         win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3841
3842         }
3843 }
3844 void
3845 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3846 {
3847         MMHandleType attrs = 0;
3848         void *handle = NULL;
3849
3850         /* check video sinkbin is created */
3851         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3852                 return;
3853
3854         attrs = MMPLAYER_GET_ATTRS(player);
3855         MMPLAYER_RETURN_IF_FAIL(attrs);
3856
3857         /* common case if using overlay surface */
3858         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3859
3860         if (handle) {
3861                 /* default is using wl_surface_id */
3862                 unsigned int wl_surface_id      = 0;
3863                 wl_surface_id = *(int*)handle;
3864                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3865                 gst_video_overlay_set_wl_window_wl_surface_id(
3866                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3867                                 *(int*)handle);
3868         } else
3869                 /* FIXIT : is it error case? */
3870                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3871 }
3872
3873
3874 int
3875 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3876 {
3877         bool update_all_param = FALSE;
3878         MMPLAYER_FENTER();
3879
3880         /* check video sinkbin is created */
3881         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3882                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3883
3884         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3885                 LOGE("can not find tizenwlsink");
3886                 return MM_ERROR_PLAYER_INTERNAL;
3887         }
3888
3889         LOGD("param_name : %s", param_name);
3890         if (!g_strcmp0(param_name, "update_all_param"))
3891                 update_all_param = TRUE;
3892
3893         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3894                 __mmplayer_video_param_set_display_overlay(player);
3895         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3896                 __mmplayer_video_param_set_display_method(player);
3897         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3898                 __mmplayer_video_param_set_display_visible(player);
3899         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3900                 __mmplayer_video_param_set_display_rotation(player);
3901         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
3902                 __mmplayer_video_param_set_roi_area(player);
3903
3904         return MM_ERROR_NONE;
3905 }
3906
3907 int
3908 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3909 {
3910         MMHandleType attrs = 0;
3911         int surface_type = 0;
3912         int ret = MM_ERROR_NONE;
3913
3914         MMPLAYER_FENTER();
3915
3916         /* check video sinkbin is created */
3917         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3918                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3919
3920         attrs = MMPLAYER_GET_ATTRS(player);
3921         if (!attrs) {
3922                 LOGE("cannot get content attribute");
3923                 return MM_ERROR_PLAYER_INTERNAL;
3924         }
3925         LOGD("param_name : %s", param_name);
3926
3927         /* update display surface */
3928         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3929         LOGD("check display surface type attribute: %d", surface_type);
3930
3931         /* configuring display */
3932         switch (surface_type) {
3933         case MM_DISPLAY_SURFACE_OVERLAY:
3934                 {
3935                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3936                         if (ret != MM_ERROR_NONE)
3937                                 return ret;
3938                 }
3939                 break;
3940         }
3941
3942         MMPLAYER_FLEAVE();
3943
3944         return MM_ERROR_NONE;
3945 }
3946
3947 int
3948 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3949 {
3950         gboolean disable_overlay = FALSE;
3951         mm_player_t* player = (mm_player_t*) hplayer;
3952         int ret = MM_ERROR_NONE;
3953
3954         MMPLAYER_FENTER();
3955         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3956         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3957                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3958                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3959
3960         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3961                 LOGW("Display control is not supported");
3962                 return MM_ERROR_PLAYER_INTERNAL;
3963         }
3964
3965         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3966
3967         if (audio_only == (bool)disable_overlay) {
3968                 LOGE("It's the same with current setting: (%d)", audio_only);
3969                 return MM_ERROR_NONE;
3970         }
3971
3972         if (audio_only) {
3973                 LOGE("disable overlay");
3974                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3975
3976                 /* release overlay resource */
3977                 if (player->video_overlay_resource != NULL) {
3978                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3979                                         player->video_overlay_resource);
3980                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3981                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3982                                 goto ERROR;
3983                         }
3984                         player->video_overlay_resource = NULL;
3985                 }
3986
3987                 ret = mm_resource_manager_commit(player->resource_manager);
3988                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3990                         goto ERROR;
3991                 }
3992         } else {
3993                 /* mark video overlay for acquire */
3994                 if (player->video_overlay_resource == NULL) {
3995                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3996                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3997                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3998                                         &player->video_overlay_resource);
3999                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4000                                 LOGE("could not prepare for video_overlay resource\n");
4001                                 goto ERROR;
4002                         }
4003                 }
4004
4005                 player->interrupted_by_resource = FALSE;
4006                 /* acquire resources for video overlay */
4007                 ret = mm_resource_manager_commit(player->resource_manager);
4008                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4009                         LOGE("could not acquire resources for video playing\n");
4010                         goto ERROR;
4011                 }
4012
4013                 LOGD("enable overlay");
4014                 __mmplayer_video_param_set_display_overlay(player);
4015                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4016         }
4017
4018 ERROR:
4019         MMPLAYER_FLEAVE();
4020         return MM_ERROR_NONE;
4021 }
4022
4023 int
4024 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4025 {
4026         mm_player_t* player = (mm_player_t*) hplayer;
4027         gboolean disable_overlay = FALSE;
4028
4029         MMPLAYER_FENTER();
4030
4031         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4032         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4033         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4034                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4035                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4036
4037         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4038                 LOGW("Display control is not supported");
4039                 return MM_ERROR_PLAYER_INTERNAL;
4040         }
4041
4042         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4043
4044         *paudio_only = (bool)(disable_overlay);
4045
4046         LOGD("audio_only : %d", *paudio_only);
4047
4048         MMPLAYER_FLEAVE();
4049
4050         return MM_ERROR_NONE;
4051 }
4052
4053 static int
4054 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4055 {
4056         GList* bucket = element_bucket;
4057         MMPlayerGstElement* element = NULL;
4058         MMPlayerGstElement* prv_element = NULL;
4059         gint successful_link_count = 0;
4060
4061         MMPLAYER_FENTER();
4062
4063         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4064
4065         prv_element = (MMPlayerGstElement*)bucket->data;
4066         bucket = bucket->next;
4067
4068         for (; bucket; bucket = bucket->next) {
4069                 element = (MMPlayerGstElement*)bucket->data;
4070
4071                 if (element && element->gst) {
4072                         /* If next element is audio appsrc then make a separate audio pipeline */
4073                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4074                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4075                                 prv_element = element;
4076                                 continue;
4077                         }
4078
4079                         if (prv_element && prv_element->gst) {
4080                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4081                                         LOGD("linking [%s] to [%s] success\n",
4082                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4083                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4084                                         successful_link_count++;
4085                                 } else {
4086                                         LOGD("linking [%s] to [%s] failed\n",
4087                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4088                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4089                                         return -1;
4090                                 }
4091                         }
4092                 }
4093
4094                 prv_element = element;
4095         }
4096
4097         MMPLAYER_FLEAVE();
4098
4099         return successful_link_count;
4100 }
4101
4102 static int
4103 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4104 {
4105         GList* bucket = element_bucket;
4106         MMPlayerGstElement* element = NULL;
4107         int successful_add_count = 0;
4108
4109         MMPLAYER_FENTER();
4110
4111         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4112         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4113
4114         for (; bucket; bucket = bucket->next) {
4115                 element = (MMPlayerGstElement*)bucket->data;
4116
4117                 if (element && element->gst) {
4118                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4119                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4120                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4121                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4122                                 return 0;
4123                         }
4124                         successful_add_count++;
4125                 }
4126         }
4127
4128         MMPLAYER_FLEAVE();
4129
4130         return successful_add_count;
4131 }
4132
4133 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4134 {
4135         mm_player_t* player = (mm_player_t*) data;
4136         GstCaps *caps = NULL;
4137         GstStructure *str = NULL;
4138         const char *name;
4139
4140         MMPLAYER_FENTER();
4141
4142         MMPLAYER_RETURN_IF_FAIL(pad)
4143         MMPLAYER_RETURN_IF_FAIL(unused)
4144         MMPLAYER_RETURN_IF_FAIL(data)
4145
4146         caps = gst_pad_get_current_caps(pad);
4147         if (!caps)
4148                 return;
4149
4150         str = gst_caps_get_structure(caps, 0);
4151         if (!str)
4152                 goto ERROR;
4153
4154         name = gst_structure_get_name(str);
4155         if (!name)
4156                 goto ERROR;
4157
4158         LOGD("name = %s\n", name);
4159
4160         if (strstr(name, "audio")) {
4161                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4162
4163                 if (player->audio_stream_changed_cb) {
4164                         LOGE("call the audio stream changed cb\n");
4165                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4166                 }
4167         } else if (strstr(name, "video")) {
4168                 if ((name = gst_structure_get_string(str, "format")))
4169                         player->set_mode.video_zc = name[0] == 'S';
4170
4171                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4172
4173                 if (player->video_stream_changed_cb) {
4174                         LOGE("call the video stream changed cb\n");
4175                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4176                 }
4177         } else
4178                 goto ERROR;
4179
4180 ERROR:
4181
4182         gst_caps_unref(caps);
4183
4184         MMPLAYER_FLEAVE();
4185
4186         return;
4187 }
4188
4189
4190
4191 /**
4192  * This function is to create audio pipeline for playing.
4193  *
4194  * @param       player          [in]    handle of player
4195  *
4196  * @return      This function returns zero on success.
4197  * @remark
4198  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4199  */
4200 /* macro for code readability. just for sinkbin-creation functions */
4201 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4202 do {\
4203         x_bin[x_id].id = x_id;\
4204         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4205         if (!x_bin[x_id].gst) {\
4206                 LOGE("failed to create %s \n", x_factory);\
4207                 goto ERROR;\
4208         } else {\
4209                 if (x_player->ini.set_dump_element_flag)\
4210                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4211         } \
4212         if (x_add_bucket)\
4213                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4214 } while (0);
4215
4216 static void
4217 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4218 {
4219         GList *l = NULL;
4220
4221         MMPLAYER_FENTER();
4222         MMPLAYER_RETURN_IF_FAIL(player);
4223
4224         if (player->audio_stream_buff_list) {
4225                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4226                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4227                         if (tmp) {
4228                                 if (send_all) {
4229                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4230                                         __mmplayer_audio_stream_send_data(player, tmp);
4231                                 }
4232                                 if (tmp->pcm_data)
4233                                         g_free(tmp->pcm_data);
4234                                 g_free(tmp);
4235                         }
4236                 }
4237                 g_list_free(player->audio_stream_buff_list);
4238                 player->audio_stream_buff_list = NULL;
4239         }
4240
4241         MMPLAYER_FLEAVE();
4242 }
4243
4244 static void
4245 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4246 {
4247         MMPlayerAudioStreamDataType audio_stream = { 0, };
4248
4249         MMPLAYER_FENTER();
4250         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4251
4252         audio_stream.bitrate = a_buffer->bitrate;
4253         audio_stream.channel = a_buffer->channel;
4254         audio_stream.depth = a_buffer->depth;
4255         audio_stream.is_little_endian = a_buffer->is_little_endian;
4256         audio_stream.channel_mask = a_buffer->channel_mask;
4257         audio_stream.data_size = a_buffer->data_size;
4258         audio_stream.data = a_buffer->pcm_data;
4259
4260         /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4261         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4262
4263         MMPLAYER_FLEAVE();
4264 }
4265
4266 static void
4267 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4268 {
4269         mm_player_t* player = (mm_player_t*) data;
4270
4271         gint channel = 0;
4272         gint rate = 0;
4273         gint depth = 0;
4274         gint endianness = 0;
4275         guint64 channel_mask = 0;
4276         void *a_data = NULL;
4277         gint a_size = 0;
4278         mm_player_audio_stream_buff_t *a_buffer = NULL;
4279         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4280         GList *l = NULL;
4281
4282         MMPLAYER_FENTER();
4283         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4284
4285         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4286         a_data = mapinfo.data;
4287         a_size = mapinfo.size;
4288
4289         GstCaps *caps = gst_pad_get_current_caps(pad);
4290         GstStructure *structure = gst_caps_get_structure(caps, 0);
4291
4292         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4293         gst_structure_get_int(structure, "rate", &rate);
4294         gst_structure_get_int(structure, "channels", &channel);
4295         gst_structure_get_int(structure, "depth", &depth);
4296         gst_structure_get_int(structure, "endianness", &endianness);
4297         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4298         gst_caps_unref(GST_CAPS(caps));
4299
4300         /* In case of the sync is false, use buffer list.              *
4301          * The num of buffer list depends on the num of audio channels */
4302         if (player->audio_stream_buff_list) {
4303                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4304                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4305                         if (tmp) {
4306                                 if (channel_mask == tmp->channel_mask) {
4307                                         /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4308                                         if (tmp->data_size + a_size < tmp->buff_size) {
4309                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4310                                                 tmp->data_size += a_size;
4311                                         } else {
4312                                                 /* send data to client */
4313                                                 __mmplayer_audio_stream_send_data(player, tmp);
4314
4315                                                 if (a_size > tmp->buff_size) {
4316                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4317                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4318                                                         if (tmp->pcm_data == NULL) {
4319                                                                 LOGE("failed to realloc data.");
4320                                                                 goto DONE;
4321                                                         }
4322                                                         tmp->buff_size = a_size;
4323                                                 }
4324                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4325                                                 memcpy(tmp->pcm_data, a_data, a_size);
4326                                                 tmp->data_size = a_size;
4327                                         }
4328                                         goto DONE;
4329                                 }
4330                         } else {
4331                                 LOGE("data is empty in list.");
4332                                 goto DONE;
4333                         }
4334                 }
4335         }
4336
4337         /* create new audio stream data */
4338         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4339         if (a_buffer == NULL) {
4340                 LOGE("failed to alloc data.");
4341                 goto DONE;
4342         }
4343         a_buffer->bitrate = rate;
4344         a_buffer->channel = channel;
4345         a_buffer->depth = depth;
4346         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4347         a_buffer->channel_mask = channel_mask;
4348         a_buffer->data_size = a_size;
4349
4350         if (!player->audio_stream_sink_sync) {
4351                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4352                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4353                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4354                 if (a_buffer->pcm_data == NULL) {
4355                         LOGE("failed to alloc data.");
4356                         g_free(a_buffer);
4357                         goto DONE;
4358                 }
4359                 memcpy(a_buffer->pcm_data, a_data, a_size);
4360                 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4361                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4362         } else {
4363                 /* If sync is TRUE, send data directly. */
4364                 a_buffer->pcm_data = a_data;
4365                 __mmplayer_audio_stream_send_data(player, a_buffer);
4366                 g_free(a_buffer);
4367         }
4368
4369 DONE:
4370         gst_buffer_unmap(buffer, &mapinfo);
4371         MMPLAYER_FLEAVE();
4372 }
4373
4374 static void
4375 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4376 {
4377         mm_player_t* player = (mm_player_t*)data;
4378         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4379         GstPad* sinkpad = NULL;
4380         GstElement *queue = NULL, *sink = NULL;
4381
4382         MMPLAYER_FENTER();
4383         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4384
4385         queue = gst_element_factory_make("queue", NULL);
4386         if (queue == NULL) {
4387                 LOGD("fail make queue\n");
4388                 goto ERROR;
4389         }
4390
4391         sink = gst_element_factory_make("fakesink", NULL);
4392         if (sink == NULL) {
4393                 LOGD("fail make fakesink\n");
4394                 goto ERROR;
4395         }
4396
4397         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4398
4399         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4400                 LOGW("failed to link queue & sink\n");
4401                 goto ERROR;
4402         }
4403
4404         sinkpad = gst_element_get_static_pad(queue, "sink");
4405
4406         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4407                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4408                 goto ERROR;
4409         }
4410
4411         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4412
4413         gst_object_unref(sinkpad);
4414         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4415         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4416
4417         gst_element_set_state(sink, GST_STATE_PAUSED);
4418         gst_element_set_state(queue, GST_STATE_PAUSED);
4419
4420         MMPLAYER_SIGNAL_CONNECT(player,
4421                 G_OBJECT(sink),
4422                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4423                 "handoff",
4424                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4425                 (gpointer)player);
4426
4427         MMPLAYER_FLEAVE();
4428         return;
4429
4430 ERROR:
4431         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4432         if (queue) {
4433                 gst_object_unref(GST_OBJECT(queue));
4434                 queue = NULL;
4435         }
4436         if (sink) {
4437                 gst_object_unref(GST_OBJECT(sink));
4438                 sink = NULL;
4439         }
4440         if (sinkpad) {
4441                 gst_object_unref(GST_OBJECT(sinkpad));
4442                 sinkpad = NULL;
4443         }
4444
4445         return;
4446 }
4447
4448 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4449 {
4450         #define MAX_PROPS_LEN 128
4451         gint latency_mode = 0;
4452         gchar *stream_type = NULL;
4453         gchar *latency = NULL;
4454         gint stream_id = 0;
4455         gchar stream_props[MAX_PROPS_LEN] = {0,};
4456         GstStructure *props = NULL;
4457
4458         /* set volume table
4459          * It should be set after player creation through attribute.
4460          * But, it can not be changed during playing.
4461          */
4462         MMPLAYER_FENTER();
4463         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4464         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4465
4466         if (!stream_type) {
4467                 LOGE("stream_type is null.\n");
4468         } else {
4469                 if (player->sound.focus_id)
4470                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4471                                         stream_type, stream_id, player->sound.focus_id);
4472                 else
4473                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4474                                         stream_type, stream_id);
4475                 props = gst_structure_from_string(stream_props, NULL);
4476                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4477                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4478                         stream_type, stream_id, player->sound.focus_id, stream_props);
4479                 gst_structure_free(props);
4480         }
4481
4482         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4483
4484         switch (latency_mode) {
4485         case AUDIO_LATENCY_MODE_LOW:
4486                 latency = g_strndup("low", 3);
4487                 break;
4488         case AUDIO_LATENCY_MODE_MID:
4489                 latency = g_strndup("mid", 3);
4490                 break;
4491         case AUDIO_LATENCY_MODE_HIGH:
4492                 latency = g_strndup("high", 4);
4493                 break;
4494         };
4495
4496         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4497                         "latency", latency,
4498                         NULL);
4499
4500         LOGD("audiosink property - latency=%s \n", latency);
4501
4502         g_free(latency);
4503
4504         MMPLAYER_FLEAVE();
4505 }
4506
4507 static int
4508 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4509 {
4510         MMPlayerGstElement* first_element = NULL;
4511         MMPlayerGstElement* audiobin = NULL;
4512         MMHandleType attrs = 0;
4513         GstPad *pad = NULL;
4514         GstPad *ghostpad = NULL;
4515         GList* element_bucket = NULL;
4516         gboolean link_audio_sink_now = TRUE;
4517         int i = 0;
4518         GstCaps *acaps;
4519
4520         MMPLAYER_FENTER();
4521
4522         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4523
4524         /* alloc handles */
4525         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4526         if (!audiobin) {
4527                 LOGE("failed to allocate memory for audiobin\n");
4528                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4529         }
4530
4531         attrs = MMPLAYER_GET_ATTRS(player);
4532
4533         /* create bin */
4534         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4535         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4536         if (!audiobin[MMPLAYER_A_BIN].gst) {
4537                 LOGE("failed to create audiobin\n");
4538                 goto ERROR;
4539         }
4540
4541         /* take it */
4542         player->pipeline->audiobin = audiobin;
4543
4544         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4545
4546         /* Adding audiotp plugin for reverse trickplay feature */
4547 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4548
4549         /* converter */
4550         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4551
4552         /* replaygain volume */
4553         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4554         if (player->sound.rg_enable)
4555                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4556         else
4557                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4558
4559         /* resampler */
4560         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4561
4562         if (player->set_mode.pcm_extraction) {
4563                 // pcm extraction only and no sound output
4564                 if (player->audio_stream_render_cb_ex) {
4565                         char *caps_str = NULL;
4566                         GstCaps* caps = NULL;
4567                         gchar *format = NULL;
4568
4569                         /* capsfilter */
4570                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4571
4572                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4573
4574                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4575
4576                         caps = gst_caps_new_simple("audio/x-raw",
4577                                         "format", G_TYPE_STRING, format,
4578                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4579                                         "channels", G_TYPE_INT, player->pcm_channel,
4580                                         NULL);
4581                         caps_str = gst_caps_to_string(caps);
4582                         LOGD("new caps : %s\n", caps_str);
4583
4584                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4585
4586                         /* clean */
4587                         gst_caps_unref(caps);
4588                         MMPLAYER_FREEIF(caps_str);
4589
4590                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4591
4592                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4593                         /* raw pad handling signal */
4594                         MMPLAYER_SIGNAL_CONNECT(player,
4595                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4596                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4597                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4598                 } else {
4599                         int dst_samplerate = 0;
4600                         int dst_channels = 0;
4601                         int dst_depth = 0;
4602                         char *caps_str = NULL;
4603                         GstCaps* caps = NULL;
4604
4605                         /* get conf. values */
4606                         mm_attrs_multiple_get(player->attrs,
4607                                                 NULL,
4608                                                 "pcm_extraction_samplerate", &dst_samplerate,
4609                                                 "pcm_extraction_channels", &dst_channels,
4610                                                 "pcm_extraction_depth", &dst_depth,
4611                                                 NULL);
4612
4613                         /* capsfilter */
4614                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4615                         caps = gst_caps_new_simple("audio/x-raw",
4616                                         "rate", G_TYPE_INT, dst_samplerate,
4617                                         "channels", G_TYPE_INT, dst_channels,
4618                                         "depth", G_TYPE_INT, dst_depth,
4619                                         NULL);
4620                         caps_str = gst_caps_to_string(caps);
4621                         LOGD("new caps : %s\n", caps_str);
4622
4623                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4624
4625                         /* clean */
4626                         gst_caps_unref(caps);
4627                         MMPLAYER_FREEIF(caps_str);
4628
4629                         /* fake sink */
4630                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4631
4632                         /* set sync */
4633                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4634                 }
4635         } else {
4636                 // normal playback
4637                 //GstCaps* caps = NULL;
4638                 gint channels = 0;
4639
4640                 /* for logical volume control */
4641                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4642                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4643
4644                 if (player->sound.mute) {
4645                         LOGD("mute enabled\n");
4646                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4647                 }
4648
4649 #if 0
4650                 /*capsfilter */
4651                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4652                 caps = gst_caps_from_string("audio/x-raw-int, "
4653                                         "endianness = (int) LITTLE_ENDIAN, "
4654                                         "signed = (boolean) true, "
4655                                         "width = (int) 16, "
4656                                         "depth = (int) 16");
4657                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4658                 gst_caps_unref(caps);
4659 #endif
4660
4661                 /* check if multi-channels */
4662                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4663                         GstPad *srcpad = NULL;
4664                         GstCaps *caps = NULL;
4665
4666                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4667                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4668                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4669                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4670                                         if (str)
4671                                                 gst_structure_get_int(str, "channels", &channels);
4672                                         gst_caps_unref(caps);
4673                                 }
4674                                 gst_object_unref(srcpad);
4675                         }
4676                 }
4677
4678                 /* audio effect element. if audio effect is enabled */
4679                 if ((strcmp(player->ini.audioeffect_element, ""))
4680                         && (channels <= 2)
4681                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4682                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4683
4684                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4685
4686                         if ((!player->bypass_audio_effect)
4687                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4688                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4689                                         if (!_mmplayer_audio_effect_custom_apply(player))
4690                                                 LOGI("apply audio effect(custom) setting success\n");
4691                                 }
4692                         }
4693
4694                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4695                                 && (player->set_mode.rich_audio))
4696                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4697                 }
4698
4699                 /* create audio sink */
4700                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4701                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4702                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4703
4704                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4705                 if (player->is_360_feature_enabled &&
4706                         player->is_content_spherical &&
4707                         channels == 4 &&
4708                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4709                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4710                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4711
4712                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4713
4714                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4715
4716                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4717                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4718                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4719                         gst_caps_unref(acaps);
4720
4721                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4722                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4723                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4724                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4725
4726                         player->is_openal_plugin_used = TRUE;
4727
4728                         if (player->video360_yaw_radians <= M_PI &&
4729                                         player->video360_yaw_radians >= -M_PI &&
4730                                         player->video360_pitch_radians <= M_PI_2 &&
4731                                         player->video360_pitch_radians >= -M_PI_2) {
4732                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4733                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4734                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4735                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4736                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4737                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4738                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4739                         }
4740                 } else {
4741                         if (player->is_360_feature_enabled && player->is_content_spherical)
4742                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4743                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4744                 }
4745
4746                 /* qos on */
4747                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4748                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4749
4750
4751                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4752                         (player->videodec_linked && player->ini.use_system_clock)) {
4753                         LOGD("system clock will be used.\n");
4754                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4755                 }
4756
4757                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4758                         __mmplayer_gst_set_audiosink_property(player, attrs);
4759         }
4760
4761         if (audiobin[MMPLAYER_A_SINK].gst) {
4762                 GstPad *sink_pad = NULL;
4763                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4764                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4765                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4766                 gst_object_unref(GST_OBJECT(sink_pad));
4767         }
4768
4769         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4770
4771         /* adding created elements to bin */
4772         LOGD("adding created elements to bin\n");
4773         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4774                 LOGE("failed to add elements\n");
4775                 goto ERROR;
4776         }
4777
4778         /* linking elements in the bucket by added order. */
4779         LOGD("Linking elements in the bucket by added order.\n");
4780         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4781                 LOGE("failed to link elements\n");
4782                 goto ERROR;
4783         }
4784
4785         /* get first element's sinkpad for creating ghostpad */
4786         first_element = (MMPlayerGstElement *)element_bucket->data;
4787         if (!first_element) {
4788                 LOGE("failed to get first elem\n");
4789                 goto ERROR;
4790         }
4791
4792         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4793         if (!pad) {
4794                 LOGE("failed to get pad from first element of audiobin\n");
4795                 goto ERROR;
4796         }
4797
4798         ghostpad = gst_ghost_pad_new("sink", pad);
4799         if (!ghostpad) {
4800                 LOGE("failed to create ghostpad\n");
4801                 goto ERROR;
4802         }
4803
4804         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4805                 LOGE("failed to add ghostpad to audiobin\n");
4806                 goto ERROR;
4807         }
4808
4809         gst_object_unref(pad);
4810
4811         g_list_free(element_bucket);
4812         MMPLAYER_FLEAVE();
4813
4814         return MM_ERROR_NONE;
4815
4816 ERROR:
4817
4818         LOGD("ERROR : releasing audiobin\n");
4819
4820         if (pad)
4821                 gst_object_unref(GST_OBJECT(pad));
4822
4823         if (ghostpad)
4824                 gst_object_unref(GST_OBJECT(ghostpad));
4825
4826         if (element_bucket)
4827                 g_list_free(element_bucket);
4828
4829         /* release element which are not added to bin */
4830         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4831                 /* NOTE : skip bin */
4832                 if (audiobin[i].gst) {
4833                         GstObject* parent = NULL;
4834                         parent = gst_element_get_parent(audiobin[i].gst);
4835
4836                         if (!parent) {
4837                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4838                                 audiobin[i].gst = NULL;
4839                         } else
4840                                 gst_object_unref(GST_OBJECT(parent));
4841                 }
4842         }
4843
4844         /* release audiobin with it's childs */
4845         if (audiobin[MMPLAYER_A_BIN].gst)
4846                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4847
4848         MMPLAYER_FREEIF(audiobin);
4849
4850         player->pipeline->audiobin = NULL;
4851
4852         return MM_ERROR_PLAYER_INTERNAL;
4853 }
4854
4855 static GstPadProbeReturn
4856 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4857 {
4858         mm_player_t* player = (mm_player_t*) u_data;
4859         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4860         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4861
4862         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4863
4864         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4865                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4866
4867         return GST_PAD_PROBE_OK;
4868 }
4869
4870 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4871 {
4872         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4873 }
4874
4875 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4876 {
4877         int ret = MM_ERROR_NONE;
4878         GList *l = NULL;
4879         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4881
4882         MMPLAYER_VIDEO_BO_LOCK(player);
4883
4884         if (player->video_bo_list) {
4885                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4886                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887                         if (tmp && tmp->bo == bo) {
4888                                 tmp->using = FALSE;
4889                                 LOGD("release bo %p", bo);
4890                                 tbm_bo_unref(tmp->bo);
4891                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4892                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4893                                 return ret;
4894                         }
4895                 }
4896         } else {
4897                 /* hw codec is running or the list was reset for DRC. */
4898                 LOGW("there is no bo list.");
4899         }
4900         MMPLAYER_VIDEO_BO_UNLOCK(player);
4901
4902         LOGW("failed to find bo %p", bo);
4903         return ret;
4904 }
4905
4906 static void
4907 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4908 {
4909         GList *l = NULL;
4910
4911         MMPLAYER_FENTER();
4912         MMPLAYER_RETURN_IF_FAIL(player);
4913
4914         MMPLAYER_VIDEO_BO_LOCK(player);
4915         if (player->video_bo_list) {
4916                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4917                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4918                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4919                         if (tmp) {
4920                                 if (tmp->bo)
4921                                         tbm_bo_unref(tmp->bo);
4922                                 g_free(tmp);
4923                         }
4924                 }
4925                 g_list_free(player->video_bo_list);
4926                 player->video_bo_list = NULL;
4927         }
4928         player->video_bo_size = 0;
4929         MMPLAYER_VIDEO_BO_UNLOCK(player);
4930
4931         MMPLAYER_FLEAVE();
4932         return;
4933 }
4934
4935 static void*
4936 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4937 {
4938         GList *l = NULL;
4939         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4940         gboolean ret = TRUE;
4941
4942         /* check DRC, if it is, destroy the prev bo list to create again */
4943         if (player->video_bo_size != size) {
4944                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4945                 __mmplayer_video_stream_destroy_bo_list(player);
4946                 player->video_bo_size = size;
4947         }
4948
4949         MMPLAYER_VIDEO_BO_LOCK(player);
4950
4951         if ((!player->video_bo_list) ||
4952                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4953
4954                 /* create bo list */
4955                 int idx = 0;
4956                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4957
4958                 if (player->video_bo_list) {
4959                         /* if bo list did not created all, try it again. */
4960                         idx = g_list_length(player->video_bo_list);
4961                         LOGD("bo list exist(len: %d)", idx);
4962                 }
4963
4964                 for (; idx < player->ini.num_of_video_bo; idx++) {
4965                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4966                         if (!bo_info) {
4967                                 LOGE("Fail to alloc bo_info.");
4968                                 break;
4969                         }
4970                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4971                         if (!bo_info->bo) {
4972                                 LOGE("Fail to tbm_bo_alloc.");
4973                                 g_free(bo_info);
4974                                 break;
4975                         }
4976                         bo_info->using = FALSE;
4977                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4978                 }
4979
4980                 /* update video num buffers */
4981                 player->video_num_buffers = idx;
4982                 if (idx == player->ini.num_of_video_bo)
4983                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4984
4985                 if (idx == 0) {
4986                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4987                         return NULL;
4988                 }
4989
4990                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4991         }
4992
4993         while (TRUE) {
4994                 /* get bo from list*/
4995                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4996                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4997                         if (tmp && (tmp->using == FALSE)) {
4998                                 LOGD("found bo %p to use", tmp->bo);
4999                                 tmp->using = TRUE;
5000                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5001                                 return tbm_bo_ref(tmp->bo);
5002                         }
5003                 }
5004                 if (!ret) {
5005                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5006                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5007                         return NULL;
5008                 }
5009
5010                 if (player->ini.video_bo_timeout <= 0) {
5011                         MMPLAYER_VIDEO_BO_WAIT(player);
5012                 } else {
5013                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5014                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5015                 }
5016                 continue;
5017         }
5018 }
5019
5020 static void
5021 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5022 {
5023         mm_player_t* player = (mm_player_t*)data;
5024         MMPLAYER_FENTER();
5025         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5026
5027         /* send prerolled pkt */
5028         player->video_stream_prerolled = FALSE;
5029
5030         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5031
5032         /* not to send prerolled pkt again */
5033         player->video_stream_prerolled = TRUE;
5034 }
5035
5036 static void
5037 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5038 {
5039         mm_player_t* player = (mm_player_t*)data;
5040         GstCaps *caps = NULL;
5041         MMPlayerVideoStreamDataType *stream = NULL;
5042         MMVideoBuffer *video_buffer = NULL;
5043         GstMemory *dataBlock = NULL;
5044         GstMemory *metaBlock = NULL;
5045         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5046         GstStructure *structure = NULL;
5047         const gchar *string_format = NULL;
5048         unsigned int fourcc = 0;
5049
5050         MMPLAYER_FENTER();
5051         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5052
5053         if (player->video_stream_prerolled) {
5054                 player->video_stream_prerolled = FALSE;
5055                 LOGD("skip the prerolled pkt not to send it again");
5056                 return;
5057         }
5058
5059         caps = gst_pad_get_current_caps(pad);
5060         if (caps == NULL) {
5061                 LOGE("Caps is NULL.");
5062                 return;
5063         }
5064
5065         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5066
5067         /* clear stream data structure */
5068         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5069         if (!stream) {
5070                 LOGE("failed to alloc mem for video data");
5071                 return;
5072         }
5073
5074         structure = gst_caps_get_structure(caps, 0);
5075         gst_structure_get_int(structure, "width", &(stream->width));
5076         gst_structure_get_int(structure, "height", &(stream->height));
5077         string_format = gst_structure_get_string(structure, "format");
5078         if (string_format)
5079                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5080         stream->format = util_get_pixtype(fourcc);
5081         gst_caps_unref(caps);
5082         caps = NULL;
5083
5084         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5085
5086     /*
5087         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5088                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5089     */
5090
5091         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5092                 LOGE("Wrong condition!!");
5093                 goto ERROR;
5094         }
5095
5096         /* set size and timestamp */
5097         dataBlock = gst_buffer_peek_memory(buffer, 0);
5098         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5099         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5100
5101         /* check zero-copy */
5102         if (player->set_mode.video_zc &&
5103                 player->set_mode.media_packet_video_stream &&
5104                 gst_buffer_n_memory(buffer) > 1) {
5105                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5106                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5107                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5108         }
5109
5110         if (video_buffer) { /* hw codec */
5111                 /* set tbm bo */
5112                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5113                         int i = 0;
5114
5115                         /* copy pointer of tbm bo, stride, elevation */
5116                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5117                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5118                                 i++;
5119                         }
5120                 } else {
5121                         LOGE("Not support video buffer format");
5122                         goto ERROR;
5123                 }
5124                 memcpy(stream->stride, video_buffer->stride_width,
5125                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5126                 memcpy(stream->elevation, video_buffer->stride_height,
5127                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5128
5129                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5130                 stream->internal_buffer = gst_buffer_ref(buffer);
5131         } else { /* sw codec */
5132                 int i = 0;
5133                 int j = 0;
5134                 int k = 0;
5135                 int ret = TBM_SURFACE_ERROR_NONE;
5136                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5137                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5138                 int size = 0;
5139                 unsigned char *src = NULL;
5140                 unsigned char *dest = NULL;
5141                 tbm_bo_handle thandle;
5142                 tbm_surface_h surface;
5143                 tbm_surface_info_s info;
5144                 gboolean gst_ret;
5145
5146                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5147                 if (!gst_ret) {
5148                         LOGE("fail to gst_memory_map");
5149                         goto ERROR;
5150                 }
5151
5152
5153                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5154                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5155
5156                         ret = tbm_surface_get_info(surface, &info);
5157
5158                         if (ret != TBM_SURFACE_ERROR_NONE) {
5159                                 tbm_surface_destroy(surface);
5160                                 goto ERROR;
5161                         }
5162                         tbm_surface_destroy(surface);
5163
5164                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5165                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5166                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5167                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5168                         stream->stride[0] = info.planes[0].stride;
5169                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5170                         stream->stride[1] = info.planes[1].stride;
5171                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5172                         stream->stride[2] = info.planes[2].stride;
5173                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5174                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5175                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5176                         stream->stride[0] = stream->width * 4;
5177                         stream->elevation[0] = stream->height;
5178                         size = stream->stride[0] * stream->height;
5179                 } else {
5180                         LOGE("Not support format %d", stream->format);
5181                         goto ERROR;
5182                 }
5183
5184                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5185                 if (!stream->bo[0]) {
5186                         LOGE("Fail to tbm_bo_alloc!!");
5187                         goto ERROR;
5188                 }
5189
5190                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5191                 if (thandle.ptr && mapinfo.data) {
5192                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5193                                 for (i = 0; i < 3; i++) {
5194                                         src = mapinfo.data + src_offset[i];
5195                                         dest = thandle.ptr + info.planes[i].offset;
5196
5197                                         if (i > 0) k = 1;
5198                                         for (j = 0; j < stream->height>>k; j++) {
5199                                                 memcpy(dest, src, stream->width>>k);
5200                                                 src += src_stride[i];
5201                                                 dest += stream->stride[i];
5202                                         }
5203                                 }
5204                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5205                                 memcpy(thandle.ptr, mapinfo.data, size);
5206                         } else {
5207                                 LOGE("Not support format %d", stream->format);
5208                                 goto ERROR;
5209                         }
5210                 } else {
5211                         LOGE("data pointer is wrong. dest : %p, src : %p",
5212                                         thandle.ptr, mapinfo.data);
5213                         goto ERROR;
5214                 }
5215                 tbm_bo_unmap(stream->bo[0]);
5216         }
5217
5218         if (player->video_stream_cb) { /* This has been already checked at the entry */
5219                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5220                         LOGE("failed to send video stream data.");
5221                         goto ERROR;
5222                 }
5223         }
5224
5225         if (metaBlock)
5226                 gst_memory_unmap(metaBlock, &mapinfo);
5227         else
5228                 gst_memory_unmap(dataBlock, &mapinfo);
5229
5230         return;
5231
5232 ERROR:
5233         LOGE("release video stream resource.");
5234         if (metaBlock) {
5235                 int i = 0;
5236                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5237                         if (stream->bo[i])
5238                                 tbm_bo_unref(stream->bo[i]);
5239                 }
5240                 gst_memory_unmap(metaBlock, &mapinfo);
5241
5242                 /* unref gst buffer */
5243                 if (stream->internal_buffer)
5244                         gst_buffer_unref(stream->internal_buffer);
5245         } else if (dataBlock) {
5246                 if (stream->bo[0])
5247                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5248                 gst_memory_unmap(dataBlock, &mapinfo);
5249         }
5250
5251         g_free(stream);
5252         return;
5253 }
5254
5255 static int
5256 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5257 {
5258         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5259         GList* element_bucket = NULL;
5260
5261         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5262
5263         MMPLAYER_FENTER();
5264
5265         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5266                 LOGD("do not need to add video filters.");
5267                 return MM_ERROR_NONE;
5268         }
5269
5270         /* in case of sw codec except 360 playback,
5271          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5272         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5273         LOGD("using video converter: %s", video_csc);
5274
5275         /* set video rotator */
5276         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5277
5278         *bucket = element_bucket;
5279         MMPLAYER_FLEAVE();
5280         return MM_ERROR_NONE;
5281
5282 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5283         g_list_free(element_bucket);
5284
5285         *bucket = NULL;
5286         MMPLAYER_FLEAVE();
5287         return MM_ERROR_PLAYER_INTERNAL;
5288 }
5289
5290 /**
5291  * This function is to create video pipeline.
5292  *
5293  * @param       player          [in]    handle of player
5294  *              caps            [in]    src caps of decoder
5295  *              surface_type    [in]    surface type for video rendering
5296  *
5297  * @return      This function returns zero on success.
5298  * @remark
5299  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5300  */
5301 /**
5302   * VIDEO PIPELINE
5303   * - video overlay surface(arm/x86) : tizenwlsink
5304   */
5305 static int
5306 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5307 {
5308         GstPad *pad = NULL;
5309         MMHandleType attrs;
5310         GList*element_bucket = NULL;
5311         MMPlayerGstElement* first_element = NULL;
5312         MMPlayerGstElement* videobin = NULL;
5313         gchar *videosink_element = NULL;
5314
5315         MMPLAYER_FENTER();
5316
5317         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5318
5319         /* alloc handles */
5320         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5321         if (!videobin)
5322                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5323
5324         player->pipeline->videobin = videobin;
5325
5326         attrs = MMPLAYER_GET_ATTRS(player);
5327         if (!attrs) {
5328                 LOGE("cannot get content attribute");
5329                 return MM_ERROR_PLAYER_INTERNAL;
5330         }
5331
5332         /* create bin */
5333         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5334         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5335         if (!videobin[MMPLAYER_V_BIN].gst) {
5336                 LOGE("failed to create videobin");
5337                 goto ERROR;
5338         }
5339
5340         int enable_video_decoded_cb = 0;
5341         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5342
5343         if (player->is_360_feature_enabled && player->is_content_spherical) {
5344                 LOGD("video360 elem will be added.");
5345
5346                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5347                                 "video-360", TRUE, player);
5348
5349                 /* Set spatial media metadata and/or user settings to the element.
5350                  * */
5351                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352                                 "projection-type", player->video360_metadata.projection_type, NULL);
5353
5354                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5356
5357                 if (player->video360_metadata.full_pano_width_pixels &&
5358                                 player->video360_metadata.full_pano_height_pixels &&
5359                                 player->video360_metadata.cropped_area_image_width &&
5360                                 player->video360_metadata.cropped_area_image_height) {
5361                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5362                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5363                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5364                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5365                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5366                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5367                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5368                                         NULL);
5369                 }
5370
5371                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5372                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5373                                         "horizontal-fov", player->video360_horizontal_fov,
5374                                         "vertical-fov", player->video360_vertical_fov, NULL);
5375                 }
5376
5377                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5378                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5379                                         "zoom", 1.0f / player->video360_zoom, NULL);
5380                 }
5381
5382                 if (player->video360_yaw_radians <= M_PI &&
5383                                 player->video360_yaw_radians >= -M_PI &&
5384                                 player->video360_pitch_radians <= M_PI_2 &&
5385                                 player->video360_pitch_radians >= -M_PI_2) {
5386                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5387                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5388                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5389                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5390                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5391                                         "pose-yaw", player->video360_metadata.init_view_heading,
5392                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5393                 }
5394
5395                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5396                                 "passthrough", !player->is_video360_enabled, NULL);
5397         }
5398
5399         /* set video sink */
5400         switch (surface_type) {
5401         case MM_DISPLAY_SURFACE_OVERLAY:
5402                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5403                         goto ERROR;
5404                 if (strlen(player->ini.videosink_element_overlay) > 0)
5405                         videosink_element = player->ini.videosink_element_overlay;
5406                 else
5407                         goto ERROR;
5408                 break;
5409         case MM_DISPLAY_SURFACE_NULL:
5410                 if (strlen(player->ini.videosink_element_fake) > 0)
5411                         videosink_element = player->ini.videosink_element_fake;
5412                 else
5413                         goto ERROR;
5414                 break;
5415         case MM_DISPLAY_SURFACE_REMOTE:
5416                 if (strlen(player->ini.videosink_element_fake) > 0)
5417                         videosink_element = player->ini.videosink_element_fake;
5418                 else
5419                         goto ERROR;
5420                 break;
5421         default:
5422                 LOGE("unidentified surface type");
5423                 goto ERROR;
5424         }
5425         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5426
5427         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5428
5429         /* additional setting for sink plug-in */
5430         switch (surface_type) {
5431         case MM_DISPLAY_SURFACE_OVERLAY:
5432         {
5433                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5434                 if (!use_tbm) {
5435                         LOGD("selected videosink name: %s", videosink_element);
5436
5437                         /* support shard memory with S/W codec on HawkP */
5438                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5439                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5440                                         "use-tbm", use_tbm, NULL);
5441                         }
5442                 } else {
5443                         if (attrs) {
5444                                 int gapless = 0;
5445
5446                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5447
5448                                 if (gapless > 0) {
5449                                         LOGD("disable last-sample");
5450                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5451                                 }
5452                         }
5453                 }
5454                 if (player->set_mode.media_packet_video_stream) {
5455                         int enable = 0;
5456                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5457                         if (enable)
5458                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5459
5460                         MMPLAYER_SIGNAL_CONNECT(player,
5461                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5462                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5463                                                                         "handoff",
5464                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5465                                                                         (gpointer)player);
5466
5467                         MMPLAYER_SIGNAL_CONNECT(player,
5468                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5469                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5470                                                                         "preroll-handoff",
5471                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5472                                                                         (gpointer)player);
5473                 }
5474                 break;
5475         }
5476         case MM_DISPLAY_SURFACE_REMOTE:
5477         {
5478                 if (player->set_mode.media_packet_video_stream) {
5479                         LOGE("add data probe at videosink");
5480                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5481                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5482
5483                         MMPLAYER_SIGNAL_CONNECT(player,
5484                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5485                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5486                                                                         "handoff",
5487                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5488                                                                         (gpointer)player);
5489
5490                         MMPLAYER_SIGNAL_CONNECT(player,
5491                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5492                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5493                                                                         "preroll-handoff",
5494                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5495                                                                         (gpointer)player);
5496                         if (attrs) {
5497                                 int gapless = 0;
5498
5499                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5500
5501                                 if (gapless > 0) {
5502                                         LOGD("disable last-sample");
5503                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5504                                 }
5505                         }
5506                 }
5507                 break;
5508         }
5509         default:
5510                 break;
5511         }
5512
5513         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5514                 goto ERROR;
5515
5516         if (videobin[MMPLAYER_V_SINK].gst) {
5517                 GstPad *sink_pad = NULL;
5518                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5519                 if (sink_pad) {
5520                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5521                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5522                         gst_object_unref(GST_OBJECT(sink_pad));
5523                 } else
5524                         LOGW("failed to get sink pad from videosink\n");
5525         }
5526
5527         /* store it as it's sink element */
5528         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5529
5530         /* adding created elements to bin */
5531         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5532                 LOGE("failed to add elements\n");
5533                 goto ERROR;
5534         }
5535
5536         /* Linking elements in the bucket by added order */
5537         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5538                 LOGE("failed to link elements\n");
5539                 goto ERROR;
5540         }
5541
5542         /* get first element's sinkpad for creating ghostpad */
5543         if (element_bucket)
5544                 first_element = (MMPlayerGstElement *)element_bucket->data;
5545         if (!first_element) {
5546                 LOGE("failed to get first element from bucket\n");
5547                 goto ERROR;
5548         }
5549
5550         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5551         if (!pad) {
5552                 LOGE("failed to get pad from first element\n");
5553                 goto ERROR;
5554         }
5555
5556         /* create ghostpad */
5557         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5558         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5559                 LOGE("failed to add ghostpad to videobin\n");
5560                 goto ERROR;
5561         }
5562         gst_object_unref(pad);
5563
5564         /* done. free allocated variables */
5565         if (element_bucket)
5566                 g_list_free(element_bucket);
5567
5568         MMPLAYER_FLEAVE();
5569
5570         return MM_ERROR_NONE;
5571
5572 ERROR:
5573         LOGE("ERROR : releasing videobin\n");
5574
5575         g_list_free(element_bucket);
5576
5577         if (pad)
5578                 gst_object_unref(GST_OBJECT(pad));
5579
5580         /* release videobin with it's childs */
5581         if (videobin[MMPLAYER_V_BIN].gst)
5582                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5583
5584
5585         MMPLAYER_FREEIF(videobin);
5586
5587         player->pipeline->videobin = NULL;
5588
5589         return MM_ERROR_PLAYER_INTERNAL;
5590 }
5591
5592 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5593 {
5594         GList *element_bucket = NULL;
5595         MMPlayerGstElement *textbin = player->pipeline->textbin;
5596
5597         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5598         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5599         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5600                                                         "signal-handoffs", FALSE,
5601                                                         NULL);
5602
5603         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5604         MMPLAYER_SIGNAL_CONNECT(player,
5605                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5606                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5607                                                         "handoff",
5608                                                         G_CALLBACK(__mmplayer_update_subtitle),
5609                                                         (gpointer)player);
5610
5611         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5612         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5613
5614         if (!player->play_subtitle) {
5615                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5616                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5617         }
5618
5619         /* adding created elements to bin */
5620         LOGD("adding created elements to bin\n");
5621         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5622                 LOGE("failed to add elements\n");
5623                 goto ERROR;
5624         }
5625
5626         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5627         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5628         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5629
5630         /* linking elements in the bucket by added order. */
5631         LOGD("Linking elements in the bucket by added order.\n");
5632         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5633                 LOGE("failed to link elements\n");
5634                 goto ERROR;
5635         }
5636
5637         /* done. free allocated variables */
5638         g_list_free(element_bucket);
5639
5640         if (textbin[MMPLAYER_T_QUEUE].gst) {
5641                 GstPad *pad = NULL;
5642                 GstPad *ghostpad = NULL;
5643
5644                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5645                 if (!pad) {
5646                         LOGE("failed to get sink pad of text queue");
5647                         goto ERROR;
5648                 }
5649
5650                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5651                 gst_object_unref(pad);
5652
5653                 if (!ghostpad) {
5654                         LOGE("failed to create ghostpad of textbin\n");
5655                         goto ERROR;
5656                 }
5657
5658                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5659                         LOGE("failed to add ghostpad to textbin\n");
5660                         gst_object_unref(ghostpad);
5661                         goto ERROR;
5662                 }
5663         }
5664
5665         return MM_ERROR_NONE;
5666
5667 ERROR:
5668         g_list_free(element_bucket);
5669
5670         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5671                 LOGE("remove textbin sink from sink list");
5672                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5673         }
5674
5675         /* release element at __mmplayer_gst_create_text_sink_bin */
5676         return MM_ERROR_PLAYER_INTERNAL;
5677 }
5678
5679 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5680 {
5681         MMPlayerGstElement *textbin = NULL;
5682         GList *element_bucket = NULL;
5683         int surface_type = 0;
5684         gint i = 0;
5685
5686         MMPLAYER_FENTER();
5687
5688         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5689
5690         /* alloc handles */
5691         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5692         if (!textbin) {
5693                 LOGE("failed to allocate memory for textbin\n");
5694                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5695         }
5696
5697         /* create bin */
5698         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5699         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5700         if (!textbin[MMPLAYER_T_BIN].gst) {
5701                 LOGE("failed to create textbin\n");
5702                 goto ERROR;
5703         }
5704
5705         /* take it */
5706         player->pipeline->textbin = textbin;
5707
5708         /* fakesink */
5709         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5710         LOGD("surface type for subtitle : %d", surface_type);
5711         switch (surface_type) {
5712         case MM_DISPLAY_SURFACE_OVERLAY:
5713         case MM_DISPLAY_SURFACE_NULL:
5714         case MM_DISPLAY_SURFACE_REMOTE:
5715                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5716                         LOGE("failed to make plain text elements\n");
5717                         goto ERROR;
5718                 }
5719                 break;
5720         default:
5721                 goto ERROR;
5722                 break;
5723         }
5724
5725         MMPLAYER_FLEAVE();
5726
5727         return MM_ERROR_NONE;
5728
5729 ERROR:
5730
5731         LOGD("ERROR : releasing textbin\n");
5732
5733         g_list_free(element_bucket);
5734
5735         /* release signal */
5736         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5737
5738         /* release element which are not added to bin */
5739         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5740                 /* NOTE : skip bin */
5741                 if (textbin[i].gst) {
5742                         GstObject* parent = NULL;
5743                         parent = gst_element_get_parent(textbin[i].gst);
5744
5745                         if (!parent) {
5746                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5747                                 textbin[i].gst = NULL;
5748                         } else {
5749                                 gst_object_unref(GST_OBJECT(parent));
5750                         }
5751                 }
5752         }
5753
5754         /* release textbin with it's childs */
5755         if (textbin[MMPLAYER_T_BIN].gst)
5756                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5757
5758         MMPLAYER_FREEIF(player->pipeline->textbin);
5759         player->pipeline->textbin = NULL;
5760
5761         MMPLAYER_FLEAVE();
5762         return MM_ERROR_PLAYER_INTERNAL;
5763 }
5764
5765
5766 static int
5767 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5768 {
5769         MMPlayerGstElement* mainbin = NULL;
5770         MMPlayerGstElement* textbin = NULL;
5771         MMHandleType attrs = 0;
5772         GstElement *subsrc = NULL;
5773         GstElement *subparse = NULL;
5774         gchar *subtitle_uri = NULL;
5775         const gchar *charset = NULL;
5776         GstPad *pad = NULL;
5777
5778         MMPLAYER_FENTER();
5779
5780         /* get mainbin */
5781         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5782                                                                 player->pipeline &&
5783                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5784
5785         mainbin = player->pipeline->mainbin;
5786
5787         attrs = MMPLAYER_GET_ATTRS(player);
5788         if (!attrs) {
5789                 LOGE("cannot get content attribute\n");
5790                 return MM_ERROR_PLAYER_INTERNAL;
5791         }
5792
5793         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5794         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5795                 LOGE("subtitle uri is not proper filepath.\n");
5796                 return MM_ERROR_PLAYER_INVALID_URI;
5797         }
5798
5799         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5800                 LOGE("failed to get storage info of subtitle path");
5801                 return MM_ERROR_PLAYER_INVALID_URI;
5802         }
5803
5804         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5805
5806         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5807         player->subtitle_language_list = NULL;
5808         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5809
5810         /* create the subtitle source */
5811         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5812         if (!subsrc) {
5813                 LOGE("failed to create filesrc element\n");
5814                 goto ERROR;
5815         }
5816         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5817
5818         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5819         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5820
5821         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5822                 LOGW("failed to add queue\n");
5823                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5824                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5825                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5826                 goto ERROR;
5827         }
5828
5829         /* subparse */
5830         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5831         if (!subparse) {
5832                 LOGE("failed to create subparse element\n");
5833                 goto ERROR;
5834         }
5835
5836         charset = util_get_charset(subtitle_uri);
5837         if (charset) {
5838                 LOGD("detected charset is %s\n", charset);
5839                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5840         }
5841
5842         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5843         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5844
5845         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5846                 LOGW("failed to add subparse\n");
5847                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5848                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5849                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5850                 goto ERROR;
5851         }
5852
5853         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5854                 LOGW("failed to link subsrc and subparse\n");
5855                 goto ERROR;
5856         }
5857
5858         player->play_subtitle = TRUE;
5859         player->adjust_subtitle_pos = 0;
5860
5861         LOGD("play subtitle using subtitle file\n");
5862
5863         if (player->pipeline->textbin == NULL) {
5864                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5865                         LOGE("failed to create text sink bin. continuing without text\n");
5866                         goto ERROR;
5867                 }
5868
5869                 textbin = player->pipeline->textbin;
5870
5871                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5872                         LOGW("failed to add textbin\n");
5873
5874                         /* release signal */
5875                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5876
5877                         /* release textbin with it's childs */
5878                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5879                         MMPLAYER_FREEIF(player->pipeline->textbin);
5880                         player->pipeline->textbin = textbin = NULL;
5881                         goto ERROR;
5882                 }
5883
5884                 LOGD("link text input selector and textbin ghost pad");
5885
5886                 player->textsink_linked = 1;
5887                 player->external_text_idx = 0;
5888                 LOGI("player->textsink_linked set to 1\n");
5889         } else {
5890                 textbin = player->pipeline->textbin;
5891                 LOGD("text bin has been created. reuse it.");
5892                 player->external_text_idx = 1;
5893         }
5894
5895         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5896                 LOGW("failed to link subparse and textbin\n");
5897                 goto ERROR;
5898         }
5899
5900         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5901         if (!pad) {
5902                 LOGE("failed to get sink pad from textsink to probe data");
5903                 goto ERROR;
5904         }
5905
5906         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5907                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5908
5909         gst_object_unref(pad);
5910         pad = NULL;
5911
5912         /* create dot. for debugging */
5913         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5914         MMPLAYER_FLEAVE();
5915
5916         return MM_ERROR_NONE;
5917
5918 ERROR:
5919         /* release text pipeline resource */
5920         player->textsink_linked = 0;
5921
5922         /* release signal */
5923         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5924
5925         if (player->pipeline->textbin) {
5926                 LOGE("remove textbin");
5927
5928                 /* release textbin with it's childs */
5929                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5930                 MMPLAYER_FREEIF(player->pipeline->textbin);
5931                 player->pipeline->textbin = NULL;
5932
5933         }
5934
5935         /* release subtitle elem */
5936         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5937         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5938
5939         return MM_ERROR_PLAYER_INTERNAL;
5940 }
5941
5942 gboolean
5943 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5944 {
5945         mm_player_t* player = (mm_player_t*) data;
5946         MMMessageParamType msg = {0, };
5947         GstClockTime duration = 0;
5948         gpointer text = NULL;
5949         guint text_size = 0;
5950         gboolean ret = TRUE;
5951         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5952
5953         MMPLAYER_FENTER();
5954
5955         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5956         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5957
5958         if (player->is_subtitle_force_drop) {
5959                 LOGW("subtitle is dropped forcedly.");
5960                 return ret;
5961         }
5962
5963         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5964         text = mapinfo.data;
5965         text_size = mapinfo.size;
5966         duration = GST_BUFFER_DURATION(buffer);
5967
5968         if (player->set_mode.subtitle_off) {
5969                 LOGD("subtitle is OFF.\n");
5970                 return TRUE;
5971         }
5972
5973         if (!text || (text_size == 0)) {
5974                 LOGD("There is no subtitle to be displayed.\n");
5975                 return TRUE;
5976         }
5977
5978         msg.data = (void *) text;
5979         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5980
5981         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5982
5983         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5984         gst_buffer_unmap(buffer, &mapinfo);
5985
5986         MMPLAYER_FLEAVE();
5987
5988         return ret;
5989 }
5990
5991 static GstPadProbeReturn
5992 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5993 {
5994         mm_player_t *player = (mm_player_t *) u_data;
5995         GstClockTime cur_timestamp = 0;
5996         gint64 adjusted_timestamp = 0;
5997         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5998
5999         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6000
6001         if (player->set_mode.subtitle_off) {
6002                 LOGD("subtitle is OFF.\n");
6003                 return TRUE;
6004         }
6005
6006         if (player->adjust_subtitle_pos == 0) {
6007                 LOGD("nothing to do");
6008                 return TRUE;
6009         }
6010
6011         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6012         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6013
6014         if (adjusted_timestamp < 0) {
6015                 LOGD("adjusted_timestamp under zero");
6016                 MMPLAYER_FLEAVE();
6017                 return FALSE;
6018         }
6019
6020         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6021         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6022                                 GST_TIME_ARGS(cur_timestamp),
6023                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6024
6025         return GST_PAD_PROBE_OK;
6026 }
6027 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6028 {
6029         MMPLAYER_FENTER();
6030
6031         /* check player and subtitlebin are created */
6032         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6033         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6034
6035         if (position == 0) {
6036                 LOGD("nothing to do\n");
6037                 MMPLAYER_FLEAVE();
6038                 return MM_ERROR_NONE;
6039         }
6040
6041         switch (format) {
6042         case MM_PLAYER_POS_FORMAT_TIME:
6043                 {
6044                         /* check current postion */
6045                         player->adjust_subtitle_pos = position;
6046
6047                         LOGD("save adjust_subtitle_pos in player") ;
6048                 }
6049                 break;
6050
6051         default:
6052                 {
6053                         LOGW("invalid format.\n");
6054                         MMPLAYER_FLEAVE();
6055                         return MM_ERROR_INVALID_ARGUMENT;
6056                 }
6057         }
6058
6059         MMPLAYER_FLEAVE();
6060
6061         return MM_ERROR_NONE;
6062 }
6063
6064 static void
6065 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6066 {
6067         GstElement *appsrc = element;
6068         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6069         GstBuffer *buffer = NULL;
6070         GstFlowReturn ret = GST_FLOW_OK;
6071         gint len = size;
6072
6073         MMPLAYER_RETURN_IF_FAIL(element);
6074         MMPLAYER_RETURN_IF_FAIL(buf);
6075
6076         buffer = gst_buffer_new();
6077
6078         if (buf->offset >= buf->len) {
6079                 LOGD("call eos appsrc\n");
6080                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6081                 return;
6082         }
6083
6084         if (buf->len - buf->offset < size)
6085                 len = buf->len - buf->offset;
6086
6087         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6088         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6089         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6090
6091         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6092         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6093
6094         buf->offset += len;
6095 }
6096
6097 static gboolean
6098 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6099 {
6100         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6101
6102         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6103
6104         buf->offset  = (int)size;
6105
6106         return TRUE;
6107 }
6108
6109 static GstBusSyncReply
6110 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6111 {
6112         mm_player_t *player = (mm_player_t *)data;
6113         GstBusSyncReply reply = GST_BUS_DROP;
6114
6115         if (!(player->pipeline && player->pipeline->mainbin)) {
6116                 LOGE("player pipeline handle is null");
6117                 return GST_BUS_PASS;
6118         }
6119
6120         if (!__mmplayer_check_useful_message(player, message)) {
6121                 gst_message_unref(message);
6122                 return GST_BUS_DROP;
6123         }
6124
6125         switch (GST_MESSAGE_TYPE(message)) {
6126         case GST_MESSAGE_STATE_CHANGED:
6127                 /* post directly for fast launch */
6128                 if (player->sync_handler) {
6129                         __mmplayer_gst_callback(message, player);
6130                         reply = GST_BUS_DROP;
6131                 } else
6132                         reply = GST_BUS_PASS;
6133                 break;
6134         case GST_MESSAGE_TAG:
6135                 __mmplayer_gst_extract_tag_from_msg(player, message);
6136
6137                 #if 0 // debug
6138                 {
6139                         GstTagList *tags = NULL;
6140
6141                         gst_message_parse_tag(message, &tags);
6142                         if (tags) {
6143                                 LOGE("TAGS received from element \"%s\".\n",
6144                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6145
6146                                 gst_tag_list_foreach(tags, print_tag, NULL);
6147                                 gst_tag_list_free(tags);
6148                                 tags = NULL;
6149                         }
6150                         break;
6151                 }
6152                 #endif
6153                 break;
6154
6155         case GST_MESSAGE_DURATION_CHANGED:
6156                 __mmplayer_gst_handle_duration(player, message);
6157                 break;
6158         case GST_MESSAGE_ASYNC_DONE:
6159                 /* NOTE:Don't call gst_callback directly
6160                  * because previous frame can be showed even though this message is received for seek.
6161                  */
6162         default:
6163                 reply = GST_BUS_PASS;
6164                 break;
6165         }
6166
6167         if (reply == GST_BUS_DROP)
6168                 gst_message_unref(message);
6169
6170         return reply;
6171 }
6172
6173 static gboolean
6174 __mmplayer_gst_create_decoder(mm_player_t *player,
6175                                                                 MMPlayerTrackType track,
6176                                                                 GstPad* srcpad,
6177                                                                 enum MainElementID elemId,
6178                                                                 const gchar* name)
6179 {
6180         gboolean ret = TRUE;
6181         GstPad *sinkpad = NULL;
6182
6183         MMPLAYER_FENTER();
6184
6185         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6186                                                 player->pipeline &&
6187                                                 player->pipeline->mainbin, FALSE);
6188         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6189         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6190         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6191
6192         GstElement *decodebin = NULL;
6193         GstCaps *dec_caps = NULL;
6194
6195         /* create decodebin */
6196         decodebin = gst_element_factory_make("decodebin", name);
6197
6198         if (!decodebin) {
6199                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6200                 ret = FALSE;
6201                 goto ERROR;
6202         }
6203
6204         /* raw pad handling signal */
6205         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6206                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6207
6208         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6209         before looking for any elements that can handle that stream.*/
6210         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6211                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6212
6213         /* This signal is emitted when a element is added to the bin.*/
6214         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6215                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6216
6217         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6218                 LOGE("failed to add new decodebin\n");
6219                 ret = FALSE;
6220                 goto ERROR;
6221         }
6222
6223         dec_caps = gst_pad_query_caps(srcpad, NULL);
6224         if (dec_caps) {
6225                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6226                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6227                 gst_caps_unref(dec_caps);
6228         }
6229
6230         player->pipeline->mainbin[elemId].id = elemId;
6231         player->pipeline->mainbin[elemId].gst = decodebin;
6232
6233         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6234
6235         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6236                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6237                 gst_object_unref(GST_OBJECT(decodebin));
6238         }
6239
6240         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6241                 LOGE("failed to sync second level decodebin state with parent\n");
6242
6243         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6244
6245 ERROR:
6246         if (sinkpad) {
6247                 gst_object_unref(GST_OBJECT(sinkpad));
6248                 sinkpad = NULL;
6249         }
6250         MMPLAYER_FLEAVE();
6251
6252         return ret;
6253 }
6254
6255 /**
6256  * This function is to create  audio or video pipeline for playing.
6257  *
6258  * @param       player          [in]    handle of player
6259  *
6260  * @return      This function returns zero on success.
6261  * @remark
6262  * @see
6263  */
6264 static int
6265 __mmplayer_gst_create_pipeline(mm_player_t* player)
6266 {
6267         GstBus  *bus = NULL;
6268         MMPlayerGstElement *mainbin = NULL;
6269         MMHandleType attrs = 0;
6270         GstElement* element = NULL;
6271         GstElement* elem_src_audio = NULL;
6272         GstElement* elem_src_subtitle = NULL;
6273         GstElement* es_video_queue = NULL;
6274         GstElement* es_audio_queue = NULL;
6275         GstElement* es_subtitle_queue = NULL;
6276         GList* element_bucket = NULL;
6277         gboolean need_state_holder = TRUE;
6278         gint i = 0;
6279 #ifdef SW_CODEC_ONLY
6280         int surface_type = 0;
6281 #endif
6282         MMPLAYER_FENTER();
6283
6284         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6285
6286         /* get profile attribute */
6287         attrs = MMPLAYER_GET_ATTRS(player);
6288         if (!attrs) {
6289                 LOGE("cannot get content attribute\n");
6290                 goto INIT_ERROR;
6291         }
6292
6293         /* create pipeline handles */
6294         if (player->pipeline) {
6295                 LOGW("pipeline should be released before create new one\n");
6296                 goto INIT_ERROR;
6297         }
6298
6299         player->video360_metadata.is_spherical = -1;
6300         player->is_openal_plugin_used = FALSE;
6301
6302         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6303         if (player->pipeline == NULL)
6304                 goto INIT_ERROR;
6305
6306         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6307
6308         /* create mainbin */
6309         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6310         if (mainbin == NULL)
6311                 goto INIT_ERROR;
6312
6313         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6314
6315         /* create pipeline */
6316         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6317         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6318         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6319                 LOGE("failed to create pipeline\n");
6320                 goto INIT_ERROR;
6321         }
6322         player->demux_pad_index = 0;
6323         player->subtitle_language_list = NULL;
6324
6325         player->is_subtitle_force_drop = FALSE;
6326         player->last_multiwin_status = FALSE;
6327
6328         _mmplayer_track_initialize(player);
6329         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6330
6331         /* create source element */
6332         switch (player->profile.uri_type) {
6333         /* rtsp streamming */
6334         case MM_PLAYER_URI_TYPE_URL_RTSP:
6335                 {
6336                         gchar *user_agent;
6337
6338                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6339
6340                         if (!element) {
6341                                 LOGE("failed to create streaming source element\n");
6342                                 break;
6343                         }
6344
6345                         /* make it zero */
6346                         user_agent = NULL;
6347
6348                         /* get attribute */
6349                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6350
6351                         SECURE_LOGD("user_agent : %s\n", user_agent);
6352
6353                         /* setting property to streaming source */
6354                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6355                         if (user_agent)
6356                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6357
6358                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6359                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6360                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6361                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6362                 }
6363                 break;
6364
6365         /* http streaming*/
6366         case MM_PLAYER_URI_TYPE_URL_HTTP:
6367                 {
6368                         gchar *user_agent, *cookies, **cookie_list;
6369                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6370                         user_agent = cookies = NULL;
6371                         cookie_list = NULL;
6372                         gint mode = MM_PLAYER_PD_MODE_NONE;
6373
6374                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6375
6376                         player->pd_mode = mode;
6377
6378                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6379
6380                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6381                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6382                                 if (!element) {
6383                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6384                                         break;
6385                                 }
6386                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6387
6388                                 /* get attribute */
6389                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6390                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6391
6392                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6393                                         LOGD("get timeout from ini\n");
6394                                         http_timeout = player->ini.http_timeout;
6395                                 }
6396
6397                                 /* get attribute */
6398                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6399                                 SECURE_LOGD("cookies : %s\n", cookies);
6400                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6401                                 LOGD("timeout : %d\n",  http_timeout);
6402
6403                                 /* setting property to streaming source */
6404                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6405                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6406                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6407
6408                                 /* parsing cookies */
6409                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6410                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6411                                         g_strfreev(cookie_list);
6412                                 }
6413                                 if (user_agent)
6414                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6415
6416                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6417                                         LOGW("it's dash. and it's still experimental feature.");
6418                         } else {
6419                                 // progressive download
6420                                 gchar* location = NULL;
6421
6422                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6423                                         gchar *path = NULL;
6424
6425                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6426
6427                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6428
6429                                         LOGD("PD Location : %s\n", path);
6430
6431                                         if (path) {
6432                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6433                                                         LOGE("failed to get storage info");
6434                                                         break;
6435                                                 }
6436                                                 player->pd_file_save_path = g_strdup(path);
6437                                         } else {
6438                                                 LOGE("can't find pd location so, it should be set \n");
6439                                                 break;
6440                                         }
6441                                 }
6442
6443                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6444                                 if (!element) {
6445                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6446                                         break;
6447                                 }
6448
6449                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6450                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6451                                 else
6452                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6453                                 g_object_get(element, "location", &location, NULL);
6454                                 LOGD("PD_LOCATION [%s].\n", location);
6455                                 if (location)
6456                                         g_free(location);
6457                         }
6458                 }
6459                 break;
6460
6461         /* file source */
6462         case MM_PLAYER_URI_TYPE_FILE:
6463                 {
6464                         LOGD("using filesrc for 'file://' handler.\n");
6465                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6466                                 LOGE("failed to get storage info");
6467                                 break;
6468                         }
6469
6470                         element = gst_element_factory_make("filesrc", "source");
6471                         if (!element) {
6472                                 LOGE("failed to create filesrc\n");
6473                                 break;
6474                         }
6475
6476                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6477                 }
6478                 break;
6479
6480         case MM_PLAYER_URI_TYPE_SS:
6481                 {
6482                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6483                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6484                         if (!element) {
6485                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6486                                 break;
6487                         }
6488
6489                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6490                                 LOGD("get timeout from ini\n");
6491                                 http_timeout = player->ini.http_timeout;
6492                         }
6493
6494                         /* setting property to streaming source */
6495                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6496                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6497                 }
6498                 break;
6499         case MM_PLAYER_URI_TYPE_MS_BUFF:
6500                 {
6501                         LOGD("MS buff src is selected\n");
6502
6503                         if (player->v_stream_caps) {
6504                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6505                                 if (!element) {
6506                                         LOGF("failed to create video app source element[appsrc].\n");
6507                                         break;
6508                                 }
6509
6510                                 if (player->a_stream_caps) {
6511                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6512                                         if (!elem_src_audio) {
6513                                                 LOGF("failed to create audio app source element[appsrc].\n");
6514                                                 break;
6515                                         }
6516                                 }
6517                         } else if (player->a_stream_caps) {
6518                                 /* no video, only audio pipeline*/
6519                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6520                                 if (!element) {
6521                                         LOGF("failed to create audio app source element[appsrc].\n");
6522                                         break;
6523                                 }
6524                         }
6525
6526                         if (player->s_stream_caps) {
6527                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6528                                 if (!elem_src_subtitle) {
6529                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6530                                         break;
6531                                 }
6532                         }
6533
6534                         LOGD("setting app sources properties.\n");
6535                         LOGD("location : %s\n", player->profile.uri);
6536
6537                         if (player->v_stream_caps && element) {
6538                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6539                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6540                                                                                                 "caps", player->v_stream_caps, NULL);
6541
6542                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6544                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6545                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6546
6547                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6548                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6549                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6550                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6551
6552                                 if (player->a_stream_caps && elem_src_audio) {
6553                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6554                                                                                                                         "caps", player->a_stream_caps, NULL);
6555
6556                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6559                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6560
6561                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6562                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6563                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6564                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6565                                 }
6566                         } else if (player->a_stream_caps && element) {
6567                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6568                                                                                                 "caps", player->a_stream_caps, NULL);
6569
6570                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6572                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6573                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6574
6575                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6576                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6577                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6578                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6579                         }
6580
6581                         if (player->s_stream_caps && elem_src_subtitle) {
6582                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6583                                                                                                                  "caps", player->s_stream_caps, NULL);
6584
6585                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6587                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6588                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6589
6590                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6591
6592                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6593                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6594                         }
6595
6596                         if (player->v_stream_caps && element) {
6597                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6599                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6600                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6601
6602                                 if (player->a_stream_caps && elem_src_audio) {
6603                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6605                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6606                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6607                                 }
6608                         } else if (player->a_stream_caps && element) {
6609                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6611                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6612                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6613                         }
6614
6615                         if (player->s_stream_caps && elem_src_subtitle)
6616                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6617                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6618
6619                         need_state_holder = FALSE;
6620
6621                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6622                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6623                                 LOGE("failed to commit\n");
6624                 }
6625                 break;
6626         /* appsrc */
6627         case MM_PLAYER_URI_TYPE_MEM:
6628                 {
6629                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6630
6631                         LOGD("mem src is selected\n");
6632
6633                         element = gst_element_factory_make("appsrc", "mem-source");
6634                         if (!element) {
6635                                 LOGE("failed to create appsrc element\n");
6636                                 break;
6637                         }
6638
6639                         g_object_set(element, "stream-type", stream_type, NULL);
6640                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6641                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6642
6643                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6644                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6645                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6646                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6647                 }
6648                 break;
6649         case MM_PLAYER_URI_TYPE_URL:
6650                 break;
6651
6652         case MM_PLAYER_URI_TYPE_TEMP:
6653                 break;
6654
6655         case MM_PLAYER_URI_TYPE_NONE:
6656         default:
6657                 break;
6658         }
6659
6660         /* check source element is OK */
6661         if (!element) {
6662                 LOGE("no source element was created.\n");
6663                 goto INIT_ERROR;
6664         }
6665
6666         /* take source element */
6667         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6668         mainbin[MMPLAYER_M_SRC].gst = element;
6669         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6670
6671         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6672                 player->streamer = __mm_player_streaming_create();
6673                 __mm_player_streaming_initialize(player->streamer);
6674         }
6675
6676         if (MMPLAYER_IS_HTTP_PD(player)) {
6677                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6678
6679                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6680                 element = gst_element_factory_make("queue2", "queue2");
6681                 if (!element) {
6682                         LOGE("failed to create http streaming buffer element\n");
6683                         goto INIT_ERROR;
6684                 }
6685
6686                 /* take it */
6687                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6688                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6689                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6690
6691                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6692
6693                 player->streamer->is_pd_mode = TRUE;
6694
6695                 __mm_player_streaming_set_queue2(player->streamer,
6696                                 element,
6697                                 TRUE,
6698                                 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6699                                 pre_buffering_time,
6700                                 1.0,
6701                                 player->ini.http_buffering_limit,
6702                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6703                                 NULL,
6704                                 0);
6705         }
6706         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6707                 if (player->v_stream_caps) {
6708                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6709                         if (!es_video_queue) {
6710                                 LOGE("create es_video_queue for es player failed\n");
6711                                 goto INIT_ERROR;
6712                         }
6713                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6714                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6716                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6717
6718                         /* Adding audio appsrc to bucket */
6719                         if (player->a_stream_caps && elem_src_audio) {
6720                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6721                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6722                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6723
6724                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6725                                 if (!es_audio_queue) {
6726                                         LOGE("create es_audio_queue for es player failed\n");
6727                                         goto INIT_ERROR;
6728                                 }
6729                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6730
6731                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6732                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6733                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6734                         }
6735                 } else if (player->a_stream_caps) {
6736                         /* Only audio stream, no video */
6737                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6738                         if (!es_audio_queue) {
6739                                 LOGE("create es_audio_queue for es player failed\n");
6740                                 goto INIT_ERROR;
6741                         }
6742                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6743                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6744                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6745                 }
6746
6747                 if (player->s_stream_caps && elem_src_subtitle) {
6748                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6749                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6750                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6751
6752                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6753                         if (!es_subtitle_queue) {
6754                                 LOGE("create es_subtitle_queue for es player failed\n");
6755                                 goto INIT_ERROR;
6756                         }
6757                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6758                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6759                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6760                 }
6761         }
6762
6763         /* create autoplugging element if src element is not a rtsp src */
6764         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6765                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6766                 element = NULL;
6767                 enum MainElementID elemId = MMPLAYER_M_NUM;
6768
6769                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6770                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6771                         elemId = MMPLAYER_M_AUTOPLUG;
6772                         element = __mmplayer_create_decodebin(player);
6773                         if (element) {
6774                                 /* default size of mq in decodebin is 2M
6775                                  * but it can cause blocking issue during seeking depends on content. */
6776                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6777                         }
6778                         need_state_holder = FALSE;
6779                 } else {
6780                         elemId = MMPLAYER_M_TYPEFIND;
6781                         element = gst_element_factory_make("typefind", "typefinder");
6782                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6783                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6784                 }
6785
6786                 /* check autoplug element is OK */
6787                 if (!element) {
6788                         LOGE("can not create element(%d)\n", elemId);
6789                         goto INIT_ERROR;
6790                 }
6791
6792                 mainbin[elemId].id = elemId;
6793                 mainbin[elemId].gst = element;
6794
6795                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6796         }
6797
6798         /* add elements to pipeline */
6799         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6800                 LOGE("Failed to add elements to pipeline\n");
6801                 goto INIT_ERROR;
6802         }
6803
6804
6805         /* linking elements in the bucket by added order. */
6806         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6807                 LOGE("Failed to link some elements\n");
6808                 goto INIT_ERROR;
6809         }
6810
6811
6812         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6813         if (need_state_holder) {
6814                 /* create */
6815                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6816                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6817
6818                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6819                         LOGE("fakesink element could not be created\n");
6820                         goto INIT_ERROR;
6821                 }
6822                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6823
6824                 /* take ownership of fakesink. we are reusing it */
6825                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6826
6827                 /* add */
6828                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6829                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6830                         LOGE("failed to add fakesink to bin\n");
6831                         goto INIT_ERROR;
6832                 }
6833         }
6834
6835         /* now we have completed mainbin. take it */
6836         player->pipeline->mainbin = mainbin;
6837
6838         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6839                 GstPad *srcpad = NULL;
6840
6841                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6842                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6843                         if (srcpad) {
6844                                 __mmplayer_gst_create_decoder(player,
6845                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6846                                                                                                 srcpad,
6847                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6848                                                                                                 "video_decodebin");
6849
6850                                 gst_object_unref(GST_OBJECT(srcpad));
6851                                 srcpad = NULL;
6852                         }
6853                 }
6854
6855                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6856                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6857                         if (srcpad) {
6858                                 __mmplayer_gst_create_decoder(player,
6859                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6860                                                                                                 srcpad,
6861                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6862                                                                                                 "audio_decodebin");
6863
6864                                 gst_object_unref(GST_OBJECT(srcpad));
6865                                 srcpad = NULL;
6866                         } // else error
6867                 } //  else error
6868
6869                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6870                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6871         }
6872
6873         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6874         if (__mmplayer_check_subtitle(player)) {
6875                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6876                         LOGE("fail to create text pipeline");
6877         }
6878
6879         /* connect bus callback */
6880         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6881         if (!bus) {
6882                 LOGE("cannot get bus from pipeline.\n");
6883                 goto INIT_ERROR;
6884         }
6885
6886         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6887
6888         player->context.thread_default = g_main_context_get_thread_default();
6889
6890         if (player->context.thread_default == NULL) {
6891                 player->context.thread_default = g_main_context_default();
6892                 LOGD("thread-default context is the global default context");
6893         }
6894         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6895
6896         /* set sync handler to get tag synchronously */
6897         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6898
6899         /* finished */
6900         gst_object_unref(GST_OBJECT(bus));
6901         g_list_free(element_bucket);
6902
6903         /* create gst bus_msb_cb thread */
6904         g_mutex_init(&player->bus_msg_thread_mutex);
6905         g_cond_init(&player->bus_msg_thread_cond);
6906         player->bus_msg_thread_exit = FALSE;
6907         player->bus_msg_thread =
6908                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6909         if (!player->bus_msg_thread) {
6910                 LOGE("failed to create gst BUS msg thread");
6911                 g_mutex_clear(&player->bus_msg_thread_mutex);
6912                 g_cond_clear(&player->bus_msg_thread_cond);
6913                 goto INIT_ERROR;
6914         }
6915
6916         MMPLAYER_FLEAVE();
6917
6918         return MM_ERROR_NONE;
6919
6920 INIT_ERROR:
6921         __mmplayer_gst_destroy_pipeline(player);
6922         g_list_free(element_bucket);
6923
6924         if (mainbin) {
6925                 /* release element which are not added to bin */
6926                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6927                         /* NOTE : skip pipeline */
6928                         if (mainbin[i].gst) {
6929                                 GstObject* parent = NULL;
6930                                 parent = gst_element_get_parent(mainbin[i].gst);
6931
6932                                 if (!parent) {
6933                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6934                                         mainbin[i].gst = NULL;
6935                                 } else
6936                                         gst_object_unref(GST_OBJECT(parent));
6937                         }
6938                 }
6939
6940                 /* release pipeline with it's childs */
6941                 if (mainbin[MMPLAYER_M_PIPE].gst)
6942                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6943
6944                 MMPLAYER_FREEIF(mainbin);
6945         }
6946
6947         MMPLAYER_FREEIF(player->pipeline);
6948         return MM_ERROR_PLAYER_INTERNAL;
6949 }
6950
6951 static void
6952 __mmplayer_reset_gapless_state(mm_player_t* player)
6953 {
6954         MMPLAYER_FENTER();
6955         MMPLAYER_RETURN_IF_FAIL(player
6956                 && player->pipeline
6957                 && player->pipeline->audiobin
6958                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6959
6960         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6961
6962         MMPLAYER_FLEAVE();
6963         return;
6964 }
6965
6966 static int
6967 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6968 {
6969         gint timeout = 0;
6970         int ret = MM_ERROR_NONE;
6971
6972         MMPLAYER_FENTER();
6973
6974         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6975
6976         /* cleanup stuffs */
6977         MMPLAYER_FREEIF(player->type);
6978         player->have_dynamic_pad = FALSE;
6979         player->no_more_pad = FALSE;
6980         player->num_dynamic_pad = 0;
6981         player->demux_pad_index = 0;
6982         player->use_deinterleave = FALSE;
6983         player->max_audio_channels = 0;
6984         player->video_share_api_delta = 0;
6985         player->video_share_clock_delta = 0;
6986         player->video_hub_download_mode = 0;
6987
6988         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6989         player->subtitle_language_list = NULL;
6990         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6991
6992         __mmplayer_reset_gapless_state(player);
6993
6994         if (player->streamer) {
6995                 __mm_player_streaming_deinitialize(player->streamer);
6996                 __mm_player_streaming_destroy(player->streamer);
6997                 player->streamer = NULL;
6998         }
6999
7000         /* cleanup unlinked mime type */
7001         MMPLAYER_FREEIF(player->unlinked_audio_mime);
7002         MMPLAYER_FREEIF(player->unlinked_video_mime);
7003         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7004
7005         /* cleanup running stuffs */
7006         __mmplayer_cancel_eos_timer(player);
7007
7008         /* cleanup gst stuffs */
7009         if (player->pipeline) {
7010                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7011                 GstTagList* tag_list = player->pipeline->tag_list;
7012
7013                 /* first we need to disconnect all signal hander */
7014                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7015
7016                 if (mainbin) {
7017                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7018                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7019                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7020                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7021                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7022                         gst_object_unref(bus);
7023
7024                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7025                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7026                         if (ret != MM_ERROR_NONE) {
7027                                 LOGE("fail to change state to NULL\n");
7028                                 return MM_ERROR_PLAYER_INTERNAL;
7029                         }
7030
7031                         LOGW("succeeded in chaning state to NULL\n");
7032
7033                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7034
7035                         /* free fakesink */
7036                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7037                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7038
7039                         /* free avsysaudiosink
7040                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7041                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7042                         */
7043                         MMPLAYER_FREEIF(audiobin);
7044                         MMPLAYER_FREEIF(videobin);
7045                         MMPLAYER_FREEIF(textbin);
7046                         MMPLAYER_FREEIF(mainbin);
7047                 }
7048
7049                 if (tag_list)
7050                         gst_tag_list_free(tag_list);
7051
7052                 MMPLAYER_FREEIF(player->pipeline);
7053         }
7054         MMPLAYER_FREEIF(player->album_art);
7055
7056         if (player->v_stream_caps) {
7057                 gst_caps_unref(player->v_stream_caps);
7058                 player->v_stream_caps = NULL;
7059         }
7060         if (player->a_stream_caps) {
7061                 gst_caps_unref(player->a_stream_caps);
7062                 player->a_stream_caps = NULL;
7063         }
7064
7065         if (player->s_stream_caps) {
7066                 gst_caps_unref(player->s_stream_caps);
7067                 player->s_stream_caps = NULL;
7068         }
7069         _mmplayer_track_destroy(player);
7070
7071         if (player->sink_elements)
7072                 g_list_free(player->sink_elements);
7073         player->sink_elements = NULL;
7074
7075         if (player->bufmgr) {
7076                 tbm_bufmgr_deinit(player->bufmgr);
7077                 player->bufmgr = NULL;
7078         }
7079
7080         LOGW("finished destroy pipeline\n");
7081
7082         MMPLAYER_FLEAVE();
7083
7084         return ret;
7085 }
7086
7087 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
7088 {
7089         MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
7090
7091         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
7092
7093         audiobin = player->pipeline->audiobin; /* can be null */
7094         videobin = player->pipeline->videobin; /* can be null */
7095         textbin = player->pipeline->textbin;   /* can be null */
7096
7097         LOGD("Async will be set to %d about 0x%X type sink", async, type);
7098
7099         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
7100                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
7101
7102         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
7103                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
7104
7105         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
7106                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
7107
7108         return;
7109 }
7110
7111 static int __gst_realize(mm_player_t* player)
7112 {
7113         gint timeout = 0;
7114         int ret = MM_ERROR_NONE;
7115
7116         MMPLAYER_FENTER();
7117
7118         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7119
7120         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7121
7122         ret = __mmplayer_gst_create_pipeline(player);
7123         if (ret) {
7124                 LOGE("failed to create pipeline\n");
7125                 return ret;
7126         }
7127
7128         /* set pipeline state to READY */
7129         /* NOTE : state change to READY must be performed sync. */
7130         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7131         ret = __mmplayer_gst_set_state(player,
7132                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7133
7134         if (ret != MM_ERROR_NONE) {
7135                 /* return error if failed to set state */
7136                 LOGE("failed to set READY state");
7137                 return ret;
7138         }
7139
7140         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7141
7142         /* create dot before error-return. for debugging */
7143         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7144
7145         MMPLAYER_FLEAVE();
7146
7147         return ret;
7148 }
7149
7150 static int __gst_unrealize(mm_player_t* player)
7151 {
7152         int ret = MM_ERROR_NONE;
7153
7154         MMPLAYER_FENTER();
7155
7156         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7157
7158         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7159         MMPLAYER_PRINT_STATE(player);
7160
7161         /* release miscellaneous information */
7162         __mmplayer_release_misc(player);
7163
7164         /* destroy pipeline */
7165         ret = __mmplayer_gst_destroy_pipeline(player);
7166         if (ret != MM_ERROR_NONE) {
7167                 LOGE("failed to destory pipeline\n");
7168                 return ret;
7169         }
7170
7171         /* release miscellaneous information.
7172            these info needs to be released after pipeline is destroyed. */
7173         __mmplayer_release_misc_post(player);
7174
7175         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7176
7177         MMPLAYER_FLEAVE();
7178
7179         return ret;
7180 }
7181
7182 static int __gst_pending_seek(mm_player_t* player)
7183 {
7184         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7185         int ret = MM_ERROR_NONE;
7186
7187         MMPLAYER_FENTER();
7188
7189         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7190
7191         if (!player->pending_seek.is_pending) {
7192                 LOGD("pending seek is not reserved. nothing to do.\n");
7193                 return ret;
7194         }
7195
7196         /* check player state if player could pending seek or not. */
7197         current_state = MMPLAYER_CURRENT_STATE(player);
7198
7199         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7200                 LOGW("try to pending seek in %s state, try next time. \n",
7201                         MMPLAYER_STATE_GET_NAME(current_state));
7202                 return ret;
7203         }
7204
7205         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7206
7207         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7208
7209         if (MM_ERROR_NONE != ret)
7210                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7211
7212         player->pending_seek.is_pending = FALSE;
7213
7214         MMPLAYER_FLEAVE();
7215
7216         return ret;
7217 }
7218
7219 static int __gst_start(mm_player_t* player)
7220 {
7221         int ret = MM_ERROR_NONE;
7222         gboolean async = FALSE;
7223
7224         MMPLAYER_FENTER();
7225
7226         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7227
7228         /* NOTE : if SetPosition was called before Start. do it now */
7229         /* streaming doesn't support it. so it should be always sync */
7230         /* !!create one more api to check if there is pending seek rather than checking variables */
7231         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
7232                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7233                 ret = __gst_pause(player, FALSE);
7234                 if (ret != MM_ERROR_NONE) {
7235                         LOGE("failed to set state to PAUSED for pending seek");
7236                         return ret;
7237                 }
7238
7239                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7240                 if (__gst_pending_seek(player) != MM_ERROR_NONE)
7241                                 LOGW("failed to seek pending postion. starting from the begin of content");
7242         }
7243
7244         LOGD("current state before doing transition");
7245         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7246         MMPLAYER_PRINT_STATE(player);
7247
7248         /* set pipeline state to PLAYING  */
7249         ret = __mmplayer_gst_set_state(player,
7250                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7251
7252         if (ret == MM_ERROR_NONE) {
7253                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7254         } else {
7255                 LOGE("failed to set state to PLAYING");
7256                 return ret;
7257         }
7258
7259         /* generating debug info before returning error */
7260         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7261
7262         MMPLAYER_FLEAVE();
7263
7264         return ret;
7265 }
7266
7267 static int __gst_stop(mm_player_t* player)
7268 {
7269         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7270         MMHandleType attrs = 0;
7271         gboolean rewind = FALSE;
7272         gint timeout = 0;
7273         int ret = MM_ERROR_NONE;
7274
7275         MMPLAYER_FENTER();
7276
7277         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7279
7280         LOGD("current state before doing transition");
7281         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7282         MMPLAYER_PRINT_STATE(player);
7283
7284         attrs = MMPLAYER_GET_ATTRS(player);
7285         if (!attrs) {
7286                 LOGE("cannot get content attribute\n");
7287                 return MM_ERROR_PLAYER_INTERNAL;
7288         }
7289
7290         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7291         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7292
7293         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7294                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7295                 rewind = TRUE;
7296
7297         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7298                 /* disable the async state transition because there could be no data in the pipeline */
7299                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
7300         }
7301
7302         /* set gst state */
7303         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
7304
7305         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7306                 /* enable the async state transition as default operation */
7307                 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
7308         }
7309
7310         /* return if set_state has failed */
7311         if (ret != MM_ERROR_NONE) {
7312                 LOGE("failed to set state.\n");
7313                 return ret;
7314         }
7315
7316         /* rewind */
7317         if (rewind) {
7318                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7319                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7320                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7321                         LOGW("failed to rewind\n");
7322                         ret = MM_ERROR_PLAYER_SEEK;
7323                 }
7324         }
7325
7326         /* initialize */
7327         player->sent_bos = FALSE;
7328
7329         if (player->es_player_push_mode) //for cloudgame
7330                 timeout = 0;
7331
7332         /* wait for seek to complete */
7333         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7334         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7335                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7336         } else {
7337                 LOGE("fail to stop player.\n");
7338                 ret = MM_ERROR_PLAYER_INTERNAL;
7339                 __mmplayer_dump_pipeline_state(player);
7340         }
7341
7342         /* generate dot file if enabled */
7343         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7344
7345         MMPLAYER_FLEAVE();
7346
7347         return ret;
7348 }
7349
7350 int __gst_pause(mm_player_t* player, gboolean async)
7351 {
7352         int ret = MM_ERROR_NONE;
7353
7354         MMPLAYER_FENTER();
7355
7356         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7357         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7358
7359         LOGD("current state before doing transition");
7360         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7361         MMPLAYER_PRINT_STATE(player);
7362
7363         /* set pipeline status to PAUSED */
7364         ret = __mmplayer_gst_set_state(player,
7365                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7366
7367         if (FALSE == async) {
7368                 if (ret != MM_ERROR_NONE) {
7369                         GstMessage *msg = NULL;
7370                         GTimer *timer = NULL;
7371                         gdouble MAX_TIMEOUT_SEC = 3;
7372
7373                         LOGE("failed to set state to PAUSED");
7374
7375                         if (player->msg_posted) {
7376                                 LOGE("error msg is already posted.");
7377                                 return ret;
7378                         }
7379
7380                         timer = g_timer_new();
7381                         g_timer_start(timer);
7382
7383                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7384
7385                         do {
7386                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7387                                 if (msg) {
7388                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7389                                                 GError *error = NULL;
7390
7391                                                 /* parse error code */
7392                                                 gst_message_parse_error(msg, &error, NULL);
7393
7394                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7395                                                         /* Note : the streaming error from the streaming source is handled
7396                                                          *   using __mmplayer_handle_streaming_error.
7397                                                          */
7398                                                         __mmplayer_handle_streaming_error(player, msg);
7399
7400                                                 } else if (error) {
7401                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7402
7403                                                         if (error->domain == GST_STREAM_ERROR)
7404                                                                 ret = __gst_handle_stream_error(player, error, msg);
7405                                                         else if (error->domain == GST_RESOURCE_ERROR)
7406                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7407                                                         else if (error->domain == GST_LIBRARY_ERROR)
7408                                                                 ret = __gst_handle_library_error(player, error->code);
7409                                                         else if (error->domain == GST_CORE_ERROR)
7410                                                                 ret = __gst_handle_core_error(player, error->code);
7411
7412                                                         g_error_free(error);
7413                                                 }
7414                                                 player->msg_posted = TRUE;
7415                                         }
7416                                         gst_message_unref(msg);
7417                                 }
7418                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7419                         /* clean */
7420                         gst_object_unref(bus);
7421                         g_timer_stop(timer);
7422                         g_timer_destroy(timer);
7423
7424                         return ret;
7425
7426                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7427                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7428
7429                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7430
7431                 } else if (ret == MM_ERROR_NONE) {
7432
7433                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7434                 }
7435         }
7436
7437         /* generate dot file before returning error */
7438         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7439
7440         MMPLAYER_FLEAVE();
7441
7442         return ret;
7443 }
7444
7445 int __gst_resume(mm_player_t* player, gboolean async)
7446 {
7447         int ret = MM_ERROR_NONE;
7448         gint timeout = 0;
7449
7450         MMPLAYER_FENTER();
7451
7452         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7453                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7454
7455         LOGD("current state before doing transition");
7456         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7457         MMPLAYER_PRINT_STATE(player);
7458
7459         if (async)
7460                 LOGD("do async state transition to PLAYING");
7461
7462         /* set pipeline state to PLAYING */
7463         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7464
7465         ret = __mmplayer_gst_set_state(player,
7466                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7467         if (ret != MM_ERROR_NONE) {
7468                 LOGE("failed to set state to PLAYING");
7469                 goto EXIT;
7470         } else {
7471                 if (async == FALSE)
7472                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7473         }
7474
7475 EXIT:
7476         /* generate dot file */
7477         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7478
7479         MMPLAYER_FLEAVE();
7480
7481         return ret;
7482 }
7483
7484 static int
7485 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7486 {
7487         gint64 dur_nsec = 0;
7488         gint64 pos_nsec = 0;
7489         gboolean ret = TRUE;
7490         gboolean accurated = FALSE;
7491         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7492
7493         MMPLAYER_FENTER();
7494         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7495         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7496
7497         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7498                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7499                 goto PENDING;
7500
7501         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7502                 /* check duration */
7503                 /* NOTE : duration cannot be zero except live streaming.
7504                  *              Since some element could have some timing problemn with quering duration, try again.
7505                  */
7506                 if (player->duration == 0) {
7507                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7508                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7509                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7510                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7511                                         player->pending_seek.is_pending = TRUE;
7512                                         player->pending_seek.format = format;
7513                                         player->pending_seek.pos = position;
7514                                         player->seek_state = MMPLAYER_SEEK_NONE;
7515                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7516                                         return MM_ERROR_NONE;
7517                                 } else {
7518                                         goto SEEK_ERROR;
7519                                 }
7520                         }
7521                         player->duration = dur_nsec;
7522                 }
7523         }
7524         LOGD("playback rate: %f\n", player->playback_rate);
7525
7526         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7527         if (accurated)
7528                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7529         else
7530                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7531
7532         /* do seek */
7533         switch (format) {
7534         case MM_PLAYER_POS_FORMAT_TIME:
7535         {
7536                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7537                         GstQuery *query = NULL;
7538                         gboolean seekable = FALSE;
7539
7540                         /* check position is valid or not */
7541                         if (position > player->duration)
7542                                 goto INVALID_ARGS;
7543
7544                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7545                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7546                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7547                                 gst_query_unref(query);
7548
7549                                 if (!seekable) {
7550                                         LOGW("non-seekable content");
7551                                         player->seek_state = MMPLAYER_SEEK_NONE;
7552                                         return MM_ERROR_PLAYER_NO_OP;
7553                                 }
7554                         } else {
7555                                 LOGW("failed to get seeking query");
7556                                 gst_query_unref(query); /* keep seeking operation */
7557                         }
7558
7559                         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7560
7561                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7562                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7563                            This causes problem is position calculation during normal pause resume scenarios also.
7564                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7565                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7566                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7567                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7568                                         LOGW("getting current position failed in seek\n");
7569
7570                                 player->last_position = pos_nsec;
7571                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7572                         }
7573
7574                         if (player->seek_state != MMPLAYER_SEEK_NONE) {
7575                                 LOGD("not completed seek");
7576                                 return MM_ERROR_PLAYER_DOING_SEEK;
7577                         }
7578                 }
7579
7580                 if (!internal_called)
7581                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7582
7583                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7584                         gint64 cur_time = 0;
7585
7586                         /* get current position */
7587                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7588
7589                         /* flush */
7590                         GstEvent *event = gst_event_new_seek(1.0,
7591                                                         GST_FORMAT_TIME,
7592                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7593                                                         GST_SEEK_TYPE_SET, cur_time,
7594                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7595                         if (event)
7596                                 __gst_send_event_to_sink(player, event);
7597
7598                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7599                                 __gst_pause(player, FALSE);
7600                 }
7601
7602                 pos_nsec = position;
7603
7604                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7605                         that's why set position through property. */
7606                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7607                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7608                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7609                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7610
7611                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7612                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7613                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7614                         player->seek_state = MMPLAYER_SEEK_NONE;
7615                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7616                 } else {
7617                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7618                                                         GST_FORMAT_TIME, seek_flags,
7619                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7620                 }
7621
7622                 if (!ret) {
7623                         LOGE("failed to set position.");
7624                         goto SEEK_ERROR;
7625                 }
7626         }
7627         break;
7628
7629         case MM_PLAYER_POS_FORMAT_PERCENT:
7630         {
7631                 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7632
7633                 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7634                         LOGD("not completed seek");
7635                         return MM_ERROR_PLAYER_DOING_SEEK;
7636                 }
7637
7638                 if (!internal_called)
7639                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7640
7641                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7642                 pos_nsec = (gint64)((position * player->duration) / 100);
7643                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7644                                                 GST_FORMAT_TIME, seek_flags,
7645                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7646                 if (!ret) {
7647                         LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7648                         goto SEEK_ERROR;
7649                 }
7650         }
7651         break;
7652
7653         default:
7654                 goto INVALID_ARGS;
7655         }
7656
7657         /* NOTE : store last seeking point to overcome some bad operation
7658           *     (returning zero when getting current position) of some elements
7659           */
7660         player->last_position = pos_nsec;
7661
7662         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7663         if (player->playback_rate > 1.0)
7664                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7665
7666         if ((!internal_called) &&
7667             (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7668                 LOGD("buffering should be reset after seeking");
7669                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7670                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
7671         }
7672
7673         MMPLAYER_FLEAVE();
7674         return MM_ERROR_NONE;
7675
7676 PENDING:
7677         player->pending_seek.is_pending = TRUE;
7678         player->pending_seek.format = format;
7679         player->pending_seek.pos = position;
7680
7681         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7682                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7683                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7684                 player->pending_seek.pos);
7685
7686         return MM_ERROR_NONE;
7687
7688 INVALID_ARGS:
7689         LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7690         return MM_ERROR_INVALID_ARGUMENT;
7691
7692 SEEK_ERROR:
7693         player->seek_state = MMPLAYER_SEEK_NONE;
7694         return MM_ERROR_PLAYER_SEEK;
7695 }
7696
7697 #define TRICKPLAY_OFFSET GST_MSECOND
7698
7699 static int
7700 __gst_get_position(mm_player_t* player, int format, gint64* position)
7701 {
7702         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7703         gint64 pos_nsec = 0;
7704         gboolean ret = TRUE;
7705
7706         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7707                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7708
7709         current_state = MMPLAYER_CURRENT_STATE(player);
7710
7711         /* NOTE : query position except paused state to overcome some bad operation
7712          * please refer to below comments in details
7713          */
7714         if (current_state != MM_PLAYER_STATE_PAUSED)
7715                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7716
7717         /* NOTE : get last point to overcome some bad operation of some elements
7718          *(returning zero when getting current position in paused state
7719          * and when failed to get postion during seeking
7720          */
7721         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7722                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7723
7724                 if (player->playback_rate < 0.0)
7725                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7726                 else
7727                         pos_nsec = player->last_position;
7728
7729                 if (!ret)
7730                         pos_nsec = player->last_position;
7731                 else
7732                         player->last_position = pos_nsec;
7733
7734                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7735
7736         } else {
7737                 if (player->duration > 0 && pos_nsec > player->duration)
7738                         pos_nsec = player->duration;
7739
7740                 player->last_position = pos_nsec;
7741         }
7742
7743         switch (format) {
7744         case MM_PLAYER_POS_FORMAT_TIME:
7745                 *position = pos_nsec;
7746                 break;
7747
7748         case MM_PLAYER_POS_FORMAT_PERCENT:
7749         {
7750                 if (player->duration <= 0) {
7751                         LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7752                         *position = 0;
7753                 } else {
7754                         LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7755                         *position = (gint64)(pos_nsec * 100 / player->duration);
7756                 }
7757                 break;
7758         }
7759         default:
7760                 return MM_ERROR_PLAYER_INTERNAL;
7761         }
7762
7763         return MM_ERROR_NONE;
7764 }
7765
7766
7767 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7768 {
7769 #define STREAMING_IS_FINISHED   0
7770 #define BUFFERING_MAX_PER       100
7771 #define DEFAULT_PER_VALUE       -1
7772 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7773
7774         MMPlayerGstElement *mainbin = NULL;
7775         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7776         gint64 buffered_total = 0;
7777         gint64 position = 0;
7778         gint buffered_sec = -1;
7779         GstBufferingMode mode = GST_BUFFERING_STREAM;
7780         gint64 content_size_time = player->duration;
7781         guint64 content_size_bytes = player->http_content_size;
7782
7783         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7784                                                 player->pipeline &&
7785                                                 player->pipeline->mainbin,
7786                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7787
7788         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7789
7790         *start_pos = 0;
7791         *stop_pos = 0;
7792
7793         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7794                 /* and rtsp is not ready yet. */
7795                 LOGW("it's only used for http streaming case.\n");
7796                 return MM_ERROR_PLAYER_NO_OP;
7797         }
7798
7799         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7800                 LOGW("Time format is not supported yet.\n");
7801                 return MM_ERROR_INVALID_ARGUMENT;
7802         }
7803
7804         if (content_size_time <= 0 || content_size_bytes <= 0) {
7805                 LOGW("there is no content size.");
7806                 return MM_ERROR_NONE;
7807         }
7808
7809         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7810                 LOGW("fail to get current position.");
7811                 return MM_ERROR_NONE;
7812         }
7813
7814         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7815                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7816
7817         mainbin = player->pipeline->mainbin;
7818         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7819
7820         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7821                 GstQuery *query = NULL;
7822                 gint byte_in_rate = 0, byte_out_rate = 0;
7823                 gint64 estimated_total = 0;
7824
7825                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7826                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7827                         LOGW("fail to get buffering query from queue2");
7828                         if (query)
7829                                 gst_query_unref(query);
7830                         return MM_ERROR_NONE;
7831                 }
7832
7833                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7834                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7835
7836                 if (mode == GST_BUFFERING_STREAM) {
7837                         /* using only queue in case of push mode(ts / mp3) */
7838                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7839                                 GST_FORMAT_BYTES, &buffered_total)) {
7840                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7841                                 stop_per = 100 * buffered_total / content_size_bytes;
7842                         }
7843                 } else {
7844                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7845                         guint idx = 0;
7846                         guint num_of_ranges = 0;
7847                         gint64 start_byte = 0, stop_byte = 0;
7848
7849                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7850                         if (estimated_total != STREAMING_IS_FINISHED) {
7851                                 /* buffered size info from queue2 */
7852                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7853                                 for (idx = 0; idx < num_of_ranges; idx++) {
7854                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7855                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7856
7857                                         buffered_total += (stop_byte - start_byte);
7858                                 }
7859                         } else
7860                                 stop_per = BUFFERING_MAX_PER;
7861                 }
7862                 gst_query_unref(query);
7863         }
7864
7865         if (stop_per == DEFAULT_PER_VALUE) {
7866                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7867                 if (dur_sec > 0) {
7868                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7869
7870                         /* buffered size info from multiqueue */
7871                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7872                                 guint curr_size_bytes = 0;
7873                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7874                                         "curr-size-bytes", &curr_size_bytes, NULL);
7875                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7876                                 buffered_total += curr_size_bytes;
7877                         }
7878
7879                         if (avg_byterate > 0)
7880                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7881                         else if (player->total_maximum_bitrate > 0)
7882                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7883                         else if (player->total_bitrate > 0)
7884                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7885
7886                         if (buffered_sec >= 0)
7887                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7888                 }
7889         }
7890
7891         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7892         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7893
7894         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7895                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7896
7897         return MM_ERROR_NONE;
7898 }
7899
7900 static int
7901 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7902 {
7903         MMPLAYER_FENTER();
7904
7905         if (!player) {
7906                 LOGW("set_message_callback is called with invalid player handle\n");
7907                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7908         }
7909
7910         player->msg_cb = callback;
7911         player->msg_cb_param = user_param;
7912
7913         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7914
7915         MMPLAYER_FLEAVE();
7916
7917         return MM_ERROR_NONE;
7918 }
7919
7920 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7921 {
7922         int ret = MM_ERROR_PLAYER_INVALID_URI;
7923         char *path = NULL;
7924
7925         MMPLAYER_FENTER();
7926
7927         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7928         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7929         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7930
7931         memset(data, 0, sizeof(MMPlayerParseProfile));
7932
7933         if ((path = strstr(uri, "es_buff://"))) {
7934                 if (strlen(path)) {
7935                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7936                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7937                         ret = MM_ERROR_NONE;
7938                 }
7939         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7940                 if (strlen(path)) {
7941                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7942                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7943                         ret = MM_ERROR_NONE;
7944                 }
7945         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7946                 if (strlen(path)) {
7947                         gchar *tmp = NULL;
7948                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7949                         tmp = g_ascii_strdown(uri, strlen(uri));
7950
7951                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7952                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7953                         else
7954                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7955
7956                         ret = MM_ERROR_NONE;
7957                         g_free(tmp);
7958                 }
7959         } else if ((path = strstr(uri, "rtspu://"))) {
7960                 if (strlen(path)) {
7961                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7962                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7963                         ret = MM_ERROR_NONE;
7964                 }
7965         } else if ((path = strstr(uri, "rtspr://"))) {
7966                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7967                 char *separater = strstr(path, "*");
7968
7969                 if (separater) {
7970                         int urgent_len = 0;
7971                         char *urgent = separater + strlen("*");
7972
7973                         if ((urgent_len = strlen(urgent))) {
7974                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7975                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7976                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7977                                 ret = MM_ERROR_NONE;
7978                         }
7979                 }
7980         } else if ((path = strstr(uri, "mms://"))) {
7981                 if (strlen(path)) {
7982                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7983                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7984                         ret = MM_ERROR_NONE;
7985                 }
7986         } else if ((path = strstr(uri, "mem://"))) {
7987                 if (strlen(path)) {
7988                         int mem_size = 0;
7989                         char *buffer = NULL;
7990                         char *seperator = strchr(path, ',');
7991                         char ext[100] = {0,}, size[100] = {0,};
7992
7993                         if (seperator) {
7994                                 if ((buffer = strstr(path, "ext="))) {
7995                                         buffer += strlen("ext=");
7996
7997                                         if (strlen(buffer)) {
7998                                                 strncpy(ext, buffer, 99);
7999
8000                                                 if ((seperator = strchr(ext, ','))
8001                                                         || (seperator = strchr(ext, ' '))
8002                                                         || (seperator = strchr(ext, '\0'))) {
8003                                                         seperator[0] = '\0';
8004                                                 }
8005                                         }
8006                                 }
8007
8008                                 if ((buffer = strstr(path, "size="))) {
8009                                         buffer += strlen("size=");
8010
8011                                         if (strlen(buffer) > 0) {
8012                                                 strncpy(size, buffer, 99);
8013
8014                                                 if ((seperator = strchr(size, ','))
8015                                                         || (seperator = strchr(size, ' '))
8016                                                         || (seperator = strchr(size, '\0'))) {
8017                                                         seperator[0] = '\0';
8018                                                 }
8019
8020                                                 mem_size = atoi(size);
8021                                         }
8022                                 }
8023                         }
8024
8025                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8026                         if (mem_size && param) {
8027                                 if (data->input_mem.buf)
8028                                         free(data->input_mem.buf);
8029                                 data->input_mem.buf = malloc(mem_size);
8030
8031                                 if (data->input_mem.buf) {
8032                                         memcpy(data->input_mem.buf, param, mem_size);
8033                                         data->input_mem.len = mem_size;
8034                                         ret = MM_ERROR_NONE;
8035                                 } else {
8036                                         LOGE("failed to alloc mem %d", mem_size);
8037                                         ret = MM_ERROR_PLAYER_INTERNAL;
8038                                 }
8039
8040                                 data->input_mem.offset = 0;
8041                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8042                         }
8043                 }
8044         } else {
8045                 gchar *location = NULL;
8046                 GError *err = NULL;
8047
8048                 if ((path = strstr(uri, "file://"))) {
8049
8050                         location = g_filename_from_uri(uri, NULL, &err);
8051
8052                         if (!location || (err != NULL)) {
8053                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8054                                  (err != NULL) ? err->message : "unknown error");
8055
8056                           if (err) g_error_free(err);
8057                           if (location) g_free(location);
8058
8059                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8060                           goto exit;
8061                         }
8062
8063                         LOGD("path from uri: %s", location);
8064                 }
8065
8066                 path = (location != NULL) ? (location) : ((char*)uri);
8067                 int file_stat = MM_ERROR_NONE;
8068
8069                 file_stat = util_exist_file_path(path);
8070
8071                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8072                 if (file_stat == MM_ERROR_NONE) {
8073                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8074
8075                         if (util_is_sdp_file(path)) {
8076                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8077                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8078                         } else {
8079                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8080                         }
8081                         ret = MM_ERROR_NONE;
8082                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8083                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8084                 } else {
8085                         LOGE("invalid uri, could not play..\n");
8086                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8087                 }
8088
8089                 if (location) g_free(location);
8090         }
8091
8092 exit:
8093         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8094                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8095         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8096                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8097
8098         /* dump parse result */
8099         SECURE_LOGW("incomming uri : %s\n", uri);
8100         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8101                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8102
8103         MMPLAYER_FLEAVE();
8104
8105         return ret;
8106 }
8107
8108 gboolean
8109 __mmplayer_can_do_interrupt(mm_player_t *player)
8110 {
8111         if (!player || !player->pipeline || !player->attrs) {
8112                 LOGW("not initialized");
8113                 goto FAILED;
8114         }
8115
8116         if (player->set_mode.pcm_extraction) {
8117                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8118                 goto FAILED;
8119         }
8120
8121         /* check if seeking */
8122         if (player->seek_state != MMPLAYER_SEEK_NONE) {
8123                 MMMessageParamType msg_param;
8124                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8125                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8126                 player->seek_state = MMPLAYER_SEEK_NONE;
8127                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8128                 goto FAILED;
8129         }
8130
8131         /* check other thread */
8132         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8133                 LOGW("locked already, cmd state : %d", player->cmd);
8134
8135                 /* check application command */
8136                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8137                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8138
8139                         /* lock will be released at mrp_resource_release_cb() */
8140                         MMPLAYER_CMD_LOCK(player);
8141                         goto INTERRUPT;
8142                 }
8143                 LOGW("nothing to do");
8144                 goto FAILED;
8145         } else {
8146                 LOGW("can interrupt immediately");
8147                 goto INTERRUPT;
8148         }
8149
8150 FAILED:    /* with CMD UNLOCKED */
8151         return FALSE;
8152
8153 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8154         return TRUE;
8155 }
8156
8157 static int
8158 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8159                 void *user_data)
8160 {
8161         mm_player_t *player = NULL;
8162
8163         MMPLAYER_FENTER();
8164
8165         if (user_data == NULL) {
8166                 LOGE("- user_data is null\n");
8167                 return FALSE;
8168         }
8169         player = (mm_player_t *)user_data;
8170
8171         /* do something to release resource here.
8172          * player stop and interrupt forwarding */
8173         if (!__mmplayer_can_do_interrupt(player)) {
8174                 LOGW("no need to interrupt, so leave");
8175         } else {
8176                 MMMessageParamType msg = {0, };
8177                 gint64 pos = 0;
8178
8179                 player->interrupted_by_resource = TRUE;
8180
8181                 /* get last play position */
8182                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8183                         LOGW("failed to get play position.");
8184                 } else {
8185                         msg.union_type = MM_MSG_UNION_TIME;
8186                         msg.time.elapsed = pos;
8187                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8188                 }
8189                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8190                 if (_mmplayer_unrealize((MMHandleType)player))
8191                         LOGW("failed to unrealize");
8192
8193                 /* lock is called in __mmplayer_can_do_interrupt() */
8194                 MMPLAYER_CMD_UNLOCK(player);
8195         }
8196
8197         if (res == player->video_overlay_resource)
8198                 player->video_overlay_resource = FALSE;
8199         else
8200                 player->video_decoder_resource = FALSE;
8201
8202         MMPLAYER_FLEAVE();
8203
8204         return FALSE;
8205 }
8206
8207 int
8208 _mmplayer_create_player(MMHandleType handle)
8209 {
8210         int ret = MM_ERROR_PLAYER_INTERNAL;
8211         bool enabled = false;
8212
8213         mm_player_t* player = MM_PLAYER_CAST(handle);
8214
8215         MMPLAYER_FENTER();
8216
8217         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8218
8219         /* initialize player state */
8220         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8221         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8222         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8223         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8224
8225         /* check current state */
8226         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8227
8228         /* construct attributes */
8229         player->attrs = _mmplayer_construct_attribute(handle);
8230
8231         if (!player->attrs) {
8232                 LOGE("Failed to construct attributes\n");
8233                 return ret;
8234         }
8235
8236         /* initialize gstreamer with configured parameter */
8237         if (!__mmplayer_init_gstreamer(player)) {
8238                 LOGE("Initializing gstreamer failed\n");
8239                 _mmplayer_deconstruct_attribute(handle);
8240                 return ret;
8241         }
8242
8243         /* create lock. note that g_tread_init() has already called in gst_init() */
8244         g_mutex_init(&player->fsink_lock);
8245
8246         /* create update tag lock */
8247         g_mutex_init(&player->update_tag_lock);
8248
8249         /* create next play mutex */
8250         g_mutex_init(&player->next_play_thread_mutex);
8251
8252         /* create next play cond */
8253         g_cond_init(&player->next_play_thread_cond);
8254
8255         /* create next play thread */
8256         player->next_play_thread =
8257                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8258         if (!player->next_play_thread) {
8259                 LOGE("failed to create next play thread");
8260                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8261                 g_mutex_clear(&player->next_play_thread_mutex);
8262                 g_cond_clear(&player->next_play_thread_cond);
8263                 goto ERROR;
8264         }
8265
8266         player->bus_msg_q = g_queue_new();
8267         if (!player->bus_msg_q) {
8268                 LOGE("failed to create queue for bus_msg");
8269                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8270                 goto ERROR;
8271         }
8272
8273         ret = _mmplayer_initialize_video_capture(player);
8274         if (ret != MM_ERROR_NONE) {
8275                 LOGE("failed to initialize video capture\n");
8276                 goto ERROR;
8277         }
8278
8279         /* initialize resource manager */
8280         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8281                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8282                         &player->resource_manager)) {
8283                 LOGE("failed to initialize resource manager\n");
8284                 goto ERROR;
8285         }
8286
8287         if (MMPLAYER_IS_HTTP_PD(player)) {
8288                 player->pd_downloader = NULL;
8289                 player->pd_file_save_path = NULL;
8290         }
8291
8292         /* create video bo lock and cond */
8293         g_mutex_init(&player->video_bo_mutex);
8294         g_cond_init(&player->video_bo_cond);
8295
8296         /* create media stream callback mutex */
8297         g_mutex_init(&player->media_stream_cb_lock);
8298
8299         /* create subtitle info lock and cond */
8300         g_mutex_init(&player->subtitle_info_mutex);
8301         g_cond_init(&player->subtitle_info_cond);
8302
8303         player->streaming_type = STREAMING_SERVICE_NONE;
8304
8305         /* give default value of audio effect setting */
8306         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8307         player->sound.rg_enable = false;
8308         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8309
8310         player->play_subtitle = FALSE;
8311         player->use_deinterleave = FALSE;
8312         player->max_audio_channels = 0;
8313         player->video_share_api_delta = 0;
8314         player->video_share_clock_delta = 0;
8315         player->has_closed_caption = FALSE;
8316         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8317         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8318         player->pending_resume = FALSE;
8319         if (player->ini.dump_element_keyword[0][0] == '\0')
8320                 player->ini.set_dump_element_flag = FALSE;
8321         else
8322                 player->ini.set_dump_element_flag = TRUE;
8323
8324         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8325         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8326         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8327
8328         /* Set video360 settings to their defaults for just-created player.
8329          * */
8330
8331         player->is_360_feature_enabled = FALSE;
8332         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8333                 LOGI("spherical feature info: %d", enabled);
8334                 if (enabled)
8335                         player->is_360_feature_enabled = TRUE;
8336         } else {
8337                 LOGE("failed to get spherical feature info");
8338         }
8339
8340         player->is_content_spherical = FALSE;
8341         player->is_video360_enabled = TRUE;
8342         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8343         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8344         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8345         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8346         player->video360_zoom = 1.0f;
8347         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8348         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8349
8350         /* set player state to null */
8351         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8352         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8353
8354         return MM_ERROR_NONE;
8355
8356 ERROR:
8357         /* free lock */
8358         g_mutex_clear(&player->fsink_lock);
8359
8360         /* free update tag lock */
8361         g_mutex_clear(&player->update_tag_lock);
8362
8363         g_queue_free(player->bus_msg_q);
8364
8365         /* free next play thread */
8366         if (player->next_play_thread) {
8367                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8368                 player->next_play_thread_exit = TRUE;
8369                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8370                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8371
8372                 g_thread_join(player->next_play_thread);
8373                 player->next_play_thread = NULL;
8374
8375                 g_mutex_clear(&player->next_play_thread_mutex);
8376                 g_cond_clear(&player->next_play_thread_cond);
8377         }
8378
8379         /* release attributes */
8380         _mmplayer_deconstruct_attribute(handle);
8381
8382         MMPLAYER_FLEAVE();
8383
8384         return ret;
8385 }
8386
8387 static gboolean
8388 __mmplayer_init_gstreamer(mm_player_t* player)
8389 {
8390         static gboolean initialized = FALSE;
8391         static const int max_argc = 50;
8392         gint* argc = NULL;
8393         gchar** argv = NULL;
8394         gchar** argv2 = NULL;
8395         GError *err = NULL;
8396         int i = 0;
8397         int arg_count = 0;
8398
8399         if (initialized) {
8400                 LOGD("gstreamer already initialized.\n");
8401                 return TRUE;
8402         }
8403
8404         /* alloc */
8405         argc = malloc(sizeof(int));
8406         argv = malloc(sizeof(gchar*) * max_argc);
8407         argv2 = malloc(sizeof(gchar*) * max_argc);
8408
8409         if (!argc || !argv || !argv2)
8410                 goto ERROR;
8411
8412         memset(argv, 0, sizeof(gchar*) * max_argc);
8413         memset(argv2, 0, sizeof(gchar*) * max_argc);
8414
8415         /* add initial */
8416         *argc = 1;
8417         argv[0] = g_strdup("mmplayer");
8418
8419         /* add gst_param */
8420         for (i = 0; i < 5; i++) {
8421                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8422                 if (strlen(player->ini.gst_param[i]) > 0) {
8423                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8424                         (*argc)++;
8425                 }
8426         }
8427
8428         /* we would not do fork for scanning plugins */
8429         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8430         (*argc)++;
8431
8432         /* check disable registry scan */
8433         if (player->ini.skip_rescan) {
8434                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8435                 (*argc)++;
8436         }
8437
8438         /* check disable segtrap */
8439         if (player->ini.disable_segtrap) {
8440                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8441                 (*argc)++;
8442         }
8443
8444         LOGD("initializing gstreamer with following parameter\n");
8445         LOGD("argc : %d\n", *argc);
8446         arg_count = *argc;
8447
8448         for (i = 0; i < arg_count; i++) {
8449                 argv2[i] = argv[i];
8450                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8451         }
8452
8453         /* initializing gstreamer */
8454         if (!gst_init_check(argc, &argv, &err)) {
8455                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8456                 if (err)
8457                         g_error_free(err);
8458
8459                 goto ERROR;
8460         }
8461         /* release */
8462         for (i = 0; i < arg_count; i++) {
8463                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8464                 MMPLAYER_FREEIF(argv2[i]);
8465         }
8466
8467         MMPLAYER_FREEIF(argv);
8468         MMPLAYER_FREEIF(argv2);
8469         MMPLAYER_FREEIF(argc);
8470
8471         /* done */
8472         initialized = TRUE;
8473
8474         return TRUE;
8475
8476 ERROR:
8477
8478         /* release */
8479         for (i = 0; i < arg_count; i++) {
8480                 LOGD("free[%d] : %s\n", i, argv2[i]);
8481                 MMPLAYER_FREEIF(argv2[i]);
8482         }
8483
8484         MMPLAYER_FREEIF(argv);
8485         MMPLAYER_FREEIF(argv2);
8486         MMPLAYER_FREEIF(argc);
8487
8488         return FALSE;
8489 }
8490
8491 int
8492 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8493 {
8494         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8495
8496         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8497                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8498                 MMPLAYER_FREEIF(player->pd_file_save_path);
8499         }
8500
8501         return MM_ERROR_NONE;
8502 }
8503
8504 static void
8505 __mmplayer_check_async_state_transition(mm_player_t* player)
8506 {
8507         GstState element_state = GST_STATE_VOID_PENDING;
8508         GstState element_pending_state = GST_STATE_VOID_PENDING;
8509         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8510         GstElement * element = NULL;
8511         gboolean async = FALSE;
8512
8513         /* check player handle */
8514         MMPLAYER_RETURN_IF_FAIL(player &&
8515                                                 player->pipeline &&
8516                                                 player->pipeline->mainbin &&
8517                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8518
8519         if (player->attrs)
8520                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8521
8522         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8523                 LOGD("don't need to check the pipeline state");
8524                 return;
8525         }
8526
8527         MMPLAYER_PRINT_STATE(player);
8528
8529         /* wait for state transition */
8530         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8531         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8532
8533         if (ret == GST_STATE_CHANGE_FAILURE) {
8534                 LOGE(" [%s] state : %s   pending : %s \n",
8535                         GST_ELEMENT_NAME(element),
8536                         gst_element_state_get_name(element_state),
8537                         gst_element_state_get_name(element_pending_state));
8538
8539                 /* dump state of all element */
8540                 __mmplayer_dump_pipeline_state(player);
8541
8542                 return;
8543         }
8544
8545         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8546         return;
8547 }
8548
8549 int
8550 _mmplayer_destroy(MMHandleType handle)
8551 {
8552         mm_player_t* player = MM_PLAYER_CAST(handle);
8553
8554         MMPLAYER_FENTER();
8555
8556         /* check player handle */
8557         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8558
8559         /* destroy can called at anytime */
8560         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8561
8562         /* check async state transition */
8563         __mmplayer_check_async_state_transition(player);
8564
8565         __mmplayer_destroy_streaming_ext(player);
8566
8567         /* release next play thread */
8568         if (player->next_play_thread) {
8569                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8570                 player->next_play_thread_exit = TRUE;
8571                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8572                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8573
8574                 LOGD("waitting for next play thread exit\n");
8575                 g_thread_join(player->next_play_thread);
8576                 g_mutex_clear(&player->next_play_thread_mutex);
8577                 g_cond_clear(&player->next_play_thread_cond);
8578                 LOGD("next play thread released\n");
8579         }
8580
8581         _mmplayer_release_video_capture(player);
8582
8583         /* de-initialize resource manager */
8584         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8585                         player->resource_manager))
8586                 LOGE("failed to deinitialize resource manager\n");
8587
8588         /* release pipeline */
8589         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8590                 LOGE("failed to destory pipeline\n");
8591                 return MM_ERROR_PLAYER_INTERNAL;
8592         }
8593
8594         g_queue_free(player->bus_msg_q);
8595
8596         /* release subtitle info lock and cond */
8597         g_mutex_clear(&player->subtitle_info_mutex);
8598         g_cond_clear(&player->subtitle_info_cond);
8599
8600         __mmplayer_release_dump_list(player->dump_list);
8601
8602         /* release miscellaneous information */
8603         __mmplayer_release_misc(player);
8604
8605         /* release miscellaneous information.
8606            these info needs to be released after pipeline is destroyed. */
8607         __mmplayer_release_misc_post(player);
8608
8609         /* release attributes */
8610         _mmplayer_deconstruct_attribute(handle);
8611
8612         /* release lock */
8613         g_mutex_clear(&player->fsink_lock);
8614
8615         /* release lock */
8616         g_mutex_clear(&player->update_tag_lock);
8617
8618         /* release video bo lock and cond */
8619         g_mutex_clear(&player->video_bo_mutex);
8620         g_cond_clear(&player->video_bo_cond);
8621
8622         /* release media stream callback lock */
8623         g_mutex_clear(&player->media_stream_cb_lock);
8624
8625         MMPLAYER_FLEAVE();
8626
8627         return MM_ERROR_NONE;
8628 }
8629
8630 int
8631 __mmplayer_realize_streaming_ext(mm_player_t* player)
8632 {
8633         int ret = MM_ERROR_NONE;
8634
8635         MMPLAYER_FENTER();
8636         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8637
8638         if (MMPLAYER_IS_HTTP_PD(player)) {
8639                 gboolean bret = FALSE;
8640
8641                 player->pd_downloader = _mmplayer_create_pd_downloader();
8642                 if (!player->pd_downloader) {
8643                         LOGE("Unable to create PD Downloader...");
8644                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8645                 }
8646
8647                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8648
8649                 if (FALSE == bret) {
8650                         LOGE("Unable to create PD Downloader...");
8651                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8652                 }
8653         }
8654
8655         MMPLAYER_FLEAVE();
8656         return ret;
8657 }
8658
8659 int
8660 _mmplayer_realize(MMHandleType hplayer)
8661 {
8662         mm_player_t* player = (mm_player_t*)hplayer;
8663         char *uri = NULL;
8664         void *param = NULL;
8665         MMHandleType attrs = 0;
8666         int ret = MM_ERROR_NONE;
8667
8668         MMPLAYER_FENTER();
8669
8670         /* check player handle */
8671         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8672
8673         /* check current state */
8674         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8675
8676         attrs = MMPLAYER_GET_ATTRS(player);
8677         if (!attrs) {
8678                 LOGE("fail to get attributes.\n");
8679                 return MM_ERROR_PLAYER_INTERNAL;
8680         }
8681         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8682         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8683
8684         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8685                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8686
8687                 if (ret != MM_ERROR_NONE) {
8688                         LOGE("failed to parse profile\n");
8689                         return ret;
8690                 }
8691         }
8692
8693         if (uri && (strstr(uri, "es_buff://"))) {
8694                 if (strstr(uri, "es_buff://push_mode"))
8695                         player->es_player_push_mode = TRUE;
8696                 else
8697                         player->es_player_push_mode = FALSE;
8698         }
8699
8700         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8701                 LOGW("mms protocol is not supported format.\n");
8702                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8703         }
8704
8705         if (MMPLAYER_IS_STREAMING(player))
8706                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8707         else
8708                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8709
8710         player->smooth_streaming = FALSE;
8711         player->videodec_linked  = 0;
8712         player->videosink_linked = 0;
8713         player->audiodec_linked  = 0;
8714         player->audiosink_linked = 0;
8715         player->textsink_linked = 0;
8716         player->is_external_subtitle_present = FALSE;
8717         player->is_external_subtitle_added_now = FALSE;
8718         /* set the subtitle ON default */
8719         player->is_subtitle_off = FALSE;
8720
8721         /* realize pipeline */
8722         ret = __gst_realize(player);
8723         if (ret != MM_ERROR_NONE)
8724                 LOGE("fail to realize the player.\n");
8725         else
8726                 ret = __mmplayer_realize_streaming_ext(player);
8727
8728         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8729
8730         MMPLAYER_FLEAVE();
8731
8732         return ret;
8733 }
8734
8735 int
8736 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8737 {
8738         MMPLAYER_FENTER();
8739         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8740
8741         /* destroy can called at anytime */
8742         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8743                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8744
8745         MMPLAYER_FLEAVE();
8746         return MM_ERROR_NONE;
8747 }
8748
8749 int
8750 _mmplayer_unrealize(MMHandleType hplayer)
8751 {
8752         mm_player_t* player = (mm_player_t*)hplayer;
8753         int ret = MM_ERROR_NONE;
8754
8755         MMPLAYER_FENTER();
8756
8757         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8758
8759         MMPLAYER_CMD_UNLOCK(player);
8760         /* destroy the gst bus msg thread which is created during realize.
8761            this funct have to be called before getting cmd lock. */
8762         _mmplayer_bus_msg_thread_destroy(player);
8763         MMPLAYER_CMD_LOCK(player);
8764
8765         /* check current state */
8766         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8767
8768         /* check async state transition */
8769         __mmplayer_check_async_state_transition(player);
8770
8771         __mmplayer_unrealize_streaming_ext(player);
8772
8773         /* unrealize pipeline */
8774         ret = __gst_unrealize(player);
8775
8776         /* set asm stop if success */
8777         if (MM_ERROR_NONE == ret) {
8778                 if (!player->interrupted_by_resource) {
8779                         if (player->video_decoder_resource != NULL) {
8780                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8781                                                 player->video_decoder_resource);
8782                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8783                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8784                                 else
8785                                         player->video_decoder_resource = NULL;
8786                         }
8787
8788                         if (player->video_overlay_resource != NULL) {
8789                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8790                                                 player->video_overlay_resource);
8791                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8792                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8793                                 else
8794                                         player->video_overlay_resource = NULL;
8795                         }
8796
8797                         ret = mm_resource_manager_commit(player->resource_manager);
8798                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8799                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8800                 }
8801         } else
8802                 LOGE("failed and don't change asm state to stop");
8803
8804         MMPLAYER_FLEAVE();
8805
8806         return ret;
8807 }
8808
8809 int
8810 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8811 {
8812         mm_player_t* player = (mm_player_t*)hplayer;
8813
8814         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8815
8816         return __gst_set_message_callback(player, callback, user_param);
8817 }
8818
8819 int
8820 _mmplayer_get_state(MMHandleType hplayer, int* state)
8821 {
8822         mm_player_t *player = (mm_player_t*)hplayer;
8823
8824         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8825
8826         *state = MMPLAYER_CURRENT_STATE(player);
8827
8828         return MM_ERROR_NONE;
8829 }
8830
8831
8832 int
8833 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8834 {
8835         mm_player_t* player = (mm_player_t*) hplayer;
8836         GstElement* vol_element = NULL;
8837         int i = 0;
8838
8839         MMPLAYER_FENTER();
8840
8841         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8842
8843         LOGD("volume [L]=%f:[R]=%f\n",
8844                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8845
8846         /* invalid factor range or not */
8847         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8848                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8849                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8850                         return MM_ERROR_INVALID_ARGUMENT;
8851                 }
8852         }
8853
8854         /* not support to set other value into each channel */
8855         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8856                 return MM_ERROR_INVALID_ARGUMENT;
8857
8858         /* Save volume to handle. Currently the first array element will be saved. */
8859         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8860
8861         /* check pipeline handle */
8862         if (!player->pipeline || !player->pipeline->audiobin) {
8863                 LOGD("audiobin is not created yet\n");
8864                 LOGD("but, current stored volume will be set when it's created.\n");
8865
8866                 /* NOTE : stored volume will be used in create_audiobin
8867                  * returning MM_ERROR_NONE here makes application to able to
8868                  * set volume at anytime.
8869                  */
8870                 return MM_ERROR_NONE;
8871         }
8872
8873         /* setting volume to volume element */
8874         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8875
8876         if (vol_element) {
8877                 LOGD("volume is set [%f]\n", player->sound.volume);
8878                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8879         }
8880
8881         MMPLAYER_FLEAVE();
8882
8883         return MM_ERROR_NONE;
8884 }
8885
8886
8887 int
8888 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8889 {
8890         mm_player_t* player = (mm_player_t*) hplayer;
8891         int i = 0;
8892
8893         MMPLAYER_FENTER();
8894
8895         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8896         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8897
8898         /* returning stored volume */
8899         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8900                 volume->level[i] = player->sound.volume;
8901
8902         MMPLAYER_FLEAVE();
8903
8904         return MM_ERROR_NONE;
8905 }
8906
8907 int
8908 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8909 {
8910         mm_player_t* player = (mm_player_t*) hplayer;
8911         GstElement* vol_element = NULL;
8912
8913         MMPLAYER_FENTER();
8914
8915         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916
8917         /* mute value shoud 0 or 1 */
8918         if (mute != 0 && mute != 1) {
8919                 LOGE("bad mute value\n");
8920
8921                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8922                 return MM_ERROR_INVALID_ARGUMENT;
8923         }
8924
8925         player->sound.mute = mute;
8926
8927         /* just hold mute value if pipeline is not ready */
8928         if (!player->pipeline || !player->pipeline->audiobin) {
8929                 LOGD("pipeline is not ready. holding mute value\n");
8930                 return MM_ERROR_NONE;
8931         }
8932
8933         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8934
8935         /* NOTE : volume will only created when the bt is enabled */
8936         if (vol_element) {
8937                 LOGD("mute : %d\n", mute);
8938                 g_object_set(vol_element, "mute", mute, NULL);
8939         } else
8940                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8941
8942         MMPLAYER_FLEAVE();
8943
8944         return MM_ERROR_NONE;
8945 }
8946
8947 int
8948 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8949 {
8950         mm_player_t* player = (mm_player_t*) hplayer;
8951
8952         MMPLAYER_FENTER();
8953
8954         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8955         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8956
8957         /* just hold mute value if pipeline is not ready */
8958         if (!player->pipeline || !player->pipeline->audiobin) {
8959                 LOGD("pipeline is not ready. returning stored value\n");
8960                 *pmute = player->sound.mute;
8961                 return MM_ERROR_NONE;
8962         }
8963
8964         *pmute = player->sound.mute;
8965
8966         MMPLAYER_FLEAVE();
8967
8968         return MM_ERROR_NONE;
8969 }
8970
8971 int
8972 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8973 {
8974         mm_player_t* player = (mm_player_t*) hplayer;
8975
8976         MMPLAYER_FENTER();
8977
8978         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8979
8980         player->video_stream_changed_cb = callback;
8981         player->video_stream_changed_cb_user_param = user_param;
8982         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8983
8984         MMPLAYER_FLEAVE();
8985
8986         return MM_ERROR_NONE;
8987 }
8988
8989 int
8990 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8991 {
8992         mm_player_t* player = (mm_player_t*) hplayer;
8993
8994         MMPLAYER_FENTER();
8995
8996         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8997
8998         player->audio_stream_changed_cb = callback;
8999         player->audio_stream_changed_cb_user_param = user_param;
9000         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9001
9002         MMPLAYER_FLEAVE();
9003
9004         return MM_ERROR_NONE;
9005 }
9006
9007 int
9008 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9009 {
9010         mm_player_t* player = (mm_player_t*) hplayer;
9011
9012         MMPLAYER_FENTER();
9013
9014         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9015
9016         player->audio_stream_render_cb_ex = callback;
9017         player->audio_stream_cb_user_param = user_param;
9018         player->audio_stream_sink_sync = sync;
9019         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);
9020
9021         MMPLAYER_FLEAVE();
9022
9023         return MM_ERROR_NONE;
9024 }
9025
9026 int
9027 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9028 {
9029         mm_player_t* player = (mm_player_t*) hplayer;
9030
9031         MMPLAYER_FENTER();
9032
9033         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9034
9035         if (callback && !player->bufmgr)
9036                 player->bufmgr = tbm_bufmgr_init(-1);
9037
9038         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9039         player->video_stream_cb = callback;
9040         player->video_stream_cb_user_param = user_param;
9041
9042         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9043
9044         MMPLAYER_FLEAVE();
9045
9046         return MM_ERROR_NONE;
9047 }
9048
9049 int
9050 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9051 {
9052         mm_player_t* player = (mm_player_t*) hplayer;
9053
9054         MMPLAYER_FENTER();
9055
9056         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9057
9058         player->audio_stream_cb = callback;
9059         player->audio_stream_cb_user_param = user_param;
9060         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9061
9062         MMPLAYER_FLEAVE();
9063
9064         return MM_ERROR_NONE;
9065 }
9066
9067 static int
9068 __mmplayer_start_streaming_ext(mm_player_t *player)
9069 {
9070         gint ret = MM_ERROR_NONE;
9071
9072         MMPLAYER_FENTER();
9073         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9074
9075         if (MMPLAYER_IS_HTTP_PD(player)) {
9076                 if (!player->pd_downloader) {
9077                         ret = __mmplayer_realize_streaming_ext(player);
9078
9079                         if (ret != MM_ERROR_NONE) {
9080                                 LOGE("failed to realize streaming ext\n");
9081                                 return ret;
9082                         }
9083                 }
9084
9085                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9086                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9087                         if (!ret) {
9088                                 LOGE("ERROR while starting PD...\n");
9089                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9090                         }
9091                         ret = MM_ERROR_NONE;
9092                 }
9093         }
9094
9095         MMPLAYER_FLEAVE();
9096         return ret;
9097 }
9098
9099 int
9100 _mmplayer_start(MMHandleType hplayer)
9101 {
9102         mm_player_t* player = (mm_player_t*) hplayer;
9103         gint ret = MM_ERROR_NONE;
9104
9105         MMPLAYER_FENTER();
9106
9107         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9108
9109         /* check current state */
9110         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9111
9112         /* PD - start streaming */
9113         ret = __mmplayer_start_streaming_ext(player);
9114         if (ret != MM_ERROR_NONE) {
9115                 LOGE("failed to start streaming ext 0x%X", ret);
9116                 return ret;
9117         }
9118
9119         /* start pipeline */
9120         ret = __gst_start(player);
9121         if (ret != MM_ERROR_NONE)
9122                 LOGE("failed to start player.\n");
9123
9124         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9125                 LOGD("force playing start even during buffering");
9126                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9127         }
9128
9129         MMPLAYER_FLEAVE();
9130
9131         return ret;
9132 }
9133
9134 /* NOTE: post "not supported codec message" to application
9135  * when one codec is not found during AUTOPLUGGING in MSL.
9136  * So, it's separated with error of __mmplayer_gst_callback().
9137  * And, if any codec is not found, don't send message here.
9138  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9139  */
9140 int
9141 __mmplayer_handle_missed_plugin(mm_player_t* player)
9142 {
9143         MMMessageParamType msg_param;
9144         memset(&msg_param, 0, sizeof(MMMessageParamType));
9145         gboolean post_msg_direct = FALSE;
9146
9147         MMPLAYER_FENTER();
9148
9149         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9150
9151         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9152                         player->not_supported_codec, player->can_support_codec);
9153
9154         if (player->not_found_demuxer) {
9155                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9156                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9157
9158                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9159                 MMPLAYER_FREEIF(msg_param.data);
9160
9161                 return MM_ERROR_NONE;
9162         }
9163
9164         if (player->not_supported_codec) {
9165                 if (player->can_support_codec) {
9166                         // There is one codec to play
9167                         post_msg_direct = TRUE;
9168                 } else {
9169                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9170                                 post_msg_direct = TRUE;
9171                 }
9172
9173                 if (post_msg_direct) {
9174                         MMMessageParamType msg_param;
9175                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9176
9177                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9178                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9179
9180                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9181                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9182                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9183                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9184
9185                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9186                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9187                         }
9188
9189                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9190
9191                         MMPLAYER_FREEIF(msg_param.data);
9192
9193                         return MM_ERROR_NONE;
9194                 } else {
9195                         // no any supported codec case
9196                         LOGW("not found any codec, posting error code to application.\n");
9197
9198                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9199                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9200                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9201                         } else {
9202                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9203                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9204                         }
9205
9206                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9207
9208                         MMPLAYER_FREEIF(msg_param.data);
9209                 }
9210         }
9211
9212         MMPLAYER_FLEAVE();
9213
9214         return MM_ERROR_NONE;
9215 }
9216
9217 static void __mmplayer_check_pipeline(mm_player_t* player)
9218 {
9219         GstState element_state = GST_STATE_VOID_PENDING;
9220         GstState element_pending_state = GST_STATE_VOID_PENDING;
9221         gint timeout = 0;
9222         int ret = MM_ERROR_NONE;
9223
9224         if (player->gapless.reconfigure) {
9225                 LOGW("pipeline is under construction.\n");
9226
9227                 MMPLAYER_PLAYBACK_LOCK(player);
9228                 MMPLAYER_PLAYBACK_UNLOCK(player);
9229
9230                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9231
9232                 /* wait for state transition */
9233                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9234
9235                 if (ret == GST_STATE_CHANGE_FAILURE)
9236                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9237         }
9238 }
9239
9240 /* NOTE : it should be able to call 'stop' anytime*/
9241 int
9242 _mmplayer_stop(MMHandleType hplayer)
9243 {
9244         mm_player_t* player = (mm_player_t*)hplayer;
9245         int ret = MM_ERROR_NONE;
9246
9247         MMPLAYER_FENTER();
9248
9249         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9250
9251         /* check current state */
9252         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9253
9254         /* check pipline building state */
9255         __mmplayer_check_pipeline(player);
9256         __mmplayer_reset_gapless_state(player);
9257
9258         /* NOTE : application should not wait for EOS after calling STOP */
9259         __mmplayer_cancel_eos_timer(player);
9260
9261         __mmplayer_unrealize_streaming_ext(player);
9262
9263         /* reset */
9264         player->seek_state = MMPLAYER_SEEK_NONE;
9265
9266         /* stop pipeline */
9267         ret = __gst_stop(player);
9268
9269         if (ret != MM_ERROR_NONE)
9270                 LOGE("failed to stop player.\n");
9271
9272         MMPLAYER_FLEAVE();
9273
9274         return ret;
9275 }
9276
9277 int
9278 _mmplayer_pause(MMHandleType hplayer)
9279 {
9280         mm_player_t* player = (mm_player_t*)hplayer;
9281         gint64 pos_nsec = 0;
9282         gboolean async = FALSE;
9283         gint ret = MM_ERROR_NONE;
9284
9285         MMPLAYER_FENTER();
9286
9287         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9288
9289         /* check current state */
9290         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9291
9292         /* check pipline building state */
9293         __mmplayer_check_pipeline(player);
9294
9295         switch (MMPLAYER_CURRENT_STATE(player)) {
9296         case MM_PLAYER_STATE_READY:
9297                 {
9298                         /* check prepare async or not.
9299                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9300                          */
9301                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9302                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9303
9304                         /* Changing back sync of rtspsrc to async */
9305                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9306                                 LOGD("async prepare working mode for rtsp");
9307                                 async = TRUE;
9308                         }
9309                 }
9310                 break;
9311
9312         case MM_PLAYER_STATE_PLAYING:
9313                 {
9314                         /* NOTE : store current point to overcome some bad operation
9315                         *(returning zero when getting current position in paused state) of some
9316                         * elements
9317                         */
9318                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9319                                 LOGW("getting current position failed in paused\n");
9320
9321                         player->last_position = pos_nsec;
9322
9323                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9324                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9325                            This causes problem is position calculation during normal pause resume scenarios also.
9326                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9327                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9328                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9329                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9330                         }
9331                 }
9332                 break;
9333         }
9334
9335         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9336                 LOGD("doing async pause in case of ms buff src");
9337                 async = TRUE;
9338         }
9339
9340         /* pause pipeline */
9341         ret = __gst_pause(player, async);
9342
9343         if (ret != MM_ERROR_NONE)
9344                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9345
9346         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9347                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9348                         LOGE("failed to update display_rotation");
9349         }
9350
9351         MMPLAYER_FLEAVE();
9352
9353         return ret;
9354 }
9355
9356 int
9357 _mmplayer_resume(MMHandleType hplayer)
9358 {
9359         mm_player_t* player = (mm_player_t*)hplayer;
9360         int ret = MM_ERROR_NONE;
9361         gboolean async = FALSE;
9362
9363         MMPLAYER_FENTER();
9364
9365         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9366
9367         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9368                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
9369                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
9370                         return ret;
9371                 }
9372
9373                 /* Changing back sync mode rtspsrc to async */
9374                 LOGD("async resume for rtsp case");
9375                 async = TRUE;
9376         }
9377
9378         /* check current state */
9379         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9380
9381         ret = __gst_resume(player, async);
9382         if (ret != MM_ERROR_NONE)
9383                 LOGE("failed to resume player.\n");
9384
9385         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9386                 LOGD("force resume even during buffering");
9387                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9388         }
9389
9390         MMPLAYER_FLEAVE();
9391
9392         return ret;
9393 }
9394
9395 int
9396 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9397 {
9398         mm_player_t* player = (mm_player_t*)hplayer;
9399         gint64 pos_nsec = 0;
9400         int ret = MM_ERROR_NONE;
9401         int mute = FALSE;
9402         signed long long start = 0, stop = 0;
9403         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9404         MMPLAYER_FENTER();
9405
9406         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9407         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9408
9409         /* The sound of video is not supported under 0.0 and over 2.0. */
9410         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9411                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9412                         mute = TRUE;
9413         }
9414         _mmplayer_set_mute(hplayer, mute);
9415
9416         if (player->playback_rate == rate)
9417                 return MM_ERROR_NONE;
9418
9419         /* If the position is reached at start potion during fast backward, EOS is posted.
9420          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9421          * */
9422         player->playback_rate = rate;
9423
9424         current_state = MMPLAYER_CURRENT_STATE(player);
9425
9426         if (current_state != MM_PLAYER_STATE_PAUSED)
9427                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9428
9429         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9430
9431         if ((current_state == MM_PLAYER_STATE_PAUSED)
9432                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9433                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9434                 pos_nsec = player->last_position;
9435         }
9436
9437         if (rate >= 0) {
9438                 start = pos_nsec;
9439                 stop = GST_CLOCK_TIME_NONE;
9440         } else {
9441                 start = GST_CLOCK_TIME_NONE;
9442                 stop = pos_nsec;
9443         }
9444
9445         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9446                                 player->playback_rate,
9447                                 GST_FORMAT_TIME,
9448                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9449                                 GST_SEEK_TYPE_SET, start,
9450                                 GST_SEEK_TYPE_SET, stop)) {
9451                 LOGE("failed to set speed playback\n");
9452                 return MM_ERROR_PLAYER_SEEK;
9453         }
9454
9455         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9456
9457         MMPLAYER_FLEAVE();
9458
9459         return MM_ERROR_NONE;;
9460 }
9461
9462 int
9463 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9464 {
9465         mm_player_t* player = (mm_player_t*)hplayer;
9466         int ret = MM_ERROR_NONE;
9467
9468         MMPLAYER_FENTER();
9469
9470         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9471
9472         /* check pipline building state */
9473         __mmplayer_check_pipeline(player);
9474
9475         ret = __gst_set_position(player, format, position, FALSE);
9476
9477         MMPLAYER_FLEAVE();
9478
9479         return ret;
9480 }
9481
9482 int
9483 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9484 {
9485         mm_player_t* player = (mm_player_t*)hplayer;
9486         int ret = MM_ERROR_NONE;
9487
9488         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9489
9490         ret = __gst_get_position(player, format, position);
9491
9492         return ret;
9493 }
9494
9495 int
9496 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9497 {
9498         mm_player_t* player = (mm_player_t*)hplayer;
9499         int ret = MM_ERROR_NONE;
9500
9501         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9502         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9503
9504         *duration = player->duration;
9505         return ret;
9506 }
9507
9508 int
9509 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9510 {
9511         mm_player_t* player = (mm_player_t*)hplayer;
9512         int ret = MM_ERROR_NONE;
9513
9514         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9515
9516         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9517
9518         return ret;
9519 }
9520
9521 int
9522 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9523 {
9524         mm_player_t* player = (mm_player_t*)hplayer;
9525         int ret = MM_ERROR_NONE;
9526
9527         MMPLAYER_FENTER();
9528
9529         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9530
9531         ret = __gst_adjust_subtitle_position(player, format, position);
9532
9533         MMPLAYER_FLEAVE();
9534
9535         return ret;
9536 }
9537
9538 static gboolean
9539 __mmplayer_is_midi_type(gchar* str_caps)
9540 {
9541         if ((g_strrstr(str_caps, "audio/midi")) ||
9542                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9543                 (g_strrstr(str_caps, "application/x-smaf")) ||
9544                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9545                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9546                 (g_strrstr(str_caps, "audio/xmf")) ||
9547                 (g_strrstr(str_caps, "audio/mxmf"))) {
9548                 LOGD("midi\n");
9549                 return TRUE;
9550         }
9551
9552         return FALSE;
9553 }
9554
9555 static gboolean
9556 __mmplayer_is_only_mp3_type(gchar *str_caps)
9557 {
9558         if (g_strrstr(str_caps, "application/x-id3") ||
9559                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9560                 return TRUE;
9561         return FALSE;
9562 }
9563
9564 static void
9565 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9566 {
9567         GstStructure* caps_structure = NULL;
9568         gint samplerate = 0;
9569         gint channels = 0;
9570
9571         MMPLAYER_FENTER();
9572         MMPLAYER_RETURN_IF_FAIL(player && caps);
9573
9574         caps_structure = gst_caps_get_structure(caps, 0);
9575
9576         /* set stream information */
9577         gst_structure_get_int(caps_structure, "rate", &samplerate);
9578         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9579
9580         gst_structure_get_int(caps_structure, "channels", &channels);
9581         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9582
9583         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9584 }
9585
9586 static void
9587 __mmplayer_update_content_type_info(mm_player_t* player)
9588 {
9589         MMPLAYER_FENTER();
9590         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9591
9592         if (__mmplayer_is_midi_type(player->type)) {
9593                 player->bypass_audio_effect = TRUE;
9594         } else if (g_strrstr(player->type, "application/x-hls")) {
9595                 /* If it can't know exact type when it parses uri because of redirection case,
9596                  * it will be fixed by typefinder or when doing autoplugging.
9597                  */
9598                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9599                 if (player->streamer) {
9600                         player->streamer->is_adaptive_streaming = TRUE;
9601                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9602                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9603                 }
9604         } else if (g_strrstr(player->type, "application/dash+xml")) {
9605                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9606                 if (player->streamer) {
9607                         player->streamer->is_adaptive_streaming = TRUE;
9608                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9609                 }
9610         }
9611
9612         LOGD("uri type : %d", player->profile.uri_type);
9613         MMPLAYER_FLEAVE();
9614 }
9615
9616 static void
9617 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9618 GstCaps *caps, gpointer data)
9619 {
9620         mm_player_t* player = (mm_player_t*)data;
9621         GstPad* pad = NULL;
9622
9623         MMPLAYER_FENTER();
9624
9625         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9626
9627         /* store type string */
9628         MMPLAYER_FREEIF(player->type);
9629         player->type = gst_caps_to_string(caps);
9630         if (player->type) {
9631                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9632                                 player, player->type, probability, gst_caps_get_size(caps));
9633         }
9634
9635         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9636                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9637                 LOGE("not support media format\n");
9638
9639                 if (player->msg_posted == FALSE) {
9640                         MMMessageParamType msg_param;
9641                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9642
9643                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9644                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9645
9646                         /* don't post more if one was sent already */
9647                         player->msg_posted = TRUE;
9648                 }
9649                 return;
9650         }
9651
9652         __mmplayer_update_content_type_info(player);
9653
9654         pad = gst_element_get_static_pad(tf, "src");
9655         if (!pad) {
9656                 LOGE("fail to get typefind src pad.\n");
9657                 return;
9658         }
9659
9660         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9661                 gboolean async = FALSE;
9662                 LOGE("failed to autoplug %s\n", player->type);
9663
9664                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9665
9666                 if (async && player->msg_posted == FALSE)
9667                         __mmplayer_handle_missed_plugin(player);
9668
9669                 goto DONE;
9670         }
9671
9672 DONE:
9673         gst_object_unref(GST_OBJECT(pad));
9674
9675         MMPLAYER_FLEAVE();
9676
9677         return;
9678 }
9679
9680 static GstElement *
9681 __mmplayer_create_decodebin(mm_player_t* player)
9682 {
9683         GstElement *decodebin = NULL;
9684
9685         MMPLAYER_FENTER();
9686
9687         /* create decodebin */
9688         decodebin = gst_element_factory_make("decodebin", NULL);
9689
9690         if (!decodebin) {
9691                 LOGE("fail to create decodebin\n");
9692                 goto ERROR;
9693         }
9694
9695         /* raw pad handling signal */
9696         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9697                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9698
9699         /* no-more-pad pad handling signal */
9700         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9701                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9702
9703         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9704                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9705
9706         /* This signal is emitted when a pad for which there is no further possible
9707            decoding is added to the decodebin.*/
9708         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9709                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9710
9711         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9712            before looking for any elements that can handle that stream.*/
9713         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9714                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9715
9716         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9717            before looking for any elements that can handle that stream.*/
9718         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9719                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9720
9721         /* This signal is emitted once decodebin has finished decoding all the data.*/
9722         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9723                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9724
9725         /* This signal is emitted when a element is added to the bin.*/
9726         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9727                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9728
9729 ERROR:
9730         return decodebin;
9731 }
9732
9733 static gboolean
9734 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9735 {
9736         MMPlayerGstElement* mainbin = NULL;
9737         GstElement* decodebin = NULL;
9738         GstElement* queue2 = NULL;
9739         GstPad* sinkpad = NULL;
9740         GstPad* qsrcpad = NULL;
9741         gint64 dur_bytes = 0L;
9742
9743         guint max_buffer_size_bytes = 0;
9744         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9745
9746         MMPLAYER_FENTER();
9747         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9748
9749         mainbin = player->pipeline->mainbin;
9750
9751         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9752                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9753                 LOGD("creating http streaming buffering queue(queue2)\n");
9754
9755                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9756                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9757                 } else {
9758                         queue2 = gst_element_factory_make("queue2", "queue2");
9759                         if (!queue2) {
9760                                 LOGE("failed to create buffering queue element\n");
9761                                 goto ERROR;
9762                         }
9763
9764                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9765                                 LOGE("failed to add buffering queue\n");
9766                                 goto ERROR;
9767                         }
9768
9769                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9770                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9771
9772                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9773                                 LOGE("failed to link buffering queue");
9774                                 goto ERROR;
9775                         }
9776
9777                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9778                                 LOGE("fail to get duration");
9779
9780                         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9781
9782                         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9783
9784                         if (dur_bytes > 0) {
9785                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9786                                         type = MUXED_BUFFER_TYPE_FILE;
9787                                 } else {
9788                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9789                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9790                                 }
9791                         } else {
9792                                 dur_bytes = 0;
9793                         }
9794
9795                         /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9796                          *        skip the pull mode(file or ring buffering) setting. */
9797                         if (!g_strrstr(player->type, "video/mpegts")) {
9798                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9799                                 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9800
9801                                 __mm_player_streaming_set_queue2(player->streamer,
9802                                                                                                 queue2,
9803                                                                                                 FALSE,
9804                                                                                                 max_buffer_size_bytes,
9805                                                                                                 player->ini.http_buffering_time,
9806                                                                                                 1.0,                                /* no meaning */
9807                                                                                                 player->ini.http_buffering_limit,   /* no meaning */
9808                                                                                                 type,
9809                                                                                                 player->http_file_buffering_path,
9810                                                                                                 (guint64)dur_bytes);
9811                         }
9812
9813                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9814                                 LOGE("failed to sync queue2 state with parent\n");
9815                                 goto ERROR;
9816                         }
9817
9818                         srcpad = qsrcpad;
9819
9820                         gst_object_unref(GST_OBJECT(sinkpad));
9821
9822                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9823                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9824                 }
9825         }
9826
9827         /* create decodebin */
9828         decodebin = __mmplayer_create_decodebin(player);
9829
9830         if (!decodebin) {
9831                 LOGE("can not create autoplug element\n");
9832                 goto ERROR;
9833         }
9834
9835         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9836                 LOGE("failed to add decodebin\n");
9837                 goto ERROR;
9838         }
9839
9840         /* to force caps on the decodebin element and avoid reparsing stuff by
9841         * typefind. It also avoids a deadlock in the way typefind activates pads in
9842         * the state change */
9843         g_object_set(decodebin, "sink-caps", caps, NULL);
9844
9845         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9846
9847         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9848                 LOGE("failed to link decodebin\n");
9849                 goto ERROR;
9850         }
9851
9852         gst_object_unref(GST_OBJECT(sinkpad));
9853
9854         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9855         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9856
9857         /* set decodebin property about buffer in streaming playback. *
9858          * in case of HLS/DASH, it does not need to have big buffer   *
9859          * because it is kind of adaptive streaming.                  */
9860         if (!MMPLAYER_IS_HTTP_PD(player) &&
9861             (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9862             gdouble high_percent = 0.0;
9863
9864                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9865                 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9866
9867                 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9868                         GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9869
9870                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9871                                                                                         "high-percent", (gint)high_percent,
9872                                                                                         "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9873                                                                                         "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9874                                                                                         "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9875                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9876         }
9877
9878         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9879                 LOGE("failed to sync decodebin state with parent\n");
9880                 goto ERROR;
9881         }
9882
9883         MMPLAYER_FLEAVE();
9884
9885         return TRUE;
9886
9887 ERROR:
9888
9889         if (sinkpad)
9890                 gst_object_unref(GST_OBJECT(sinkpad));
9891
9892         if (queue2) {
9893                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9894                  * You need to explicitly set elements to the NULL state before
9895                  * dropping the final reference, to allow them to clean up.
9896                  */
9897                 gst_element_set_state(queue2, GST_STATE_NULL);
9898
9899                 /* And, it still has a parent "player".
9900                  * You need to let the parent manage the object instead of unreffing the object directly.
9901                  */
9902                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9903                 gst_object_unref(queue2);
9904                 queue2 = NULL;
9905         }
9906
9907         if (decodebin) {
9908                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9909                  * You need to explicitly set elements to the NULL state before
9910                  * dropping the final reference, to allow them to clean up.
9911                  */
9912                 gst_element_set_state(decodebin, GST_STATE_NULL);
9913
9914                 /* And, it still has a parent "player".
9915                  * You need to let the parent manage the object instead of unreffing the object directly.
9916                  */
9917
9918                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9919                 gst_object_unref(decodebin);
9920                 decodebin = NULL;
9921         }
9922
9923         return FALSE;
9924 }
9925
9926 static int
9927 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9928 {
9929         MMPLAYER_FENTER();
9930
9931         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9932         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9933
9934         LOGD("class : %s, mime : %s \n", factory_class, mime);
9935
9936         /* add missing plugin */
9937         /* NOTE : msl should check missing plugin for image mime type.
9938          * Some motion jpeg clips can have playable audio track.
9939          * So, msl have to play audio after displaying popup written video format not supported.
9940          */
9941         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9942                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9943                         LOGD("not found demuxer\n");
9944                         player->not_found_demuxer = TRUE;
9945                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9946
9947                         goto DONE;
9948                 }
9949         }
9950
9951         if (!g_strrstr(factory_class, "Demuxer")) {
9952                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9953                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9954                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9955
9956                         /* check that clip have multi tracks or not */
9957                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9958                                 LOGD("video plugin is already linked\n");
9959                         } else {
9960                                 LOGW("add VIDEO to missing plugin\n");
9961                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9962                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9963                         }
9964                 } else if (g_str_has_prefix(mime, "audio")) {
9965                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9966                                 LOGD("audio plugin is already linked\n");
9967                         } else {
9968                                 LOGW("add AUDIO to missing plugin\n");
9969                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9970                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9971                         }
9972                 }
9973         }
9974
9975 DONE:
9976         MMPLAYER_FLEAVE();
9977
9978         return MM_ERROR_NONE;
9979 }
9980
9981
9982 static void
9983 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
9984 {
9985         mm_player_t* player = (mm_player_t*)data;
9986
9987         MMPLAYER_FENTER();
9988
9989         MMPLAYER_RETURN_IF_FAIL(player);
9990
9991         /* remove fakesink. */
9992         if (!__mmplayer_gst_remove_fakesink(player,
9993                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9994                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9995                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9996                  * source element are not same. To overcome this situation, this function will called
9997                  * several places and several times. Therefore, this is not an error case.
9998                  */
9999                 return;
10000         }
10001
10002         LOGD("[handle: %p] pipeline has completely constructed", player);
10003
10004         if ((player->ini.async_start) &&
10005                 (player->msg_posted == FALSE) &&
10006                 (player->cmd >= MMPLAYER_COMMAND_START))
10007                 __mmplayer_handle_missed_plugin(player);
10008
10009         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10010 }
10011
10012 static gboolean
10013 __mmplayer_verify_next_play_path(mm_player_t *player)
10014 {
10015         MMHandleType attrs = 0;
10016         MMPlayerParseProfile profile;
10017         gint uri_idx = 0, check_cnt = 0;
10018         char *uri = NULL;
10019         gint mode = MM_PLAYER_PD_MODE_NONE;
10020         gint video = 0;
10021         gint count = 0;
10022         gint gapless = 0;
10023         guint num_of_list = 0;
10024         static int profile_tv = -1;
10025
10026         MMPLAYER_FENTER();
10027
10028         LOGD("checking for gapless play");
10029
10030         if (player->pipeline->textbin) {
10031                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10032                 goto ERROR;
10033         }
10034
10035         attrs = MMPLAYER_GET_ATTRS(player);
10036         if (!attrs) {
10037                 LOGE("fail to get attributes.\n");
10038                 goto ERROR;
10039         }
10040
10041         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10042
10043         if (__builtin_expect(profile_tv == -1, 0)) {
10044                 char *profileName;
10045                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10046                 switch (*profileName) {
10047                 case 't':
10048                 case 'T':
10049                         profile_tv = 1;
10050                         break;
10051                 default:
10052                         profile_tv = 0;
10053                 }
10054                 free(profileName);
10055         }
10056         /* gapless playback is not supported in case of video at TV profile. */
10057         if (profile_tv && video) {
10058                 LOGW("not support video gapless playback");
10059                 goto ERROR;
10060         }
10061
10062         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10063                 if (mode == TRUE) {
10064                         LOGW("pd mode\n");
10065                         goto ERROR;
10066                 }
10067         }
10068
10069         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10070                 LOGE("can not get play count\n");
10071
10072         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10073                 LOGE("can not get gapless mode\n");
10074
10075         if (video && !gapless) {
10076                 LOGW("not enabled video gapless playback");
10077                 goto ERROR;
10078         }
10079
10080         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10081                 gapless = 1;
10082
10083         if (!gapless) {
10084                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10085                 goto ERROR;
10086         }
10087
10088         num_of_list = g_list_length(player->uri_info.uri_list);
10089
10090         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10091
10092         if (num_of_list == 0) {
10093                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10094                         LOGE("can not get profile_uri\n");
10095                         goto ERROR;
10096                 }
10097
10098                 if (!uri) {
10099                         LOGE("uri list is empty.\n");
10100                         goto ERROR;
10101                 }
10102
10103                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10104                 LOGD("add original path : %s ", uri);
10105
10106                 num_of_list = 1;
10107                 uri = NULL;
10108         }
10109
10110         uri_idx = player->uri_info.uri_idx;
10111
10112         while (TRUE) {
10113                 check_cnt++;
10114
10115                 if (check_cnt > num_of_list) {
10116                         LOGE("there is no valid uri.");
10117                         goto ERROR;
10118                 }
10119
10120                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10121
10122                 if (uri_idx < num_of_list-1) {
10123                         uri_idx++;
10124                 } else {
10125                         if ((count <= 1) && (count != -1)) {
10126                                 LOGD("no repeat.");
10127                                 goto ERROR;
10128                         } else if (count > 1) {
10129                                 /* decrease play count */
10130                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10131                                 count--;
10132
10133                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10134
10135                                 /* commit attribute */
10136                                 if (mmf_attrs_commit(attrs))
10137                                         LOGE("failed to commit attribute\n");
10138                         }
10139
10140                         /* count < 0 : repeat continually */
10141                         uri_idx = 0;
10142                 }
10143
10144                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10145                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10146
10147                 if (uri == NULL) {
10148                         LOGW("next uri does not exist\n");
10149                         continue;
10150                 }
10151
10152                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10153                         LOGE("failed to parse profile\n");
10154                         continue;
10155                 }
10156
10157                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10158                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10159                         LOGW("uri type is not supported(%d).", profile.uri_type);
10160                         continue;
10161                 }
10162
10163                 break;
10164         }
10165
10166         player->uri_info.uri_idx = uri_idx;
10167         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10168
10169         if (mmf_attrs_commit(player->attrs)) {
10170                 LOGE("failed to commit.\n");
10171                 goto ERROR;
10172         }
10173
10174         LOGD("next uri %s(%d)\n", uri, uri_idx);
10175
10176         return TRUE;
10177
10178 ERROR:
10179
10180         LOGE("unable to play next path. EOS will be posted soon.\n");
10181         return FALSE;
10182 }
10183
10184 static void
10185 __mmplayer_initialize_next_play(mm_player_t *player)
10186 {
10187         int i;
10188
10189         MMPLAYER_FENTER();
10190
10191         player->smooth_streaming = FALSE;
10192         player->videodec_linked = 0;
10193         player->audiodec_linked = 0;
10194         player->videosink_linked = 0;
10195         player->audiosink_linked = 0;
10196         player->textsink_linked = 0;
10197         player->is_external_subtitle_present = FALSE;
10198         player->is_external_subtitle_added_now = FALSE;
10199         player->not_supported_codec = MISSING_PLUGIN_NONE;
10200         player->can_support_codec = FOUND_PLUGIN_NONE;
10201         player->pending_seek.is_pending = FALSE;
10202         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10203         player->pending_seek.pos = 0;
10204         player->msg_posted = FALSE;
10205         player->has_many_types = FALSE;
10206         player->no_more_pad = FALSE;
10207         player->not_found_demuxer = 0;
10208         player->seek_state = MMPLAYER_SEEK_NONE;
10209         player->max_audio_channels = 0;
10210         player->is_subtitle_force_drop = FALSE;
10211         player->play_subtitle = FALSE;
10212         player->adjust_subtitle_pos = 0;
10213
10214         player->total_bitrate = 0;
10215         player->total_maximum_bitrate = 0;
10216
10217         _mmplayer_track_initialize(player);
10218         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10219
10220         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10221                 player->bitrate[i] = 0;
10222                 player->maximum_bitrate[i] = 0;
10223         }
10224
10225         if (player->v_stream_caps) {
10226                 gst_caps_unref(player->v_stream_caps);
10227                 player->v_stream_caps = NULL;
10228         }
10229
10230         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10231
10232         /* clean found parsers */
10233         if (player->parsers) {
10234                 GList *parsers = player->parsers;
10235                 for (; parsers; parsers = g_list_next(parsers)) {
10236                         gchar *name = parsers->data;
10237                         MMPLAYER_FREEIF(name);
10238                 }
10239                 g_list_free(player->parsers);
10240                 player->parsers = NULL;
10241         }
10242
10243         /* clean found audio decoders */
10244         if (player->audio_decoders) {
10245                 GList *a_dec = player->audio_decoders;
10246                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10247                         gchar *name = a_dec->data;
10248                         MMPLAYER_FREEIF(name);
10249                 }
10250                 g_list_free(player->audio_decoders);
10251                 player->audio_decoders = NULL;
10252         }
10253
10254         MMPLAYER_FLEAVE();
10255 }
10256
10257 static void
10258 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10259 {
10260         MMPlayerGstElement *mainbin = NULL;
10261         MMMessageParamType msg_param = {0,};
10262         GstElement *element = NULL;
10263         MMHandleType attrs = 0;
10264         char *uri = NULL;
10265         enum MainElementID elemId = MMPLAYER_M_NUM;
10266
10267         MMPLAYER_FENTER();
10268
10269         if ((player == NULL) ||
10270                 (player->pipeline == NULL) ||
10271                 (player->pipeline->mainbin == NULL)) {
10272                 LOGE("player is null.\n");
10273                 goto ERROR;
10274         }
10275
10276         mainbin = player->pipeline->mainbin;
10277         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10278
10279         attrs = MMPLAYER_GET_ATTRS(player);
10280         if (!attrs) {
10281                 LOGE("fail to get attributes.\n");
10282                 goto ERROR;
10283         }
10284
10285         /* Initialize Player values */
10286         __mmplayer_initialize_next_play(player);
10287
10288         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10289
10290         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10291                 LOGE("failed to parse profile\n");
10292                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10293                 goto ERROR;
10294         }
10295
10296         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10297                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10298                 LOGE("it's dash or hls. not support.");
10299                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10300                 goto ERROR;
10301         }
10302
10303         /* setup source */
10304         switch (player->profile.uri_type) {
10305         /* file source */
10306         case MM_PLAYER_URI_TYPE_FILE:
10307         {
10308                 LOGD("using filesrc for 'file://' handler.\n");
10309                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10310                         LOGE("failed to get storage info");
10311                         break;
10312                 }
10313
10314                 element = gst_element_factory_make("filesrc", "source");
10315
10316                 if (!element) {
10317                         LOGE("failed to create filesrc\n");
10318                         break;
10319                 }
10320
10321                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10322                 break;
10323         }
10324         case MM_PLAYER_URI_TYPE_URL_HTTP:
10325         {
10326                 gchar *user_agent, *cookies, **cookie_list;
10327                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10328                 user_agent = cookies = NULL;
10329                 cookie_list = NULL;
10330
10331                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10332                 if (!element) {
10333                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10334                         break;
10335                 }
10336                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10337
10338                 /* get attribute */
10339                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10340                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10341
10342                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10343                         LOGD("get timeout from ini\n");
10344                         http_timeout = player->ini.http_timeout;
10345                 }
10346
10347                 /* get attribute */
10348                 SECURE_LOGD("location : %s\n", player->profile.uri);
10349                 SECURE_LOGD("cookies : %s\n", cookies);
10350                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10351                 LOGD("timeout : %d\n", http_timeout);
10352
10353                 /* setting property to streaming source */
10354                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10355                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10356                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10357
10358                 /* parsing cookies */
10359                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10360                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10361                 if (user_agent)
10362                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10363                 break;
10364         }
10365         default:
10366                 LOGE("not support uri type %d\n", player->profile.uri_type);
10367                 break;
10368         }
10369
10370         if (!element) {
10371                 LOGE("no source element was created.\n");
10372                 goto ERROR;
10373         }
10374
10375         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10376                 LOGE("failed to add source element to pipeline\n");
10377                 gst_object_unref(GST_OBJECT(element));
10378                 element = NULL;
10379                 goto ERROR;
10380         }
10381
10382         /* take source element */
10383         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10384         mainbin[MMPLAYER_M_SRC].gst = element;
10385
10386         element = NULL;
10387
10388         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10389                 if (player->streamer == NULL) {
10390                         player->streamer = __mm_player_streaming_create();
10391                         __mm_player_streaming_initialize(player->streamer);
10392                 }
10393
10394                 elemId = MMPLAYER_M_TYPEFIND;
10395                 element = gst_element_factory_make("typefind", "typefinder");
10396                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10397                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10398         } else {
10399                 elemId = MMPLAYER_M_AUTOPLUG;
10400                 element = __mmplayer_create_decodebin(player);
10401         }
10402
10403         /* check autoplug element is OK */
10404         if (!element) {
10405                 LOGE("can not create element(%d)\n", elemId);
10406                 goto ERROR;
10407         }
10408
10409         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10410                 LOGE("failed to add sinkbin to pipeline\n");
10411                 gst_object_unref(GST_OBJECT(element));
10412                 element = NULL;
10413                 goto ERROR;
10414         }
10415
10416         mainbin[elemId].id = elemId;
10417         mainbin[elemId].gst = element;
10418
10419         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10420                 LOGE("Failed to link src - autoplug(or typefind)\n");
10421                 goto ERROR;
10422         }
10423
10424         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10425                 LOGE("Failed to change state of src element\n");
10426                 goto ERROR;
10427         }
10428
10429         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10430                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10431                         LOGE("Failed to change state of decodebin\n");
10432                         goto ERROR;
10433                 }
10434         } else {
10435                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10436                         LOGE("Failed to change state of src element\n");
10437                         goto ERROR;
10438                 }
10439         }
10440
10441         player->gapless.stream_changed = TRUE;
10442         player->gapless.running = TRUE;
10443         MMPLAYER_FLEAVE();
10444         return;
10445
10446 ERROR:
10447         if (player) {
10448                 MMPLAYER_PLAYBACK_UNLOCK(player);
10449
10450                 if (!player->msg_posted) {
10451                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10452                         player->msg_posted = TRUE;
10453                 }
10454         }
10455         return;
10456 }
10457
10458 static gboolean
10459 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10460 {
10461         mm_player_selector_t *selector = &player->selector[type];
10462         MMPlayerGstElement *sinkbin = NULL;
10463         enum MainElementID selectorId = MMPLAYER_M_NUM;
10464         enum MainElementID sinkId = MMPLAYER_M_NUM;
10465         GstPad *srcpad = NULL;
10466         GstPad *sinkpad = NULL;
10467         gboolean send_notice = FALSE;
10468
10469         MMPLAYER_FENTER();
10470         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10471
10472         LOGD("type %d", type);
10473
10474         switch (type) {
10475         case MM_PLAYER_TRACK_TYPE_AUDIO:
10476                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10477                 sinkId = MMPLAYER_A_BIN;
10478                 sinkbin = player->pipeline->audiobin;
10479                 break;
10480         case MM_PLAYER_TRACK_TYPE_VIDEO:
10481                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10482                 sinkId = MMPLAYER_V_BIN;
10483                 sinkbin = player->pipeline->videobin;
10484                 send_notice = TRUE;
10485                 break;
10486         case MM_PLAYER_TRACK_TYPE_TEXT:
10487                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10488                 sinkId = MMPLAYER_T_BIN;
10489                 sinkbin = player->pipeline->textbin;
10490                 break;
10491         default:
10492                 LOGE("requested type is not supportable");
10493                 return FALSE;
10494                 break;
10495         }
10496
10497         if (player->pipeline->mainbin[selectorId].gst) {
10498                 gint n;
10499
10500                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10501
10502                 if (selector->event_probe_id != 0)
10503                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10504                 selector->event_probe_id = 0;
10505
10506                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10507                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10508
10509                         if (srcpad && sinkpad) {
10510                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10511                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10512                                 gst_pad_unlink(srcpad, sinkpad);
10513
10514                                 /* send custom event to sink pad to handle it at video sink */
10515                                 if (send_notice) {
10516                                         LOGD("send custom event to sinkpad");
10517                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10518                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10519                                         gst_pad_send_event(sinkpad, event);
10520                                 }
10521                         }
10522
10523                         gst_object_unref(sinkpad);
10524                         sinkpad = NULL;
10525                 }
10526                 gst_object_unref(srcpad);
10527                 srcpad = NULL;
10528
10529                 LOGD("selector release");
10530
10531                 /* release and unref requests pad from the selector */
10532                 for (n = 0; n < selector->channels->len; n++) {
10533                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10534                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10535                 }
10536                 g_ptr_array_set_size(selector->channels, 0);
10537
10538                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10539                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10540
10541                 player->pipeline->mainbin[selectorId].gst = NULL;
10542                 selector = NULL;
10543         }
10544
10545         return TRUE;
10546 }
10547
10548 static void
10549 __mmplayer_deactivate_old_path(mm_player_t *player)
10550 {
10551         MMPLAYER_FENTER();
10552         MMPLAYER_RETURN_IF_FAIL(player);
10553
10554         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10555                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10556                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10557                 LOGE("deactivate selector error");
10558                 goto ERROR;
10559         }
10560
10561         _mmplayer_track_destroy(player);
10562         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10563
10564         if (player->streamer) {
10565                 __mm_player_streaming_deinitialize(player->streamer);
10566                 __mm_player_streaming_destroy(player->streamer);
10567                 player->streamer = NULL;
10568         }
10569
10570         MMPLAYER_PLAYBACK_LOCK(player);
10571         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10572
10573         MMPLAYER_FLEAVE();
10574         return;
10575
10576 ERROR:
10577
10578         if (!player->msg_posted) {
10579                 MMMessageParamType msg = {0,};
10580
10581                 /*post error*/
10582                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10583                 LOGE("next_uri_play> deactivate error");
10584
10585                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10586                 player->msg_posted = TRUE;
10587         }
10588         return;
10589 }
10590
10591 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10592 {
10593         int result = MM_ERROR_NONE;
10594         mm_player_t* player = (mm_player_t*) hplayer;
10595         MMPLAYER_FENTER();
10596
10597         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10598
10599         if (file_path) {
10600                 player->http_file_buffering_path = (gchar*)file_path;
10601                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10602         }
10603         MMPLAYER_FLEAVE();
10604         return result;
10605 }
10606
10607 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10608 {
10609         int result = MM_ERROR_NONE;
10610         mm_player_t* player = (mm_player_t*) hplayer;
10611         MMPLAYER_FENTER();
10612
10613         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10614
10615         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10616         if (mmf_attrs_commit(player->attrs)) {
10617                 LOGE("failed to commit the original uri.\n");
10618                 result = MM_ERROR_PLAYER_INTERNAL;
10619         } else {
10620                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10621                         LOGE("failed to add the original uri in the uri list.\n");
10622         }
10623
10624         MMPLAYER_FLEAVE();
10625         return result;
10626 }
10627
10628 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10629 {
10630         mm_player_t* player = (mm_player_t*) hplayer;
10631         guint num_of_list = 0;
10632
10633         MMPLAYER_FENTER();
10634
10635         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10636         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10637
10638         if (player->pipeline && player->pipeline->textbin) {
10639                 LOGE("subtitle path is enabled.\n");
10640                 return MM_ERROR_PLAYER_INVALID_STATE;
10641         }
10642
10643         num_of_list = g_list_length(player->uri_info.uri_list);
10644
10645         if (is_first_path == TRUE) {
10646                 if (num_of_list == 0) {
10647                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10648                         LOGD("add original path : %s", uri);
10649                 } else {
10650                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10651                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10652
10653                         LOGD("change original path : %s", uri);
10654                 }
10655         } else {
10656                 MMHandleType attrs = 0;
10657                 attrs = MMPLAYER_GET_ATTRS(player);
10658
10659                 if (num_of_list == 0) {
10660                         char *original_uri = NULL;
10661
10662                         if (attrs) {
10663                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10664
10665                                 if (!original_uri) {
10666                                         LOGE("there is no original uri.");
10667                                         return MM_ERROR_PLAYER_INVALID_STATE;
10668                                 }
10669
10670                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10671                                 player->uri_info.uri_idx = 0;
10672
10673                                 LOGD("add original path at first : %s(%d)", original_uri);
10674                         }
10675                 }
10676
10677                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10678                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10679         }
10680
10681         MMPLAYER_FLEAVE();
10682         return MM_ERROR_NONE;
10683 }
10684
10685 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10686 {
10687         mm_player_t* player = (mm_player_t*) hplayer;
10688         char *next_uri = NULL;
10689         guint num_of_list = 0;
10690
10691         MMPLAYER_FENTER();
10692         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10693
10694         num_of_list = g_list_length(player->uri_info.uri_list);
10695
10696         if (num_of_list > 0) {
10697                 gint uri_idx = player->uri_info.uri_idx;
10698
10699                 if (uri_idx < num_of_list-1)
10700                         uri_idx++;
10701                 else
10702                         uri_idx = 0;
10703
10704                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10705                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10706
10707                 *uri = g_strdup(next_uri);
10708         }
10709
10710         MMPLAYER_FLEAVE();
10711         return MM_ERROR_NONE;
10712 }
10713
10714 static void
10715 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10716 GstCaps *caps, gpointer data)
10717 {
10718         mm_player_t* player = (mm_player_t*)data;
10719         const gchar* klass = NULL;
10720         const gchar* mime = NULL;
10721         gchar* caps_str = NULL;
10722
10723         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10724         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10725         caps_str = gst_caps_to_string(caps);
10726
10727         LOGW("unknown type of caps : %s from %s",
10728                                         caps_str, GST_ELEMENT_NAME(elem));
10729
10730         MMPLAYER_FREEIF(caps_str);
10731
10732         /* There is no available codec. */
10733         __mmplayer_check_not_supported_codec(player, klass, mime);
10734 }
10735
10736 static gboolean
10737 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10738 GstCaps * caps,  gpointer data)
10739 {
10740         mm_player_t* player = (mm_player_t*)data;
10741         const char* mime = NULL;
10742         gboolean ret = TRUE;
10743
10744         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10745         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10746
10747         if (g_str_has_prefix(mime, "audio")) {
10748                 GstStructure* caps_structure = NULL;
10749                 gint samplerate = 0;
10750                 gint channels = 0;
10751                 gchar *caps_str = NULL;
10752
10753                 caps_structure = gst_caps_get_structure(caps, 0);
10754                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10755                 gst_structure_get_int(caps_structure, "channels", &channels);
10756
10757                 if ((channels > 0 && samplerate == 0)) {
10758                         LOGD("exclude audio...");
10759                         ret = FALSE;
10760                 }
10761
10762                 caps_str = gst_caps_to_string(caps);
10763                 /* set it directly because not sent by TAG */
10764                 if (g_strrstr(caps_str, "mobile-xmf"))
10765                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10766                 MMPLAYER_FREEIF(caps_str);
10767         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10768                 MMMessageParamType msg_param;
10769                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10770                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10771                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10772                 LOGD("video file is not supported on this device");
10773                 ret = FALSE;
10774         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10775                 LOGD("already video linked");
10776                 ret = FALSE;
10777         } else {
10778                 LOGD("found new stream");
10779         }
10780
10781         return ret;
10782 }
10783
10784 static int
10785 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10786 {
10787         int ret = MM_ERROR_NONE;
10788         int idx = 0;
10789         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10790
10791         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10792                 GstStructure* str = NULL;
10793                 gint channels = 0;
10794                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10795
10796                 LOGD("audio codec type: %d", codec_type);
10797                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10798                         /* sw codec will be skipped */
10799                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10800                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10801                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10802                                         ret = MM_ERROR_PLAYER_INTERNAL;
10803                                         goto DONE;
10804                                 }
10805                         }
10806                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10807                         /* hw codec will be skipped */
10808                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10809                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10810                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10811                                 ret = MM_ERROR_PLAYER_INTERNAL;
10812                                 goto DONE;
10813                         }
10814                 }
10815
10816                 str = gst_caps_get_structure(caps, 0);
10817                 if (str) {
10818                         gst_structure_get_int(str, "channels", &channels);
10819
10820                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10821                         if (player->max_audio_channels < channels)
10822                                 player->max_audio_channels = channels;
10823                 }
10824                 /* set stream information */
10825                 if (!player->audiodec_linked)
10826                         __mmplayer_set_audio_attrs(player, caps);
10827
10828                 /* update codec info */
10829                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10830                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10831                 player->audiodec_linked = 1;
10832
10833         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10834
10835                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10836
10837                 LOGD("video codec type: %d", codec_type);
10838                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10839                         /* sw codec is skipped */
10840                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10841                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10842                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10843                                         ret = MM_ERROR_PLAYER_INTERNAL;
10844                                         goto DONE;
10845                                 }
10846                         }
10847                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10848                         /* hw codec is skipped */
10849                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10850                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10851                                 ret = MM_ERROR_PLAYER_INTERNAL;
10852                                 goto DONE;
10853                         }
10854                 }
10855
10856                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10857                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10858
10859                         /* mark video decoder for acquire */
10860                         if (player->video_decoder_resource == NULL) {
10861                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10862                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10863                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10864                                                 &player->video_decoder_resource)
10865                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10866                                         LOGE("could not mark video_decoder resource for acquire");
10867                                         ret = MM_ERROR_PLAYER_INTERNAL;
10868                                         goto DONE;
10869                                 }
10870                         } else {
10871                                 LOGW("video decoder resource is already acquired, skip it.");
10872                                 ret = MM_ERROR_PLAYER_INTERNAL;
10873                                 goto DONE;
10874                         }
10875
10876                         player->interrupted_by_resource = FALSE;
10877                         /* acquire resources for video playing */
10878                         if (mm_resource_manager_commit(player->resource_manager)
10879                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10880                                 LOGE("could not acquire resources for video decoding\n");
10881                                 ret = MM_ERROR_PLAYER_INTERNAL;
10882                                 goto DONE;
10883                         }
10884                 }
10885
10886                 /* update codec info */
10887                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10888                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10889                 player->videodec_linked = 1;
10890         }
10891
10892 DONE:
10893         return ret;
10894 }
10895
10896 static gint
10897 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10898 GstCaps* caps, GstElementFactory* factory, gpointer data)
10899 {
10900         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10901          We are defining our own and will be removed when it actually exposed */
10902         typedef enum {
10903                 GST_AUTOPLUG_SELECT_TRY,
10904                 GST_AUTOPLUG_SELECT_EXPOSE,
10905                 GST_AUTOPLUG_SELECT_SKIP
10906         } GstAutoplugSelectResult;
10907
10908         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10909         mm_player_t* player = (mm_player_t*)data;
10910
10911         gchar* factory_name = NULL;
10912         gchar* caps_str = NULL;
10913         const gchar* klass = NULL;
10914         gint idx = 0;
10915
10916         factory_name = GST_OBJECT_NAME(factory);
10917         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10918         caps_str = gst_caps_to_string(caps);
10919
10920         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10921
10922         /* store type string */
10923         if (player->type == NULL) {
10924                 player->type = gst_caps_to_string(caps);
10925                 __mmplayer_update_content_type_info(player);
10926         }
10927
10928         /* filtering exclude keyword */
10929         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10930                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10931                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10932                                         factory_name, player->ini.exclude_element_keyword[idx]);
10933
10934                         result = GST_AUTOPLUG_SELECT_SKIP;
10935                         goto DONE;
10936                 }
10937         }
10938
10939         /* exclude webm format */
10940         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10941          * because webm format is not supportable.
10942          * If webm is disabled in "autoplug-continue", there is no state change
10943          * failure or error because the decodebin will expose the pad directly.
10944          * It make MSL invoke _prepare_async_callback.
10945          * So, we need to disable webm format in "autoplug-select" */
10946         if (caps_str && strstr(caps_str, "webm")) {
10947                 LOGW("webm is not supported");
10948                 result = GST_AUTOPLUG_SELECT_SKIP;
10949                 goto DONE;
10950         }
10951
10952         /* check factory class for filtering */
10953         /* NOTE : msl don't need to use image plugins.
10954          * So, those plugins should be skipped for error handling.
10955          */
10956         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10957                 LOGD("skipping [%s] by not required\n", factory_name);
10958                 result = GST_AUTOPLUG_SELECT_SKIP;
10959                 goto DONE;
10960         }
10961
10962         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10963                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10964                 // TO CHECK : subtitle if needed, add subparse exception.
10965                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10966                 result = GST_AUTOPLUG_SELECT_SKIP;
10967                 goto DONE;
10968         }
10969
10970         if (g_strrstr(factory_name, "mpegpsdemux")) {
10971                 LOGD("skipping PS container - not support\n");
10972                 result = GST_AUTOPLUG_SELECT_SKIP;
10973                 goto DONE;
10974         }
10975
10976         if (g_strrstr(factory_name, "mssdemux"))
10977                 player->smooth_streaming = TRUE;
10978
10979         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10980                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10981                 gint stype = 0;
10982                 gint width = 0;
10983                 GstStructure *str = NULL;
10984                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10985
10986                 /* don't make video because of not required */
10987                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10988                         (player->set_mode.media_packet_video_stream == FALSE)) {
10989                         LOGD("no video because it's not required. -> return expose");
10990                         result = GST_AUTOPLUG_SELECT_EXPOSE;
10991                         goto DONE;
10992                 }
10993
10994                 /* get w/h for omx state-tune */
10995                 /* FIXME: deprecated? */
10996                 str = gst_caps_get_structure(caps, 0);
10997                 gst_structure_get_int(str, "width", &width);
10998
10999                 if (width != 0) {
11000                         if (player->v_stream_caps) {
11001                                 gst_caps_unref(player->v_stream_caps);
11002                                 player->v_stream_caps = NULL;
11003                         }
11004
11005                         player->v_stream_caps = gst_caps_copy(caps);
11006                         LOGD("take caps for video state tune");
11007                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11008                 }
11009         }
11010
11011         if (g_strrstr(klass, "Codec/Decoder")) {
11012                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11013                         LOGD("skipping %s codec", factory_name);
11014                         result = GST_AUTOPLUG_SELECT_SKIP;
11015                         goto DONE;
11016                 }
11017         }
11018
11019 DONE:
11020         MMPLAYER_FREEIF(caps_str);
11021
11022         return result;
11023 }
11024
11025 static void
11026 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11027 gpointer data)
11028 {
11029         //mm_player_t* player = (mm_player_t*)data;
11030         GstCaps* caps = NULL;
11031
11032         LOGD("[Decodebin2] pad-removed signal\n");
11033
11034         caps = gst_pad_query_caps(new_pad, NULL);
11035         if (caps) {
11036                 gchar* caps_str = NULL;
11037                 caps_str = gst_caps_to_string(caps);
11038
11039                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11040
11041                 MMPLAYER_FREEIF(caps_str);
11042                 gst_caps_unref(caps);
11043         }
11044 }
11045
11046 static void
11047 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11048 {
11049         mm_player_t* player = (mm_player_t*)data;
11050         GstIterator *iter = NULL;
11051         GValue item = { 0, };
11052         GstPad *pad = NULL;
11053         gboolean done = FALSE;
11054         gboolean is_all_drained = TRUE;
11055
11056         MMPLAYER_FENTER();
11057         MMPLAYER_RETURN_IF_FAIL(player);
11058
11059         LOGD("__mmplayer_gst_decode_drained");
11060
11061         if (player->use_deinterleave == TRUE) {
11062                 LOGD("group playing mode.");
11063                 return;
11064         }
11065
11066         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11067                 LOGW("Fail to get cmd lock");
11068                 return;
11069         }
11070
11071         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11072                 !__mmplayer_verify_next_play_path(player)) {
11073                 LOGD("decoding is finished.");
11074                 __mmplayer_reset_gapless_state(player);
11075                 MMPLAYER_CMD_UNLOCK(player);
11076                 return;
11077         }
11078
11079         player->gapless.reconfigure = TRUE;
11080
11081         /* check decodebin src pads whether they received EOS or not */
11082         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11083
11084         while (!done) {
11085                 switch (gst_iterator_next(iter, &item)) {
11086                 case GST_ITERATOR_OK:
11087                         pad = g_value_get_object(&item);
11088                         if (pad && !GST_PAD_IS_EOS(pad)) {
11089                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11090                                 is_all_drained = FALSE;
11091                                 break;
11092                         }
11093                         g_value_reset(&item);
11094                         break;
11095                 case GST_ITERATOR_RESYNC:
11096                         gst_iterator_resync(iter);
11097                         break;
11098                 case GST_ITERATOR_ERROR:
11099                 case GST_ITERATOR_DONE:
11100                         done = TRUE;
11101                         break;
11102                 }
11103         }
11104         g_value_unset(&item);
11105         gst_iterator_free(iter);
11106
11107         if (!is_all_drained) {
11108                 LOGD("Wait util the all pads get EOS.");
11109                 MMPLAYER_CMD_UNLOCK(player);
11110                 MMPLAYER_FLEAVE();
11111                 return;
11112         }
11113
11114         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11115         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11116
11117         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11118         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11119         __mmplayer_deactivate_old_path(player);
11120         MMPLAYER_CMD_UNLOCK(player);
11121
11122         MMPLAYER_FLEAVE();
11123 }
11124
11125 static void
11126 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11127 {
11128         mm_player_t* player = (mm_player_t*)data;
11129         const gchar* klass = NULL;
11130         gchar* factory_name = NULL;
11131
11132         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11133         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11134
11135         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11136
11137         if (__mmplayer_add_dump_buffer_probe(player, element))
11138                 LOGD("add buffer probe");
11139
11140         //<-
11141         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11142                 gchar* selected = NULL;
11143                 selected = g_strdup(GST_ELEMENT_NAME(element));
11144                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11145         }
11146         //-> temp code
11147
11148         if (g_strrstr(klass, "Parser")) {
11149                 gchar* selected = NULL;
11150
11151                 selected = g_strdup(factory_name);
11152                 player->parsers = g_list_append(player->parsers, selected);
11153         }
11154
11155         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11156                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11157                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11158
11159                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11160                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11161
11162                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11163                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11164                                                 "max-video-width", player->adaptive_info.limit.width,
11165                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11166
11167         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11168                 /* FIXIT : first value will be overwritten if there's more
11169                  * than 1 demuxer/parser
11170                  */
11171
11172                 //LOGD("plugged element is demuxer. take it\n");
11173                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11174                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11175
11176                 /*Added for multi audio support */ // Q. del?
11177                 if (g_strrstr(klass, "Demux")) {
11178                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11179                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11180                 }
11181         }
11182
11183         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11184                 int surface_type = 0;
11185
11186                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11187         }
11188
11189         // to support trust-zone only
11190         if (g_strrstr(factory_name, "asfdemux")) {
11191                 LOGD("set file-location %s\n", player->profile.uri);
11192                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11193
11194                 if (player->video_hub_download_mode == TRUE)
11195                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11196         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11197                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11198                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11199         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11200                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11201                         (__mmplayer_is_only_mp3_type(player->type))) {
11202                         LOGD("[mpegaudioparse] set streaming pull mode.");
11203                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11204                 }
11205         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11206                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11207         }
11208
11209         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11210                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11211                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11212
11213                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11214                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11215
11216                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11217                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11218                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11219                         (MMPLAYER_IS_DASH_STREAMING(player)))) {
11220                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11221                         __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11222                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11223                 }
11224
11225         }
11226
11227         return;
11228 }
11229
11230 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11231 {
11232         MMPLAYER_FENTER();
11233         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11234
11235         if (MMPLAYER_IS_STREAMING(player))
11236                 return FALSE;
11237
11238         /* This callback can be set to music player only. */
11239         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11240                 LOGW("audio callback is not supported for video");
11241                 return FALSE;
11242         }
11243
11244         if (player->audio_stream_cb) {
11245                 GstPad *pad = NULL;
11246
11247                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11248
11249                 if (!pad) {
11250                         LOGE("failed to get sink pad from audiosink to probe data\n");
11251                         return FALSE;
11252                 }
11253                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11254                         __mmplayer_audio_stream_probe, player, NULL);
11255
11256                 gst_object_unref(pad);
11257
11258                 pad = NULL;
11259         } else {
11260                 LOGE("There is no audio callback to configure.\n");
11261                 return FALSE;
11262         }
11263
11264         MMPLAYER_FLEAVE();
11265
11266         return TRUE;
11267 }
11268
11269 static void
11270 __mmplayer_release_misc(mm_player_t* player)
11271 {
11272         int i;
11273         bool cur_mode = player->set_mode.rich_audio;
11274         MMPLAYER_FENTER();
11275
11276         MMPLAYER_RETURN_IF_FAIL(player);
11277
11278         player->video_stream_cb = NULL;
11279         player->video_stream_cb_user_param = NULL;
11280         player->video_stream_prerolled = FALSE;
11281
11282         player->audio_stream_cb = NULL;
11283         player->audio_stream_render_cb_ex = NULL;
11284         player->audio_stream_cb_user_param = NULL;
11285         player->audio_stream_sink_sync = false;
11286
11287         player->video_stream_changed_cb = NULL;
11288         player->video_stream_changed_cb_user_param = NULL;
11289
11290         player->audio_stream_changed_cb = NULL;
11291         player->audio_stream_changed_cb_user_param = NULL;
11292
11293         player->sent_bos = FALSE;
11294         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11295
11296         player->seek_state = MMPLAYER_SEEK_NONE;
11297
11298         player->total_bitrate = 0;
11299         player->total_maximum_bitrate = 0;
11300
11301         player->not_found_demuxer = 0;
11302
11303         player->last_position = 0;
11304         player->duration = 0;
11305         player->http_content_size = 0;
11306         player->not_supported_codec = MISSING_PLUGIN_NONE;
11307         player->can_support_codec = FOUND_PLUGIN_NONE;
11308         player->pending_seek.is_pending = FALSE;
11309         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11310         player->pending_seek.pos = 0;
11311         player->msg_posted = FALSE;
11312         player->has_many_types = FALSE;
11313         player->max_audio_channels = 0;
11314         player->video_share_api_delta = 0;
11315         player->video_share_clock_delta = 0;
11316         player->is_subtitle_force_drop = FALSE;
11317         player->play_subtitle = FALSE;
11318         player->adjust_subtitle_pos = 0;
11319         player->last_multiwin_status = FALSE;
11320         player->has_closed_caption = FALSE;
11321         player->set_mode.media_packet_video_stream = FALSE;
11322         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11323         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11324         /* recover mode */
11325         player->set_mode.rich_audio = cur_mode;
11326
11327         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11328                 player->bitrate[i] = 0;
11329                 player->maximum_bitrate[i] = 0;
11330         }
11331
11332         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11333
11334         /* remove media stream cb(appsrc cb) */
11335         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11336                 player->media_stream_buffer_status_cb[i] = NULL;
11337                 player->media_stream_seek_data_cb[i] = NULL;
11338                 player->buffer_cb_user_param[i] = NULL;
11339                 player->seek_cb_user_param[i] = NULL;
11340         }
11341         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11342
11343         /* free memory related to audio effect */
11344         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11345
11346         if (player->adaptive_info.var_list) {
11347                 g_list_free_full(player->adaptive_info.var_list, g_free);
11348                 player->adaptive_info.var_list = NULL;
11349         }
11350
11351         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11352         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11353         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11354
11355         /* Reset video360 settings to their defaults in case if the pipeline is to be
11356          * re-created.
11357          * */
11358         player->video360_metadata.is_spherical = -1;
11359         player->is_openal_plugin_used = FALSE;
11360
11361         player->is_content_spherical = FALSE;
11362         player->is_video360_enabled = TRUE;
11363         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11364         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11365         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11366         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11367         player->video360_zoom = 1.0f;
11368         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11369         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11370
11371         player->sound.rg_enable = false;
11372
11373         MMPLAYER_FLEAVE();
11374 }
11375
11376 static void
11377 __mmplayer_release_misc_post(mm_player_t* player)
11378 {
11379         char *original_uri = NULL;
11380         MMPLAYER_FENTER();
11381
11382         /* player->pipeline is already released before. */
11383
11384         MMPLAYER_RETURN_IF_FAIL(player);
11385
11386         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11387
11388         /* clean found parsers */
11389         if (player->parsers) {
11390                 GList *parsers = player->parsers;
11391                 for (; parsers; parsers = g_list_next(parsers)) {
11392                         gchar *name = parsers->data;
11393                         MMPLAYER_FREEIF(name);
11394                 }
11395                 g_list_free(player->parsers);
11396                 player->parsers = NULL;
11397         }
11398
11399         /* clean found audio decoders */
11400         if (player->audio_decoders) {
11401                 GList *a_dec = player->audio_decoders;
11402                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11403                         gchar *name = a_dec->data;
11404                         MMPLAYER_FREEIF(name);
11405                 }
11406                 g_list_free(player->audio_decoders);
11407                 player->audio_decoders = NULL;
11408         }
11409
11410         /* clean the uri list except original uri */
11411         if (player->uri_info.uri_list) {
11412                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11413
11414                 if (player->attrs) {
11415                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11416                         LOGD("restore original uri = %s\n", original_uri);
11417
11418                         if (mmf_attrs_commit(player->attrs))
11419                                 LOGE("failed to commit the original uri.\n");
11420                 }
11421
11422                 GList *uri_list = player->uri_info.uri_list;
11423                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11424                         gchar *uri = uri_list->data;
11425                         MMPLAYER_FREEIF(uri);
11426                 }
11427                 g_list_free(player->uri_info.uri_list);
11428                 player->uri_info.uri_list = NULL;
11429         }
11430
11431         /* clear the audio stream buffer list */
11432         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11433
11434         /* clear the video stream bo list */
11435         __mmplayer_video_stream_destroy_bo_list(player);
11436         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11437
11438         if (player->profile.input_mem.buf) {
11439                 free(player->profile.input_mem.buf);
11440                 player->profile.input_mem.buf = NULL;
11441         }
11442         player->profile.input_mem.len = 0;
11443         player->profile.input_mem.offset = 0;
11444
11445         player->uri_info.uri_idx = 0;
11446         MMPLAYER_FLEAVE();
11447 }
11448
11449 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11450 {
11451         GstElement *element = NULL;
11452         GstPad *sinkpad;
11453
11454         LOGD("creating %s to plug\n", name);
11455
11456         element = gst_element_factory_make(name, NULL);
11457         if (!element) {
11458                 LOGE("failed to create queue\n");
11459                 return NULL;
11460         }
11461
11462         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11463                 LOGE("failed to set state READY to %s\n", name);
11464                 gst_object_unref(element);
11465                 return NULL;
11466         }
11467
11468         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11469                 LOGE("failed to add %s\n", name);
11470                 gst_object_unref(element);
11471                 return NULL;
11472         }
11473
11474         sinkpad = gst_element_get_static_pad(element, "sink");
11475
11476         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11477                 LOGE("failed to link %s\n", name);
11478                 gst_object_unref(sinkpad);
11479                 gst_object_unref(element);
11480                 return NULL;
11481         }
11482
11483         LOGD("linked %s to pipeline successfully\n", name);
11484
11485         gst_object_unref(sinkpad);
11486
11487         return element;
11488 }
11489
11490 gboolean
11491 __mmplayer_check_subtitle(mm_player_t* player)
11492 {
11493         MMHandleType attrs = 0;
11494         char *subtitle_uri = NULL;
11495
11496         MMPLAYER_FENTER();
11497
11498         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11499
11500         /* get subtitle attribute */
11501         attrs = MMPLAYER_GET_ATTRS(player);
11502         if (!attrs)
11503                 return FALSE;
11504
11505         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11506         if (!subtitle_uri || !strlen(subtitle_uri))
11507                 return FALSE;
11508
11509         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11510         player->is_external_subtitle_present = TRUE;
11511
11512         MMPLAYER_FLEAVE();
11513
11514         return TRUE;
11515 }
11516
11517 static gboolean
11518 __mmplayer_can_extract_pcm(mm_player_t* player)
11519 {
11520         MMHandleType attrs = 0;
11521         gboolean sound_extraction = FALSE;
11522
11523         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11524
11525         attrs = MMPLAYER_GET_ATTRS(player);
11526         if (!attrs) {
11527                 LOGE("fail to get attributes.");
11528                 return FALSE;
11529         }
11530
11531         /* get sound_extraction property */
11532         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11533
11534         if (!sound_extraction) {
11535                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11536                 return FALSE;
11537         }
11538
11539         return TRUE;
11540 }
11541
11542 static gboolean
11543 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11544 {
11545         LOGD("\n");
11546         MMMessageParamType msg_param;
11547         gchar *msg_src_element = NULL;
11548         GstStructure *s = NULL;
11549         guint error_id = 0;
11550         gchar *error_string = NULL;
11551
11552         MMPLAYER_FENTER();
11553
11554         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11555         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11556
11557         s = gst_structure_copy(gst_message_get_structure(message));
11558
11559
11560         if (!gst_structure_get_uint(s, "error_id", &error_id))
11561                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11562
11563         switch (error_id) {
11564         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11565                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11566                 break;
11567         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11568                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11569                 break;
11570         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11571                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11572                 break;
11573         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11574                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11575                 break;
11576         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11577                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11578                 break;
11579         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11580                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11581                 break;
11582         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11583                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11584                 break;
11585         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11586                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11587                 break;
11588         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11589                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11590                 break;
11591         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11592                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11593                 break;
11594         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11595                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11596                 break;
11597         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11598                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11599                 break;
11600         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11601                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11602                 break;
11603         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11604                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11605                 break;
11606         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11607                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11608                 break;
11609         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11610                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11611                 break;
11612         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11613                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11614                 break;
11615         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11616                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11617                 break;
11618         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11619                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11620                 break;
11621         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11622                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11623                 break;
11624         case MMPLAYER_STREAMING_ERROR_GONE:
11625                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11626                 break;
11627         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11628                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11629                 break;
11630         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11631                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11632                 break;
11633         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11634                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11635                 break;
11636         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11637                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11638                 break;
11639         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11640                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11641                 break;
11642         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11643                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11644                 break;
11645         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11646                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11647                 break;
11648         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11649                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11650                 break;
11651         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11652                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11653                 break;
11654         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11655                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11656                 break;
11657         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11658                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11659                 break;
11660         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11661                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11662                 break;
11663         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11664                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11665                 break;
11666         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11667                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11668                 break;
11669         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11670                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11671                 break;
11672         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11673                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11674                 break;
11675         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11676                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11677                 break;
11678         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11679                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11680                 break;
11681         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11682                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11683                 break;
11684         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11685                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11686                 break;
11687         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11688                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11689                 break;
11690         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11691                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11692                 break;
11693         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11694                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11695                 break;
11696         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11697                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11698                 break;
11699         default:
11700                 {
11701                         gst_structure_free(s);
11702                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11703                 }
11704         }
11705
11706         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11707         if (error_string)
11708                 msg_param.data = (void *) error_string;
11709
11710         if (message->src) {
11711                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11712
11713                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11714                         msg_src_element, msg_param.code, (char*)msg_param.data);
11715         }
11716
11717         /* post error to application */
11718         if (!player->msg_posted) {
11719                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11720
11721                 /* don't post more if one was sent already */
11722                 player->msg_posted = TRUE;
11723         } else
11724                 LOGD("skip error post because it's sent already.\n");
11725
11726         gst_structure_free(s);
11727         MMPLAYER_FLEAVE();
11728         g_free(error_string);
11729
11730         return TRUE;
11731
11732 }
11733
11734 static void
11735 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11736 {
11737         MMPLAYER_RETURN_IF_FAIL(player);
11738
11739         /* post now if delay is zero */
11740         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11741                 LOGD("eos delay is zero. posting EOS now\n");
11742                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11743
11744                 if (player->set_mode.pcm_extraction)
11745                         __mmplayer_cancel_eos_timer(player);
11746
11747                 return;
11748         }
11749
11750         /* cancel if existing */
11751         __mmplayer_cancel_eos_timer(player);
11752
11753         /* init new timeout */
11754         /* NOTE : consider give high priority to this timer */
11755         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11756
11757         player->eos_timer = g_timeout_add(delay_in_ms,
11758                 __mmplayer_eos_timer_cb, player);
11759
11760         player->context.global_default = g_main_context_default();
11761         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11762
11763         /* check timer is valid. if not, send EOS now */
11764         if (player->eos_timer == 0) {
11765                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11766                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11767         }
11768 }
11769
11770 static void
11771 __mmplayer_cancel_eos_timer(mm_player_t* player)
11772 {
11773         MMPLAYER_RETURN_IF_FAIL(player);
11774
11775         if (player->eos_timer) {
11776                 LOGD("cancel eos timer");
11777                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11778                 player->eos_timer = 0;
11779         }
11780
11781         return;
11782 }
11783
11784 static gboolean
11785 __mmplayer_eos_timer_cb(gpointer u_data)
11786 {
11787         mm_player_t* player = NULL;
11788         MMHandleType attrs = 0;
11789         int count = 0;
11790
11791         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11792
11793         player = (mm_player_t*) u_data;
11794         attrs = MMPLAYER_GET_ATTRS(player);
11795
11796         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11797
11798         if (count == -1) {
11799                 gint ret_value = 0;
11800                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11801                 if (ret_value != MM_ERROR_NONE)
11802                         LOGE("seeking to 0 failed in repeat play");
11803         } else {
11804                 /* posting eos */
11805                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11806         }
11807
11808         /* we are returning FALSE as we need only one posting */
11809         return FALSE;
11810 }
11811
11812 /* sending event to one of sinkelements */
11813 static gboolean
11814 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11815 {
11816         GstEvent * event2 = NULL;
11817         GList *sinks = NULL;
11818         gboolean res = FALSE;
11819         MMPLAYER_FENTER();
11820
11821         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11822         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11823
11824         /* While adding subtitles in live feeds seek is getting called.
11825            Adding defensive check in framework layer.*/
11826         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11827                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11828                         LOGE("Should not send seek event during live playback");
11829                         return TRUE;
11830                 }
11831         }
11832
11833         if (player->play_subtitle)
11834                 event2 = gst_event_copy((const GstEvent *)event);
11835
11836         sinks = player->sink_elements;
11837         while (sinks) {
11838                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11839
11840                 if (GST_IS_ELEMENT(sink)) {
11841                         /* keep ref to the event */
11842                         gst_event_ref(event);
11843
11844                         if ((res = gst_element_send_event(sink, event))) {
11845                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11846                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11847
11848                                 /* rtsp case, asyn_done is not called after seek during pause state */
11849                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11850                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11851                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11852                                                         LOGD("RTSP seek completed, after pause state..\n");
11853                                                         player->seek_state = MMPLAYER_SEEK_NONE;
11854                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11855                                                 }
11856
11857                                         }
11858                                 }
11859
11860                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11861                                         sinks = g_list_next(sinks);
11862                                         continue;
11863                                 } else {
11864                                         break;
11865                                 }
11866                         }
11867
11868                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11869                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11870                 }
11871
11872                 sinks = g_list_next(sinks);
11873         }
11874
11875         /* Note : Textbin is not linked to the video or audio bin.
11876          * It needs to send the event to the text sink seperatelly.
11877          */
11878          if (player->play_subtitle && player->pipeline) {
11879                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11880
11881                 if (GST_IS_ELEMENT(text_sink)) {
11882                         /* keep ref to the event */
11883                         gst_event_ref(event2);
11884
11885                         if ((res = gst_element_send_event(text_sink, event2)))
11886                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11887                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11888                         else
11889                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11890                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11891
11892                         gst_event_unref(event2);
11893                 }
11894          }
11895
11896         gst_event_unref(event);
11897
11898         MMPLAYER_FLEAVE();
11899
11900         return res;
11901 }
11902
11903 static void
11904 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11905 {
11906         MMPLAYER_FENTER();
11907
11908         MMPLAYER_RETURN_IF_FAIL(player);
11909         MMPLAYER_RETURN_IF_FAIL(sink);
11910
11911         player->sink_elements =
11912                 g_list_append(player->sink_elements, sink);
11913
11914         MMPLAYER_FLEAVE();
11915 }
11916
11917 static void
11918 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11919 {
11920         MMPLAYER_FENTER();
11921
11922         MMPLAYER_RETURN_IF_FAIL(player);
11923         MMPLAYER_RETURN_IF_FAIL(sink);
11924
11925         player->sink_elements =
11926                         g_list_remove(player->sink_elements, sink);
11927
11928         MMPLAYER_FLEAVE();
11929 }
11930
11931 static gboolean
11932 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11933                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11934                         gint64 cur, GstSeekType stop_type, gint64 stop)
11935 {
11936         GstEvent* event = NULL;
11937         gboolean result = FALSE;
11938
11939         MMPLAYER_FENTER();
11940
11941         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11942
11943         if (player->pipeline && player->pipeline->textbin)
11944                 __mmplayer_drop_subtitle(player, FALSE);
11945
11946         event = gst_event_new_seek(rate, format, flags, cur_type,
11947                 cur, stop_type, stop);
11948
11949         result = __gst_send_event_to_sink(player, event);
11950
11951         MMPLAYER_FLEAVE();
11952
11953         return result;
11954 }
11955
11956 /* NOTE : be careful with calling this api. please refer to below glib comment
11957  * glib comment : Note that there is a bug in GObject that makes this function much
11958  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11959  * will no longer be called, but, the signal handler is not currently disconnected.
11960  * If the instance is itself being freed at the same time than this doesn't matter,
11961  * since the signal will automatically be removed, but if instance persists,
11962  * then the signal handler will leak. You should not remove the signal yourself
11963  * because in a future versions of GObject, the handler will automatically be
11964  * disconnected.
11965  *
11966  * It's possible to work around this problem in a way that will continue to work
11967  * with future versions of GObject by checking that the signal handler is still
11968  * connected before disconnected it:
11969  *
11970  *  if (g_signal_handler_is_connected(instance, id))
11971  *    g_signal_handler_disconnect(instance, id);
11972  */
11973 static void
11974 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11975 {
11976         GList* sig_list = NULL;
11977         MMPlayerSignalItem* item = NULL;
11978
11979         MMPLAYER_FENTER();
11980
11981         MMPLAYER_RETURN_IF_FAIL(player);
11982
11983         LOGD("release signals type : %d", type);
11984
11985         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11986                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11987                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11988                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11989                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11990                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11991                 return;
11992         }
11993
11994         sig_list = player->signals[type];
11995
11996         for (; sig_list; sig_list = sig_list->next) {
11997                 item = sig_list->data;
11998
11999                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12000                         if (g_signal_handler_is_connected(item->obj, item->sig))
12001                                 g_signal_handler_disconnect(item->obj, item->sig);
12002                 }
12003
12004                 MMPLAYER_FREEIF(item);
12005         }
12006
12007         g_list_free(player->signals[type]);
12008         player->signals[type] = NULL;
12009
12010         MMPLAYER_FLEAVE();
12011
12012         return;
12013 }
12014
12015 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12016 {
12017         mm_player_t* player = 0;
12018         int prev_display_surface_type = 0;
12019         void *prev_display_overlay = NULL;
12020         const gchar *klass = NULL;
12021         gchar *cur_videosink_name = NULL;
12022         int ret = 0;
12023         int i = 0;
12024         int num_of_dec = 2; /* DEC1, DEC2 */
12025
12026         MMPLAYER_FENTER();
12027
12028         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12029         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12030
12031         player = MM_PLAYER_CAST(handle);
12032
12033         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12034                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12035                 MMPLAYER_FLEAVE();
12036                 return MM_ERROR_INVALID_ARGUMENT;
12037         }
12038
12039         /* load previous attributes */
12040         if (player->attrs) {
12041                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12042                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12043                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12044                 if (prev_display_surface_type == surface_type) {
12045                         LOGD("incoming display surface type is same as previous one, do nothing..");
12046                         MMPLAYER_FLEAVE();
12047                         return MM_ERROR_NONE;
12048                 }
12049         } else {
12050                 LOGE("failed to load attributes");
12051                 MMPLAYER_FLEAVE();
12052                 return MM_ERROR_PLAYER_INTERNAL;
12053         }
12054
12055         /* check videosink element is created */
12056         if (!player->pipeline || !player->pipeline->videobin ||
12057                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12058                 LOGD("videosink element is not yet ready");
12059
12060                 /* videobin is not created yet, so we just set attributes related to display surface */
12061                 LOGD("store display attribute for given surface type(%d)", surface_type);
12062                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12063                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12064                 if (mmf_attrs_commit(player->attrs)) {
12065                         LOGE("failed to commit attribute");
12066                         MMPLAYER_FLEAVE();
12067                         return MM_ERROR_PLAYER_INTERNAL;
12068                 }
12069                 MMPLAYER_FLEAVE();
12070                 return MM_ERROR_NONE;
12071         } else {
12072                 /* get player command status */
12073                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12074                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12075                         MMPLAYER_FLEAVE();
12076                         return MM_ERROR_PLAYER_INVALID_STATE;
12077                 }
12078
12079                 /* surface change */
12080                 for (i = 0 ; i < num_of_dec ; i++) {
12081                         if (player->pipeline->mainbin &&
12082                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12083                                 GstElementFactory *decfactory;
12084                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12085
12086                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12087                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12088                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12089                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12090                                                 if (ret) {
12091                                                         goto ERROR_CASE;
12092                                                 } else {
12093                                                         LOGW("success to changing display surface(%d)", surface_type);
12094                                                         MMPLAYER_FLEAVE();
12095                                                         return MM_ERROR_NONE;
12096                                                 }
12097                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12098                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12099                                                 if (ret) {
12100                                                         goto ERROR_CASE;
12101                                                 } else {
12102                                                         LOGW("success to changing display surface(%d)", surface_type);
12103                                                         MMPLAYER_FLEAVE();
12104                                                         return MM_ERROR_NONE;
12105                                                 }
12106                                         } else {
12107                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12108                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12109                                                 goto ERROR_CASE;
12110                                         }
12111                                 }
12112                         }
12113                 }
12114         }
12115
12116 ERROR_CASE:
12117         /* rollback to previous attributes */
12118         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12119         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12120         if (mmf_attrs_commit(player->attrs)) {
12121                 LOGE("failed to commit attributes to rollback");
12122                 MMPLAYER_FLEAVE();
12123                 return MM_ERROR_PLAYER_INTERNAL;
12124         }
12125         MMPLAYER_FLEAVE();
12126         return ret;
12127 }
12128
12129 /* NOTE : It does not support some use cases, eg using colorspace converter */
12130 int
12131 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12132 {
12133         GstPad *src_pad_dec = NULL;
12134         GstPad *sink_pad_videosink = NULL;
12135         GstPad *sink_pad_videobin = NULL;
12136         GstClock *clock = NULL;
12137         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12138         int ret = MM_ERROR_NONE;
12139         gboolean is_audiobin_created = TRUE;
12140
12141         MMPLAYER_FENTER();
12142
12143         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12144         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12145         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12146
12147         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12148         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12149
12150         /* get information whether if audiobin is created */
12151         if (!player->pipeline->audiobin ||
12152                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12153                 LOGW("audiobin is null, this video content may not have audio data");
12154                 is_audiobin_created = FALSE;
12155         }
12156
12157         /* get current state of player */
12158         previous_state = MMPLAYER_CURRENT_STATE(player);
12159         LOGD("previous state(%d)", previous_state);
12160
12161
12162         /* get src pad of decoder and block it */
12163         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12164         if (!src_pad_dec) {
12165                 LOGE("failed to get src pad from decode in mainbin");
12166                 return MM_ERROR_PLAYER_INTERNAL;
12167         }
12168
12169         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12170                 LOGW("trying to block pad(video)");
12171 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12172                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12173                         NULL, NULL, NULL);
12174                 {
12175                         LOGE("failed to set block pad(video)");
12176                         return MM_ERROR_PLAYER_INTERNAL;
12177                 }
12178                 LOGW("pad is blocked(video)");
12179         } else {
12180                 /* no data flows, so no need to do pad_block */
12181                 if (player->seek_state != MMPLAYER_SEEK_NONE)
12182                         LOGW("not completed seek(%d), do nothing", player->seek_state);
12183
12184                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12185         }
12186
12187         /* remove pad */
12188         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12189                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12190                 LOGE("failed to remove previous ghost_pad for videobin");
12191                 return MM_ERROR_PLAYER_INTERNAL;
12192         }
12193
12194         /* change state of videobin to NULL */
12195         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12196         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12197         if (ret != GST_STATE_CHANGE_SUCCESS) {
12198                 LOGE("failed to change state of videobin to NULL");
12199                 return MM_ERROR_PLAYER_INTERNAL;
12200         }
12201
12202         /* unlink between decoder and videobin and remove previous videosink from videobin */
12203         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12204         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12205                 LOGE("failed to remove former videosink from videobin");
12206                 return MM_ERROR_PLAYER_INTERNAL;
12207         }
12208
12209         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12210
12211         /* create a new videosink and add it to videobin */
12212         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12213         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12214                 LOGE("failed to create videosink element\n");
12215                 MMPLAYER_FLEAVE();
12216                 return MM_ERROR_PLAYER_INTERNAL;
12217         }
12218         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12219         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12220         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12221
12222         /* save attributes */
12223         if (player->attrs) {
12224                 /* set a new display surface type */
12225                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12226                 /* set a new diplay overlay */
12227                 switch (surface_type) {
12228                 case MM_DISPLAY_SURFACE_OVERLAY:
12229                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12230                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12231                         break;
12232                 default:
12233                         LOGE("invalid type(%d) for changing display surface", surface_type);
12234                         MMPLAYER_FLEAVE();
12235                         return MM_ERROR_INVALID_ARGUMENT;
12236                 }
12237                 if (mmf_attrs_commit(player->attrs)) {
12238                         LOGE("failed to commit");
12239                         MMPLAYER_FLEAVE();
12240                         return MM_ERROR_PLAYER_INTERNAL;
12241                 }
12242         } else {
12243                 LOGE("player->attrs is null, failed to save attributes");
12244                 MMPLAYER_FLEAVE();
12245                 return MM_ERROR_PLAYER_INTERNAL;
12246         }
12247
12248         /* update video param */
12249         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12250                 LOGE("failed to update video param");
12251                 return MM_ERROR_PLAYER_INTERNAL;
12252         }
12253
12254         /* change state of videobin to READY */
12255         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12256         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12257         if (ret != GST_STATE_CHANGE_SUCCESS) {
12258                 LOGE("failed to change state of videobin to READY");
12259                 return MM_ERROR_PLAYER_INTERNAL;
12260         }
12261
12262         /* change ghostpad */
12263         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12264         if (!sink_pad_videosink) {
12265                 LOGE("failed to get sink pad from videosink element");
12266                 return MM_ERROR_PLAYER_INTERNAL;
12267         }
12268         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12269         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12270                 LOGE("failed to set active to ghost_pad");
12271                 return MM_ERROR_PLAYER_INTERNAL;
12272         }
12273         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12274                 LOGE("failed to change ghostpad for videobin");
12275                 return MM_ERROR_PLAYER_INTERNAL;
12276         }
12277         gst_object_unref(sink_pad_videosink);
12278
12279         /* link decoder with videobin */
12280         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12281         if (!sink_pad_videobin) {
12282                 LOGE("failed to get sink pad from videobin");
12283                 return MM_ERROR_PLAYER_INTERNAL;
12284         }
12285         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12286                 LOGE("failed to link");
12287                 return MM_ERROR_PLAYER_INTERNAL;
12288         }
12289         gst_object_unref(sink_pad_videobin);
12290
12291         /* clock setting for a new videosink plugin */
12292         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12293                         so we set it from audiosink plugin or pipeline(system clock) */
12294         if (!is_audiobin_created) {
12295                 LOGW("audiobin is not created, get clock from pipeline..");
12296                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12297         } else {
12298                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12299         }
12300         if (clock) {
12301                 GstClockTime now;
12302                 GstClockTime base_time;
12303                 LOGD("set the clock to videosink");
12304                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12305                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12306                 if (clock) {
12307                         LOGD("got clock of videosink");
12308                         now = gst_clock_get_time(clock);
12309                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12310                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12311                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12312                 } else {
12313                         LOGE("failed to get clock of videosink after setting clock");
12314                         return MM_ERROR_PLAYER_INTERNAL;
12315                 }
12316         } else
12317                 LOGW("failed to get clock, maybe it is the time before first playing");
12318
12319         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12320                 /* change state of videobin to PAUSED */
12321                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12322                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12323                 if (ret != GST_STATE_CHANGE_FAILURE) {
12324                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12325                 } else {
12326                         LOGE("failed to change state of videobin to PLAYING");
12327                         return MM_ERROR_PLAYER_INTERNAL;
12328                 }
12329
12330                 /* release blocked and unref src pad of video decoder */
12331                 #if 0
12332                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12333                         LOGE("failed to set pad blocked FALSE(video)");
12334                         return MM_ERROR_PLAYER_INTERNAL;
12335                 }
12336                 #endif
12337                 LOGW("pad is unblocked(video)");
12338         } else {
12339                 if (player->seek_state != MMPLAYER_SEEK_NONE)
12340                         LOGW("not completed seek(%d)", player->seek_state);
12341                 /* change state of videobin to PAUSED */
12342                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12343                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12344                 if (ret != GST_STATE_CHANGE_FAILURE) {
12345                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12346                 } else {
12347                         LOGE("failed to change state of videobin to PLAYING");
12348                         return MM_ERROR_PLAYER_INTERNAL;
12349                 }
12350
12351                 /* already skipped pad block */
12352                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12353         }
12354
12355         /* do get/set position for new videosink plugin */
12356         {
12357                 gint64 position = 0;
12358
12359                 LOGD("do get/set position for new videosink plugin");
12360                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12361                         LOGE("failed to get position");
12362                         return MM_ERROR_PLAYER_INTERNAL;
12363                 }
12364 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12365                 /* accurate seek */
12366                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12367                         LOGE("failed to set position");
12368                         return MM_ERROR_PLAYER_INTERNAL;
12369                 }
12370 #else
12371                 /* key unit seek */
12372                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12373                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12374                                                         GST_SEEK_TYPE_SET, position,
12375                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12376                 if (!ret) {
12377                         LOGE("failed to set position");
12378                         return MM_ERROR_PLAYER_INTERNAL;
12379                 }
12380 #endif
12381         }
12382
12383         if (src_pad_dec)
12384                 gst_object_unref(src_pad_dec);
12385         LOGD("success to change sink");
12386
12387         MMPLAYER_FLEAVE();
12388
12389         return MM_ERROR_NONE;
12390 }
12391
12392
12393 /* Note : if silent is true, then subtitle would not be displayed. :*/
12394 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12395 {
12396         mm_player_t* player = (mm_player_t*) hplayer;
12397
12398         MMPLAYER_FENTER();
12399
12400         /* check player handle */
12401         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12402
12403         player->set_mode.subtitle_off = silent;
12404
12405         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12406
12407         MMPLAYER_FLEAVE();
12408
12409         return MM_ERROR_NONE;
12410 }
12411
12412 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12413 {
12414         MMPlayerGstElement* mainbin = NULL;
12415         MMPlayerGstElement* textbin = NULL;
12416         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12417         GstState current_state = GST_STATE_VOID_PENDING;
12418         GstState element_state = GST_STATE_VOID_PENDING;
12419         GstState element_pending_state = GST_STATE_VOID_PENDING;
12420         gint64 time = 0;
12421         GstEvent *event = NULL;
12422         int result = MM_ERROR_NONE;
12423
12424         GstClock *curr_clock = NULL;
12425         GstClockTime base_time, start_time, curr_time;
12426
12427
12428         MMPLAYER_FENTER();
12429
12430         /* check player handle */
12431         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12432                                                                 player->pipeline &&
12433                                                                 player->pipeline->mainbin &&
12434                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12435
12436         mainbin = player->pipeline->mainbin;
12437         textbin = player->pipeline->textbin;
12438
12439         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12440
12441         // sync clock with current pipeline
12442         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12443         curr_time = gst_clock_get_time(curr_clock);
12444
12445         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12446         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12447
12448         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12449                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12450
12451         if (current_state > GST_STATE_READY) {
12452                 // sync state with current pipeline
12453                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12454                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12455                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12456
12457                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12458                 if (GST_STATE_CHANGE_FAILURE == ret) {
12459                         LOGE("fail to state change.\n");
12460                         result = MM_ERROR_PLAYER_INTERNAL;
12461                         goto ERROR;
12462                 }
12463         }
12464
12465         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12466         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12467
12468         if (curr_clock) {
12469                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12470                 gst_object_unref(curr_clock);
12471         }
12472
12473         // seek to current position
12474         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12475                 result = MM_ERROR_PLAYER_INVALID_STATE;
12476                 LOGE("gst_element_query_position failed, invalid state\n");
12477                 goto ERROR;
12478         }
12479
12480         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12481         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);
12482         if (event) {
12483                 __gst_send_event_to_sink(player, event);
12484         } else {
12485                 result = MM_ERROR_PLAYER_INTERNAL;
12486                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12487                 goto ERROR;
12488         }
12489
12490         /* sync state with current pipeline */
12491         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12492         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12493         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12494
12495         return MM_ERROR_NONE;
12496
12497 ERROR:
12498         /* release text pipeline resource */
12499         player->textsink_linked = 0;
12500
12501         /* release signal */
12502         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12503
12504         /* release textbin with it's childs */
12505         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12506         MMPLAYER_FREEIF(player->pipeline->textbin);
12507         player->pipeline->textbin = NULL;
12508
12509         /* release subtitle elem */
12510         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12511         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12512
12513         return result;
12514 }
12515
12516 static int
12517 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12518 {
12519         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12520         GstState current_state = GST_STATE_VOID_PENDING;
12521
12522         MMHandleType attrs = 0;
12523         MMPlayerGstElement* mainbin = NULL;
12524         MMPlayerGstElement* textbin = NULL;
12525
12526         gchar* subtitle_uri = NULL;
12527         int result = MM_ERROR_NONE;
12528         const gchar *charset = NULL;
12529
12530         MMPLAYER_FENTER();
12531
12532         /* check player handle */
12533         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12534                                                                 player->pipeline &&
12535                                                                 player->pipeline->mainbin &&
12536                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12537         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12538
12539         mainbin = player->pipeline->mainbin;
12540         textbin = player->pipeline->textbin;
12541
12542         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12543         if (current_state < GST_STATE_READY) {
12544                 result = MM_ERROR_PLAYER_INVALID_STATE;
12545                 LOGE("Pipeline is not in proper state\n");
12546                 goto EXIT;
12547         }
12548
12549         attrs = MMPLAYER_GET_ATTRS(player);
12550         if (!attrs) {
12551                 LOGE("cannot get content attribute\n");
12552                 result = MM_ERROR_PLAYER_INTERNAL;
12553                 goto EXIT;
12554         }
12555
12556         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12557         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12558                 LOGE("subtitle uri is not proper filepath\n");
12559                 result = MM_ERROR_PLAYER_INVALID_URI;
12560                 goto EXIT;
12561         }
12562
12563         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12564                 LOGE("failed to get storage info of subtitle path");
12565                 result = MM_ERROR_PLAYER_INVALID_URI;
12566                 goto EXIT;
12567         }
12568
12569         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12570         LOGD("new subtitle file path is [%s]\n", filepath);
12571
12572         if (!strcmp(filepath, subtitle_uri)) {
12573                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12574                 goto EXIT;
12575         } else {
12576                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12577                 if (mmf_attrs_commit(player->attrs)) {
12578                         LOGE("failed to commit.\n");
12579                         goto EXIT;
12580                 }
12581         }
12582
12583         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12584         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12585         player->subtitle_language_list = NULL;
12586         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12587
12588         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12589         if (ret != GST_STATE_CHANGE_SUCCESS) {
12590                 LOGE("failed to change state of textbin to READY");
12591                 result = MM_ERROR_PLAYER_INTERNAL;
12592                 goto EXIT;
12593         }
12594
12595         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12596         if (ret != GST_STATE_CHANGE_SUCCESS) {
12597                 LOGE("failed to change state of subparse to READY");
12598                 result = MM_ERROR_PLAYER_INTERNAL;
12599                 goto EXIT;
12600         }
12601
12602         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12603         if (ret != GST_STATE_CHANGE_SUCCESS) {
12604                 LOGE("failed to change state of filesrc to READY");
12605                 result = MM_ERROR_PLAYER_INTERNAL;
12606                 goto EXIT;
12607         }
12608
12609         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12610
12611         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12612
12613         charset = util_get_charset(filepath);
12614         if (charset) {
12615                 LOGD("detected charset is %s\n", charset);
12616                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12617         }
12618
12619         result = _mmplayer_sync_subtitle_pipeline(player);
12620
12621 EXIT:
12622         MMPLAYER_FLEAVE();
12623         return result;
12624 }
12625
12626 /* API to switch between external subtitles */
12627 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12628 {
12629         int result = MM_ERROR_NONE;
12630         mm_player_t* player = (mm_player_t*)hplayer;
12631         char *path = NULL;
12632
12633         MMPLAYER_FENTER();
12634
12635         /* check player handle */
12636         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12637
12638         /* filepath can be null in idle state */
12639         if (filepath) {
12640                 /* check file path */
12641                 if ((path = strstr(filepath, "file://")))
12642                         result = util_exist_file_path(path + 7);
12643                 else
12644                         result = util_exist_file_path(filepath);
12645
12646                 if (result != MM_ERROR_NONE) {
12647                         LOGE("invalid subtitle path 0x%X", result);
12648                         return result; /* file not found or permission denied */
12649                 }
12650         }
12651
12652         if (!player->pipeline) {
12653                 /* IDLE state */
12654                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12655                 if (mmf_attrs_commit(player->attrs)) {
12656                         LOGE("failed to commit");       /* subtitle path will not be created */
12657                         return MM_ERROR_PLAYER_INTERNAL;
12658                 }
12659         } else {
12660                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12661                 /* check filepath */
12662                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12663
12664                 if (!__mmplayer_check_subtitle(player)) {
12665                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12666                         if (mmf_attrs_commit(player->attrs)) {
12667                                 LOGE("failed to commit");
12668                                 return MM_ERROR_PLAYER_INTERNAL;
12669                         }
12670
12671                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12672                                 LOGE("fail to create text pipeline");
12673                                 return MM_ERROR_PLAYER_INTERNAL;
12674                         }
12675
12676                         result = _mmplayer_sync_subtitle_pipeline(player);
12677                 } else {
12678                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12679                 }
12680
12681                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12682                 player->is_external_subtitle_added_now = TRUE;
12683
12684                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12685                 if (!player->subtitle_language_list) {
12686                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12687                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12688                                 LOGW("subtitle language list is not updated yet");
12689                 }
12690                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12691         }
12692
12693         MMPLAYER_FLEAVE();
12694         return result;
12695 }
12696
12697 static int
12698 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12699 {
12700         int result = MM_ERROR_NONE;
12701         gchar* change_pad_name = NULL;
12702         GstPad* sinkpad = NULL;
12703         MMPlayerGstElement* mainbin = NULL;
12704         enum MainElementID elemId = MMPLAYER_M_NUM;
12705         GstCaps* caps = NULL;
12706         gint total_track_num = 0;
12707
12708         MMPLAYER_FENTER();
12709
12710         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12711                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12712
12713         LOGD("Change Track(%d) to %d\n", type, index);
12714
12715         mainbin = player->pipeline->mainbin;
12716
12717         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12718                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12719         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12720                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12721         } else {
12722                 /* Changing Video Track is not supported. */
12723                 LOGE("Track Type Error\n");
12724                 goto EXIT;
12725         }
12726
12727         if (mainbin[elemId].gst == NULL) {
12728                 result = MM_ERROR_PLAYER_NO_OP;
12729                 LOGD("Req track doesn't exist\n");
12730                 goto EXIT;
12731         }
12732
12733         total_track_num = player->selector[type].total_track_num;
12734         if (total_track_num <= 0) {
12735                 result = MM_ERROR_PLAYER_NO_OP;
12736                 LOGD("Language list is not available \n");
12737                 goto EXIT;
12738         }
12739
12740         if ((index < 0) || (index >= total_track_num)) {
12741                 result = MM_ERROR_INVALID_ARGUMENT;
12742                 LOGD("Not a proper index : %d \n", index);
12743                 goto EXIT;
12744         }
12745
12746         /*To get the new pad from the selector*/
12747         change_pad_name = g_strdup_printf("sink_%u", index);
12748         if (change_pad_name == NULL) {
12749                 result = MM_ERROR_PLAYER_INTERNAL;
12750                 LOGD("Pad does not exists\n");
12751                 goto EXIT;
12752         }
12753
12754         LOGD("new active pad name: %s\n", change_pad_name);
12755
12756         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12757         if (sinkpad == NULL) {
12758                 LOGD("sinkpad is NULL");
12759                 result = MM_ERROR_PLAYER_INTERNAL;
12760                 goto EXIT;
12761         }
12762
12763         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12764         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12765
12766         caps = gst_pad_get_current_caps(sinkpad);
12767         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12768
12769         if (sinkpad)
12770                 gst_object_unref(sinkpad);
12771
12772         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12773                 __mmplayer_set_audio_attrs(player, caps);
12774
12775 EXIT:
12776
12777         MMPLAYER_FREEIF(change_pad_name);
12778         return result;
12779 }
12780
12781 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12782 {
12783         int result = MM_ERROR_NONE;
12784         mm_player_t* player = NULL;
12785         MMPlayerGstElement* mainbin = NULL;
12786
12787         gint current_active_index = 0;
12788
12789         GstState current_state = GST_STATE_VOID_PENDING;
12790         GstEvent* event = NULL;
12791         gint64 time = 0;
12792
12793         MMPLAYER_FENTER();
12794
12795         player = (mm_player_t*)hplayer;
12796         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12797
12798         if (!player->pipeline) {
12799                 LOGE("Track %d pre setting -> %d\n", type, index);
12800
12801                 player->selector[type].active_pad_index = index;
12802                 goto EXIT;
12803         }
12804
12805         mainbin = player->pipeline->mainbin;
12806
12807         current_active_index = player->selector[type].active_pad_index;
12808
12809         /*If index is same as running index no need to change the pad*/
12810         if (current_active_index == index)
12811                 goto EXIT;
12812
12813         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12814                 result = MM_ERROR_PLAYER_INVALID_STATE;
12815                 goto EXIT;
12816         }
12817
12818         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12819         if (current_state < GST_STATE_PAUSED) {
12820                 result = MM_ERROR_PLAYER_INVALID_STATE;
12821                 LOGW("Pipeline not in porper state\n");
12822                 goto EXIT;
12823         }
12824
12825         result = __mmplayer_change_selector_pad(player, type, index);
12826         if (result != MM_ERROR_NONE) {
12827                 LOGE("change selector pad error\n");
12828                 goto EXIT;
12829         }
12830
12831         player->selector[type].active_pad_index = index;
12832
12833         if (current_state == GST_STATE_PLAYING) {
12834                 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);
12835                 if (event) {
12836                         __gst_send_event_to_sink(player, event);
12837                 } else {
12838                         result = MM_ERROR_PLAYER_INTERNAL;
12839                         goto EXIT;
12840                 }
12841         }
12842
12843 EXIT:
12844         return result;
12845 }
12846
12847 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12848 {
12849         mm_player_t* player = (mm_player_t*) hplayer;
12850
12851         MMPLAYER_FENTER();
12852
12853         /* check player handle */
12854         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12855
12856         *silent = player->set_mode.subtitle_off;
12857
12858         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12859
12860         MMPLAYER_FLEAVE();
12861
12862         return MM_ERROR_NONE;
12863 }
12864
12865 gboolean
12866 __is_ms_buff_src(mm_player_t* player)
12867 {
12868         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12869
12870         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12871 }
12872
12873 gboolean
12874 __has_suffix(mm_player_t* player, const gchar* suffix)
12875 {
12876         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12877         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12878
12879         gboolean ret = FALSE;
12880         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12881         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12882
12883         if (g_str_has_suffix(player->profile.uri, suffix))
12884                 ret = TRUE;
12885
12886         MMPLAYER_FREEIF(t_url);
12887         MMPLAYER_FREEIF(t_suffix);
12888
12889         return ret;
12890 }
12891
12892 int
12893 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12894 {
12895         mm_player_t* player = (mm_player_t*) hplayer;
12896
12897         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12898
12899         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12900                 MMPLAYER_PRINT_STATE(player);
12901                 LOGE("wrong-state : can't set the download mode to parse");
12902                 return MM_ERROR_PLAYER_INVALID_STATE;
12903         }
12904
12905         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12906         player->video_hub_download_mode = mode;
12907
12908         return MM_ERROR_NONE;
12909 }
12910
12911 int
12912 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12913 {
12914         mm_player_t* player = (mm_player_t*) hplayer;
12915
12916         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12917
12918         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12919         player->sync_handler = enable;
12920
12921         return MM_ERROR_NONE;
12922 }
12923
12924 int
12925 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12926                                                                                 gint64 video_time, gint64 media_clock, gint64 audio_time)
12927 {
12928         mm_player_t* player = (mm_player_t*) hplayer;
12929         MMPlayerGstElement* mainbin = NULL;
12930         GstClockTime start_time_audio = 0, start_time_video = 0;
12931         GstClockTimeDiff base_time = 0, new_base_time = 0;
12932         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12933         gint64 api_delta = 0;
12934         gint64 position = 0, position_delta = 0;
12935         gint64 adj_base_time = 0;
12936         GstClock *curr_clock = NULL;
12937         GstClockTime curr_time = 0;
12938         gboolean query_ret = TRUE;
12939         int result = MM_ERROR_NONE;
12940
12941         MMPLAYER_FENTER();
12942
12943         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12944         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12945         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12946
12947         /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12948                                                                         clock, clock_delta, video_time, media_clock, audio_time); */
12949
12950         if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
12951                 LOGD("skip setting master clock. %lld", video_time);
12952                 goto EXIT;
12953         }
12954
12955         mainbin = player->pipeline->mainbin;
12956
12957         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12958         curr_time = gst_clock_get_time(curr_clock);
12959
12960         current_state = MMPLAYER_CURRENT_STATE(player);
12961
12962         if (current_state == MM_PLAYER_STATE_PLAYING)
12963                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12964
12965         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12966                 (!query_ret)) {
12967                 position = player->last_position;
12968                 LOGD("query fail. %"G_GINT64_FORMAT, position);
12969         }
12970
12971         clock *= GST_USECOND;
12972         clock_delta *= GST_USECOND;
12973
12974         api_delta = clock - curr_time;
12975         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12976                 player->video_share_api_delta = api_delta;
12977         else
12978                 clock_delta += (api_delta - player->video_share_api_delta);
12979
12980         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12981                 player->video_share_clock_delta = (gint64)clock_delta;
12982
12983                 position_delta = (position/GST_USECOND) - video_time;
12984                 position_delta *= GST_USECOND;
12985
12986                 adj_base_time = position_delta;
12987                 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
12988
12989         } else {
12990                 gint64 new_play_time = 0;
12991                 gint64 network_delay = 0;
12992
12993                 video_time *= GST_USECOND;
12994
12995                 network_delay = clock_delta - player->video_share_clock_delta;
12996                 new_play_time = video_time + network_delay;
12997
12998                 adj_base_time = position - new_play_time;
12999
13000                 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13001                          "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13002                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13003         }
13004
13005         /* Adjust Current Stream Time with base_time of sink
13006          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13007          * 2. Set new base time
13008          *    if adj_base_time is positive value, the stream time will be decreased.
13009          * 3. If seek event is occurred, the start time will be reset. */
13010         if ((player->pipeline->audiobin) &&
13011                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13012                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13013
13014                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13015                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13016                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13017                 }
13018
13019                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13020         }
13021
13022         if ((player->pipeline->videobin) &&
13023                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13024                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13025
13026                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13027                         LOGD("video sink : gst_element_set_start_time -> NONE");
13028                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13029                 }
13030
13031                 // if videobin exist, get base_time from videobin.
13032                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13033         }
13034
13035         new_base_time = base_time + adj_base_time;
13036
13037         if ((player->pipeline->audiobin) &&
13038                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13039                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13040
13041         if ((player->pipeline->videobin) &&
13042                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13043                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13044
13045 EXIT:
13046         MMPLAYER_FLEAVE();
13047
13048         return result;
13049 }
13050
13051 int
13052 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13053 {
13054         mm_player_t* player = (mm_player_t*) hplayer;
13055         MMPlayerGstElement* mainbin = NULL;
13056         GstClock *curr_clock = NULL;
13057         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13058         gint64 position = 0;
13059         gboolean query_ret = TRUE;
13060
13061         MMPLAYER_FENTER();
13062
13063         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13064         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13065         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13066
13067         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13068         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13069         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13070
13071         mainbin = player->pipeline->mainbin;
13072
13073         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13074
13075         current_state = MMPLAYER_CURRENT_STATE(player);
13076
13077         if (current_state != MM_PLAYER_STATE_PAUSED)
13078                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13079
13080         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13081                 (!query_ret))
13082                 position = player->last_position;
13083
13084         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13085
13086         LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13087
13088         if (curr_clock)
13089                 gst_object_unref(curr_clock);
13090
13091         MMPLAYER_FLEAVE();
13092
13093         return MM_ERROR_NONE;
13094 }
13095
13096 static gboolean
13097 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13098 {
13099         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13100         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13101
13102         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13103         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13104
13105         int idx = 0;
13106
13107         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13108                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13109                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13110                         mm_player_dump_t *dump_s;
13111                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13112
13113                         if (dump_s == NULL) {
13114                                 LOGE("malloc fail");
13115                                 return FALSE;
13116                         }
13117
13118                         dump_s->dump_element_file = NULL;
13119                         dump_s->dump_pad = NULL;
13120                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13121
13122                         if (dump_s->dump_pad) {
13123                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13124                                 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]);
13125                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13126                                 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);
13127                                 /* add list for removed buffer probe and close FILE */
13128                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13129                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13130                                 return TRUE;
13131                         } else {
13132                                 g_free(dump_s);
13133                                 dump_s = NULL;
13134                                 LOGE("failed to get %s sink pad added", factory_name);
13135                         }
13136
13137
13138                 }
13139         }
13140         return FALSE;
13141 }
13142
13143 static GstPadProbeReturn
13144 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13145 {
13146         FILE *dump_data = (FILE *) u_data;
13147 //      int written = 0;
13148         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13149         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13150
13151         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13152
13153         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13154
13155 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13156
13157         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13158
13159         return GST_PAD_PROBE_OK;
13160 }
13161
13162 static void
13163 __mmplayer_release_dump_list(GList *dump_list)
13164 {
13165         if (dump_list) {
13166                 GList *d_list = dump_list;
13167                 for (; d_list; d_list = g_list_next(d_list)) {
13168                         mm_player_dump_t *dump_s = d_list->data;
13169                         if (dump_s->dump_pad) {
13170                                 if (dump_s->probe_handle_id)
13171                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13172                         }
13173                         if (dump_s->dump_element_file) {
13174                                 fclose(dump_s->dump_element_file);
13175                                 dump_s->dump_element_file = NULL;
13176                         }
13177                         MMPLAYER_FREEIF(dump_s);
13178                 }
13179                 g_list_free(dump_list);
13180                 dump_list = NULL;
13181         }
13182 }
13183
13184 int
13185 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13186 {
13187         mm_player_t* player = (mm_player_t*) hplayer;
13188
13189         MMPLAYER_FENTER();
13190
13191         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13192         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13193
13194         *exist = player->has_closed_caption;
13195
13196         MMPLAYER_FLEAVE();
13197
13198         return MM_ERROR_NONE;
13199 }
13200
13201 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13202 {
13203         MMPLAYER_FENTER();
13204         if (buffer) {
13205                 // LOGD("unref internal gst buffer %p", buffer);
13206                 gst_buffer_unref((GstBuffer *)buffer);
13207                 buffer = NULL;
13208         }
13209         MMPLAYER_FLEAVE();
13210 }
13211
13212 void
13213 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13214 {
13215         mm_player_t *player  = (mm_player_t*)user_data;
13216         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13217         guint64 current_level_bytes = 0;
13218
13219         MMPLAYER_RETURN_IF_FAIL(player);
13220
13221         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13222
13223         LOGI("app-src: feed audio(%llu)", current_level_bytes);
13224         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13225
13226         if (player->media_stream_buffer_status_cb[type])
13227                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13228         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13229
13230 }
13231
13232 void
13233 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13234 {
13235         mm_player_t *player  = (mm_player_t*)user_data;
13236         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13237         guint64 current_level_bytes = 0;
13238
13239         MMPLAYER_RETURN_IF_FAIL(player);
13240
13241         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13242
13243         LOGI("app-src: feed video(%llu)", current_level_bytes);
13244
13245         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13246         if (player->media_stream_buffer_status_cb[type])
13247                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13248         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13249 }
13250
13251 void
13252 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13253 {
13254         mm_player_t *player  = (mm_player_t*)user_data;
13255         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13256         guint64 current_level_bytes = 0;
13257
13258         MMPLAYER_RETURN_IF_FAIL(player);
13259
13260         LOGI("app-src: feed subtitle");
13261
13262         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13263
13264         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13265         if (player->media_stream_buffer_status_cb[type])
13266                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13267
13268         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13269 }
13270
13271 void
13272 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13273 {
13274         mm_player_t *player  = (mm_player_t*)user_data;
13275         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13276         guint64 current_level_bytes = 0;
13277
13278         MMPLAYER_RETURN_IF_FAIL(player);
13279
13280         LOGI("app-src: audio buffer is full");
13281
13282         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13283
13284         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13285
13286         if (player->media_stream_buffer_status_cb[type])
13287                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13288
13289         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13290 }
13291
13292 void
13293 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13294 {
13295         mm_player_t *player  = (mm_player_t*)user_data;
13296         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13297         guint64 current_level_bytes = 0;
13298
13299         MMPLAYER_RETURN_IF_FAIL(player);
13300
13301         LOGI("app-src: video buffer is full");
13302
13303         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13304
13305         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13306         if (player->media_stream_buffer_status_cb[type])
13307                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13308
13309         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13310 }
13311
13312 gboolean
13313 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13314 {
13315         mm_player_t *player  = (mm_player_t*)user_data;
13316         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13317
13318         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13319
13320         LOGD("app-src: seek audio data %llu", position);
13321         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13322
13323         if (player->media_stream_seek_data_cb[type])
13324                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13325         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13326
13327         return TRUE;
13328 }
13329
13330 gboolean
13331 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13332 {
13333         mm_player_t *player  = (mm_player_t*)user_data;
13334         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13335
13336         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13337
13338         LOGD("app-src: seek video data %llu", position);
13339         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13340         if (player->media_stream_seek_data_cb[type])
13341                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13342         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13343
13344         return TRUE;
13345 }
13346
13347 gboolean
13348 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13349 {
13350         mm_player_t *player  = (mm_player_t*)user_data;
13351         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13352
13353         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13354
13355         LOGD("app-src: seek subtitle data");
13356         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13357
13358         if (player->media_stream_seek_data_cb[type])
13359                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13360         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13361
13362         return TRUE;
13363 }
13364
13365 int
13366 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13367 {
13368         mm_player_t* player = (mm_player_t*) hplayer;
13369
13370         MMPLAYER_FENTER();
13371
13372         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13373
13374         player->pcm_samplerate = samplerate;
13375         player->pcm_channel = channel;
13376
13377         MMPLAYER_FLEAVE();
13378         return MM_ERROR_NONE;
13379 }
13380
13381 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13382 {
13383         mm_player_t* player = (mm_player_t*) hplayer;
13384
13385         MMPLAYER_FENTER();
13386
13387         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13388         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13389
13390         if (MMPLAYER_IS_HTTP_PD(player))
13391                 *timeout = player->ini.live_state_change_timeout*2;
13392         else if (MMPLAYER_IS_STREAMING(player))
13393                 *timeout = player->ini.live_state_change_timeout;
13394         else
13395                 *timeout = player->ini.localplayback_state_change_timeout;
13396
13397         LOGD("timeout = %d\n", *timeout);
13398
13399         MMPLAYER_FLEAVE();
13400         return MM_ERROR_NONE;
13401 }
13402
13403 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13404 {
13405         mm_player_t* player = (mm_player_t*) hplayer;
13406
13407         MMPLAYER_FENTER();
13408
13409         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13410         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13411
13412         *num = player->video_num_buffers;
13413         *extra_num = player->video_extra_num_buffers;
13414
13415         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13416
13417         MMPLAYER_FLEAVE();
13418         return MM_ERROR_NONE;
13419 }
13420
13421 static void
13422 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13423 {
13424         int i = 0;
13425         MMPLAYER_FENTER();
13426         MMPLAYER_RETURN_IF_FAIL(player);
13427
13428         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13429
13430                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13431                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13432                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13433                         player->storage_info[i].id = -1;
13434                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13435
13436                         if (path_type != MMPLAYER_PATH_MAX)
13437                                 break;
13438                 }
13439         }
13440
13441         MMPLAYER_FLEAVE();
13442 }
13443
13444 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13445 {
13446         int ret = MM_ERROR_NONE;
13447         mm_player_t* player = (mm_player_t*)hplayer;
13448         MMMessageParamType msg_param = {0, };
13449
13450         MMPLAYER_FENTER();
13451         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13452
13453         LOGW("state changed storage %d:%d", id, state);
13454
13455         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13456                 return MM_ERROR_NONE;
13457
13458         /* FIXME: text path should be handled seperately. */
13459         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13460                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13461                 LOGW("external storage is removed");
13462
13463                 if (player->msg_posted == FALSE) {
13464                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13465                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13466                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13467                         player->msg_posted = TRUE;
13468                 }
13469
13470                 /* unrealize the player */
13471                 ret = _mmplayer_unrealize(hplayer);
13472                 if (ret != MM_ERROR_NONE)
13473                         LOGE("failed to unrealize");
13474         }
13475
13476         MMPLAYER_FLEAVE();
13477         return ret;
13478 }
13479
13480 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13481 {
13482         int ret = MM_ERROR_NONE;
13483         mm_player_t* player = (mm_player_t*) hplayer;
13484         int idx = 0, total = 0;
13485         gchar *result = NULL, *tmp = NULL;
13486
13487         MMPLAYER_FENTER();
13488         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13489         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13490
13491         total = *num = g_list_length(player->adaptive_info.var_list);
13492         if (total <= 0) {
13493                 LOGW("There is no stream variant info.");
13494                 return ret;
13495         }
13496
13497         result = g_strdup("");
13498         for (idx = 0 ; idx < total ; idx++) {
13499                 VariantData *v_data = NULL;
13500                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13501
13502                 if (v_data) {
13503                         gchar data[64] = {0};
13504                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13505
13506                         tmp = g_strconcat(result, data, NULL);
13507                         g_free(result);
13508                         result = tmp;
13509                 } else {
13510                         LOGW("There is no variant data in %d", idx);
13511                         (*num)--;
13512                 }
13513         }
13514
13515         *var_info = (char *)result;
13516
13517         LOGD("variant info %d:%s", *num, *var_info);
13518         MMPLAYER_FLEAVE();
13519         return ret;
13520 }
13521
13522 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13523 {
13524         int ret = MM_ERROR_NONE;
13525         mm_player_t* player = (mm_player_t*) hplayer;
13526
13527         MMPLAYER_FENTER();
13528         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13529
13530         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13531
13532         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13533         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13534         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13535
13536         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13537                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13538                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13539                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13540
13541                 /* FIXME: seek to current position for applying new variant limitation */
13542         }
13543
13544         MMPLAYER_FLEAVE();
13545         return ret;
13546
13547 }
13548
13549 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13550 {
13551         int ret = MM_ERROR_NONE;
13552         mm_player_t* player = (mm_player_t*) hplayer;
13553
13554         MMPLAYER_FENTER();
13555         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13556         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13557
13558         *bandwidth = player->adaptive_info.limit.bandwidth;
13559         *width = player->adaptive_info.limit.width;
13560         *height = player->adaptive_info.limit.height;
13561
13562         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13563
13564         MMPLAYER_FLEAVE();
13565         return ret;
13566 }
13567
13568 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13569 {
13570         int ret = MM_ERROR_NONE;
13571         mm_player_t* player = (mm_player_t*) hplayer;
13572
13573         MMPLAYER_FENTER();
13574         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13575
13576         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13577                 LOGW("buffer_ms will not be applied.");
13578
13579
13580         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13581
13582         if (player->streamer == NULL) {
13583                 player->streamer = __mm_player_streaming_create();
13584                 __mm_player_streaming_initialize(player->streamer);
13585         }
13586
13587         if (buffer_ms >= 0)
13588                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13589
13590         if (rebuffer_ms >= 0)
13591                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13592
13593         MMPLAYER_FLEAVE();
13594         return ret;
13595
13596 }
13597
13598 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13599 {
13600         int ret = MM_ERROR_NONE;
13601         mm_player_t* player = (mm_player_t*) hplayer;
13602
13603         MMPLAYER_FENTER();
13604         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13605         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13606
13607         if (player->streamer == NULL) {
13608                 player->streamer = __mm_player_streaming_create();
13609                 __mm_player_streaming_initialize(player->streamer);
13610         }
13611
13612         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13613         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13614
13615         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13616
13617         MMPLAYER_FLEAVE();
13618         return ret;
13619 }
13620
13621 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13622 {
13623 #define IDX_FIRST_SW_CODEC 0
13624         mm_player_t* player = (mm_player_t*) hplayer;
13625         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13626         MMHandleType attrs = 0;
13627
13628         MMPLAYER_FENTER();
13629         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13630
13631         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13632                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13633                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13634
13635         switch (stream_type) {
13636         case MM_PLAYER_STREAM_TYPE_AUDIO:
13637                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13638                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13639                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13640                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13641                         LOGE("There is no a codec for codec_type %d", codec_type);
13642                         return MM_ERROR_PLAYER_NO_OP;
13643                 }
13644         break;
13645         case MM_PLAYER_STREAM_TYPE_VIDEO:
13646                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13647                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13648                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13649                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13650                         LOGE("There is no v codec for codec_type %d", codec_type);
13651                         return MM_ERROR_PLAYER_NO_OP;
13652                 }
13653
13654         break;
13655         default:
13656                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13657                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13658         break;
13659         }
13660
13661         LOGD("update %s codec_type to %d", attr_name, codec_type);
13662
13663         attrs = MMPLAYER_GET_ATTRS(player);
13664         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13665
13666         if (mmf_attrs_commit(player->attrs)) {
13667                 LOGE("failed to commit codec_type attributes");
13668                 return MM_ERROR_PLAYER_INTERNAL;
13669         }
13670
13671         MMPLAYER_FLEAVE();
13672         return MM_ERROR_NONE;
13673 }
13674
13675 int
13676 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13677 {
13678         mm_player_t* player = (mm_player_t*) hplayer;
13679         GstElement* rg_vol_element = NULL;
13680
13681         MMPLAYER_FENTER();
13682
13683         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13684
13685         player->sound.rg_enable = enabled;
13686
13687         /* just hold rgvolume enable value if pipeline is not ready */
13688         if (!player->pipeline || !player->pipeline->audiobin) {
13689                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13690                 return MM_ERROR_NONE;
13691         }
13692
13693         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13694
13695         if (!rg_vol_element) {
13696                 LOGD("rgvolume element is not created");
13697                 return MM_ERROR_PLAYER_INTERNAL;
13698         }
13699
13700         if (enabled)
13701                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13702         else
13703                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13704
13705         MMPLAYER_FLEAVE();
13706
13707         return MM_ERROR_NONE;
13708 }
13709
13710 int
13711 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13712 {
13713         mm_player_t* player = (mm_player_t*) hplayer;
13714         GstElement* rg_vol_element = NULL;
13715         gboolean enable = FALSE;
13716
13717         MMPLAYER_FENTER();
13718
13719         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13720         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13721
13722         /* just hold enable_rg value if pipeline is not ready */
13723         if (!player->pipeline || !player->pipeline->audiobin) {
13724                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13725                 *enabled = player->sound.rg_enable;
13726                 return MM_ERROR_NONE;
13727         }
13728
13729         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13730
13731         if (!rg_vol_element) {
13732                 LOGD("rgvolume element is not created");
13733                 return MM_ERROR_PLAYER_INTERNAL;
13734         }
13735
13736         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13737         *enabled = enable;
13738
13739         MMPLAYER_FLEAVE();
13740
13741         return MM_ERROR_NONE;
13742 }