[0.6.110] consider the feature when building pipeline
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
58 |                                                                                                                                                                                       |
59 ========================================================================================== */
60
61 /*---------------------------------------------------------------------------
62 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
63 ---------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------
66 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
67 ---------------------------------------------------------------------------*/
68
69 /*---------------------------------------------------------------------------
70 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
71 ---------------------------------------------------------------------------*/
72
73 /*---------------------------------------------------------------------------
74 |    LOCAL #defines:                                                                                                            |
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
78
79 #define MM_VOLUME_FACTOR_DEFAULT                1.0
80 #define MM_VOLUME_FACTOR_MIN                    0
81 #define MM_VOLUME_FACTOR_MAX                    1.0
82
83 /* Don't need to sleep for sound fadeout
84  * fadeout related fucntion will be deleted(Deprecated)
85  */
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
87
88 #define DEFAULT_PLAYBACK_RATE                   1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
90
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93         (player->ini.http_use_file_buffer) && \
94         (player->http_file_buffering_path) && \
95         (strlen(player->http_file_buffering_path) > 0))
96
97 #define PLAYER_DISPLAY_MODE_DST_ROI             5
98
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
100
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
103
104 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
105 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
106
107 /*---------------------------------------------------------------------------
108 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
109 ---------------------------------------------------------------------------*/
110
111 /*---------------------------------------------------------------------------
112 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
113 ---------------------------------------------------------------------------*/
114
115 /*---------------------------------------------------------------------------
116 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
117 ---------------------------------------------------------------------------*/
118
119 /*---------------------------------------------------------------------------
120 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
121 ---------------------------------------------------------------------------*/
122 static sound_stream_info_h stream_info;
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
126 ---------------------------------------------------------------------------*/
127 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
128 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
129 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
131 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
132 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
133 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
134
135 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
136 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
137 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
138 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
139 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
140 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
141 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
142 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
143 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
144 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
145 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
146 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
147 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
148 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
149 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
150 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
151 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
152
153 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
154 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
155 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
156 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void             __mmplayer_release_misc(mm_player_t* player);
158 static void             __mmplayer_release_misc_post(mm_player_t* player);
159 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
160 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
161 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
162 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
163 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
164 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
165 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
167 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
169 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
170
171 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
172 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
173 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
174 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
175 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
176 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
177 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
178 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
179 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
180 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
181 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
182 static gpointer __mmplayer_next_play_thread(gpointer data);
183 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
184
185 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
186 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
187 static void __mmplayer_release_dump_list(GList *dump_list);
188
189 static int              __gst_realize(mm_player_t* player);
190 static int              __gst_unrealize(mm_player_t* player);
191 static int              __gst_start(mm_player_t* player);
192 static int              __gst_stop(mm_player_t* player);
193 static int              __gst_pause(mm_player_t* player, gboolean async);
194 static int              __gst_resume(mm_player_t* player, gboolean async);
195 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
196                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
197                                         gint64 cur, GstSeekType stop_type, gint64 stop);
198 static int __gst_pending_seek(mm_player_t* player);
199
200 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
201 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
202 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
203 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
204 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
205
206 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
207
208 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
209 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
210
211 /* util */
212 static gboolean __is_ms_buff_src(mm_player_t* player);
213 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
214
215 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
216 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
217 static int __mmplayer_start_streaming_ext(mm_player_t *player);
218 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
219 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
220
221 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
222 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
223 static void __mmplayer_check_pipeline(mm_player_t* player);
224 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
225 static void __mmplayer_deactivate_old_path(mm_player_t *player);
226
227 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
228 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
229
230 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
231 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
232 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
233 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
234 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
235 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
236 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
237 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
238 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
239 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
240 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
241 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
242 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
243 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
244 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
245 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
246
247 /*===========================================================================================
248 |                                                                                                                                                                                       |
249 |  FUNCTION DEFINITIONS                                                                                                                                         |
250 |                                                                                                                                                                                       |
251 ========================================================================================== */
252
253 #if 0 //debug
254 static void
255 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
256 {
257         gint i, count;
258
259         count = gst_tag_list_get_tag_size(list, tag);
260
261         LOGD("count = %d", count);
262
263         for (i = 0; i < count; i++) {
264                 gchar *str;
265
266                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
267                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
268                                 g_assert_not_reached();
269                 } else
270                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
271
272                 if (i == 0)
273                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
274                 else
275                         g_print("                 : %s\n", str);
276
277                 g_free(str);
278         }
279 }
280 #endif
281
282 /* This function should be called after the pipeline goes PAUSED or higher
283 state. */
284 gboolean
285 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
286 {
287         static gboolean has_duration = FALSE;
288         static gboolean has_video_attrs = FALSE;
289         static gboolean has_audio_attrs = FALSE;
290         static gboolean has_bitrate = FALSE;
291         gboolean missing_only = FALSE;
292         gboolean all = FALSE;
293         gint64 dur_nsec = 0;
294         GstStructure* p = NULL;
295         MMHandleType attrs = 0;
296         gchar *path = NULL;
297         struct stat sb;
298
299         MMPLAYER_FENTER();
300
301         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
302
303         /* check player state here */
304         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
305                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
306                 /* give warning now only */
307                 LOGW("be careful. content attributes may not available in this state ");
308         }
309
310         /* get content attribute first */
311         attrs = MMPLAYER_GET_ATTRS(player);
312         if (!attrs) {
313                 LOGE("cannot get content attribute");
314                 return FALSE;
315         }
316
317         /* get update flag */
318
319         if (flag & ATTR_MISSING_ONLY) {
320                 missing_only = TRUE;
321                 LOGD("updating missed attr only");
322         }
323
324         if (flag & ATTR_ALL) {
325                 all = TRUE;
326                 has_duration = FALSE;
327                 has_video_attrs = FALSE;
328                 has_audio_attrs = FALSE;
329                 has_bitrate = FALSE;
330
331                 LOGD("updating all attrs");
332         }
333
334         if (missing_only && all) {
335                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
336                 missing_only = FALSE;
337         }
338
339         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
340                 LOGD("try to update duration");
341                 has_duration = FALSE;
342
343                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
344                         player->duration = dur_nsec;
345                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
346                 }
347
348                 if (player->duration < 0) {
349                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
350                         player->duration = 0;
351                 }
352
353                 /* update streaming service type */
354                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
355
356                 /* check duration is OK */
357                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
358                         /* FIXIT : find another way to get duration here. */
359                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
360                 } else {
361                         /*update duration */
362                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
363                         has_duration = TRUE;
364                 }
365         }
366
367         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
368                 /* update audio params
369                 NOTE : We need original audio params and it can be only obtained from src pad of audio
370                 decoder. Below code only valid when we are not using 'resampler' just before
371                 'audioconverter'. */
372
373                 LOGD("try to update audio attrs");
374                 has_audio_attrs = FALSE;
375
376                 if (player->pipeline->audiobin &&
377                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
378                         GstCaps *caps_a = NULL;
379                         GstPad* pad = NULL;
380                         gint samplerate = 0, channels = 0;
381
382                         pad = gst_element_get_static_pad(
383                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
384
385                         if (pad) {
386                                 caps_a = gst_pad_get_current_caps(pad);
387
388                                 if (caps_a) {
389                                         p = gst_caps_get_structure(caps_a, 0);
390
391                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
392
393                                         gst_structure_get_int(p, "rate", &samplerate);
394                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
395
396                                         gst_structure_get_int(p, "channels", &channels);
397                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
398
399                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
400
401                                         gst_caps_unref(caps_a);
402                                         caps_a = NULL;
403
404                                         has_audio_attrs = TRUE;
405                                 } else
406                                         LOGW("not ready to get audio caps");
407
408                                 gst_object_unref(pad);
409                         } else
410                                 LOGW("failed to get pad from audiosink");
411                 }
412         }
413
414         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
415                 LOGD("try to update video attrs");
416                 has_video_attrs = FALSE;
417
418                 if (player->pipeline->videobin &&
419                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
420                         GstCaps *caps_v = NULL;
421                         GstPad* pad = NULL;
422                         gint tmpNu, tmpDe;
423                         gint width, height;
424
425                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
426                         if (pad) {
427                                 caps_v = gst_pad_get_current_caps(pad);
428
429                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
430                                 if (!caps_v && player->v_stream_caps) {
431                                         caps_v = player->v_stream_caps;
432                                         gst_caps_ref(caps_v);
433                                 }
434
435                                 if (caps_v) {
436                                         p = gst_caps_get_structure(caps_v, 0);
437                                         gst_structure_get_int(p, "width", &width);
438                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
439
440                                         gst_structure_get_int(p, "height", &height);
441                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
442
443                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
444
445                                         SECURE_LOGD("width : %d     height : %d", width, height);
446
447                                         gst_caps_unref(caps_v);
448                                         caps_v = NULL;
449
450                                         if (tmpDe > 0) {
451                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
452                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
453                                         }
454
455                                         has_video_attrs = TRUE;
456                                 } else
457                                         LOGD("no negitiated caps from videosink");
458                                 gst_object_unref(pad);
459                                 pad = NULL;
460                         } else
461                                 LOGD("no videosink sink pad");
462                 }
463         }
464
465
466         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
467                 has_bitrate = FALSE;
468
469                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
470                 if (player->duration) {
471                         guint64 data_size = 0;
472
473                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
474                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
475
476                                 if (stat(path, &sb) == 0)
477                                         data_size = (guint64)sb.st_size;
478                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
479                                 data_size = player->http_content_size;
480                         }
481                         LOGD("try to update bitrate : data_size = %lld", data_size);
482
483                         if (data_size) {
484                                 guint64 bitrate = 0;
485                                 guint64 msec_dur = 0;
486
487                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
488                                 if (msec_dur > 0) {
489                                         bitrate = data_size * 8 * 1000 / msec_dur;
490                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
491                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
492
493                                         has_bitrate = TRUE;
494                                 } else {
495                                         LOGD("player duration is less than 0");
496                                 }
497                         }
498
499                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
500                                 if (player->total_bitrate) {
501                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
502                                         has_bitrate = TRUE;
503                                 }
504                         }
505                 }
506         }
507
508         /* validate all */
509         if (mmf_attrs_commit(attrs)) {
510                 LOGE("failed to update attributes\n");
511                 return FALSE;
512         }
513
514         MMPLAYER_FLEAVE();
515
516         return TRUE;
517 }
518
519 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
520 {
521         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
522
523         MMPLAYER_FENTER();
524
525         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
526                         player->pipeline &&
527                         player->pipeline->mainbin &&
528                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
529                         STREAMING_SERVICE_NONE);
530
531         /* streaming service type if streaming */
532         if (!MMPLAYER_IS_STREAMING(player))
533                 return STREAMING_SERVICE_NONE;
534
535         if (MMPLAYER_IS_HTTP_STREAMING(player))
536                 streaming_type = (player->duration == 0) ?
537                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
538
539         switch (streaming_type) {
540         case STREAMING_SERVICE_LIVE:
541                 LOGD("it's live streaming");
542                 break;
543         case STREAMING_SERVICE_VOD:
544                 LOGD("it's vod streaming");
545                 break;
546         default:
547                 LOGE("should not get here");
548                 break;
549         }
550
551         MMPLAYER_FLEAVE();
552
553         return streaming_type;
554 }
555
556
557 /* this function sets the player state and also report
558  * it to applicaton by calling callback function
559  */
560 int
561 __mmplayer_set_state(mm_player_t* player, int state)
562 {
563         MMMessageParamType msg = {0, };
564         gboolean post_bos = FALSE;
565
566         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
567
568         if (MMPLAYER_CURRENT_STATE(player) == state) {
569                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
570                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
571                 return MM_ERROR_NONE;
572         }
573
574         /* update player states */
575         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
576         MMPLAYER_CURRENT_STATE(player) = state;
577
578         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
579                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
580
581         /* print state */
582         MMPLAYER_PRINT_STATE(player);
583
584         switch (MMPLAYER_CURRENT_STATE(player)) {
585         case MM_PLAYER_STATE_NULL:
586         case MM_PLAYER_STATE_READY:
587                 break;
588
589         case MM_PLAYER_STATE_PAUSED:
590                 {
591                         if (!player->sent_bos) {
592                                 /* rtsp case, get content attrs by GstMessage */
593                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
594                                         /* it's first time to update all content attrs. */
595                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
596                                 }
597                         }
598
599                         /* add audio callback probe if condition is satisfied */
600                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
601                                 __mmplayer_configure_audio_callback(player);
602
603                         /* FIXIT : handle return value */
604                 }
605                 break;
606
607         case MM_PLAYER_STATE_PLAYING:
608                 {
609                         /* try to get content metadata */
610                         if (!player->sent_bos) {
611                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
612                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
613                                  * legacy mmfw-player api */
614                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
615                         }
616
617                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
618                                 if (!player->sent_bos)
619                                         __mmplayer_handle_missed_plugin(player);
620                         }
621
622                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
623                                 /* initialize because auto resume is done well. */
624                                 player->resumed_by_rewind = FALSE;
625                                 player->playback_rate = 1.0;
626                         }
627
628                         if (!player->sent_bos) {
629                                 /* check audio codec field is set or not
630                                  * we can get it from typefinder or codec's caps.
631                                  */
632                                 gchar *audio_codec = NULL;
633                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
634
635                                 /* The codec format can't be sent for audio only case like amr, mid etc.
636                                  * Because, parser don't make related TAG.
637                                  * So, if it's not set yet, fill it with found data.
638                                  */
639                                 if (!audio_codec) {
640                                         if (g_strrstr(player->type, "audio/midi"))
641                                                 audio_codec = g_strdup("MIDI");
642                                         else if (g_strrstr(player->type, "audio/x-amr"))
643                                                 audio_codec = g_strdup("AMR");
644                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
645                                                 audio_codec = g_strdup("AAC");
646                                         else
647                                                 audio_codec = g_strdup("unknown");
648                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
649
650                                         MMPLAYER_FREEIF(audio_codec);
651                                         if (mmf_attrs_commit(player->attrs))
652                                                 LOGE("failed to update attributes\n");
653
654                                         LOGD("set audio codec type with caps\n");
655                                 }
656
657                                 post_bos = TRUE;
658                         }
659                 }
660                 break;
661
662         case MM_PLAYER_STATE_NONE:
663         default:
664                 LOGW("invalid target state, there is nothing to do.\n");
665                 break;
666         }
667
668
669         /* post message to application */
670         if (MMPLAYER_TARGET_STATE(player) == state) {
671                 /* fill the message with state of player */
672                 msg.union_type = MM_MSG_UNION_STATE;
673                 msg.state.previous = MMPLAYER_PREV_STATE(player);
674                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
675
676                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
677
678                 /* state changed by resource callback */
679                 if (player->interrupted_by_resource) {
680                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
681                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
682                 } else { /* state changed by usecase */
683                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
684                 }
685         } else {
686                 LOGD("intermediate state, do nothing.\n");
687                 MMPLAYER_PRINT_STATE(player);
688                 return MM_ERROR_NONE;
689         }
690
691         if (post_bos) {
692                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
693                 player->sent_bos = TRUE;
694         }
695
696         return MM_ERROR_NONE;
697 }
698
699 static gpointer __mmplayer_next_play_thread(gpointer data)
700 {
701         mm_player_t* player = (mm_player_t*) data;
702         MMPlayerGstElement *mainbin = NULL;
703
704         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
705
706         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
707         while (!player->next_play_thread_exit) {
708                 LOGD("next play thread started. waiting for signal.\n");
709                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
710
711                 LOGD("reconfigure pipeline for gapless play.\n");
712
713                 if (player->next_play_thread_exit) {
714                         if (player->gapless.reconfigure) {
715                                 player->gapless.reconfigure = false;
716                                 MMPLAYER_PLAYBACK_UNLOCK(player);
717                         }
718                         LOGD("exiting gapless play thread\n");
719                         break;
720                 }
721
722                 mainbin = player->pipeline->mainbin;
723
724                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
725                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
726                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
728                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
729
730                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731         }
732         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
733
734         return NULL;
735 }
736
737 static void
738 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
739 {
740         MMHandleType attrs = 0;
741         guint64 data_size = 0;
742         gchar* path = NULL;
743         unsigned long pos_msec = 0;
744         struct stat sb;
745
746         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
747
748         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
749
750         attrs = MMPLAYER_GET_ATTRS(player);
751         if (!attrs) {
752                 LOGE("fail to get attributes.\n");
753                 return;
754         }
755
756         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
757                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
758
759                 if (stat(path, &sb) == 0)
760                         data_size = (guint64)sb.st_size;
761         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
762                 data_size = player->http_content_size;
763
764         __mm_player_streaming_buffering(player->streamer,
765                                                                                 buffering_msg,
766                                                                                 data_size,
767                                                                                 player->last_position,
768                                                                                 player->duration);
769
770         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
771
772         return;
773 }
774
775 static int
776 __mmplayer_handle_buffering_message(mm_player_t* player)
777 {
778         int ret = MM_ERROR_NONE;
779         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
780         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
781         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
782         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
783
784         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
785                 LOGW("do nothing for buffering msg\n");
786                 ret = MM_ERROR_PLAYER_INVALID_STATE;
787                 goto exit;
788         }
789
790         prev_state = MMPLAYER_PREV_STATE(player);
791         current_state = MMPLAYER_CURRENT_STATE(player);
792         target_state = MMPLAYER_TARGET_STATE(player);
793         pending_state = MMPLAYER_PENDING_STATE(player);
794
795         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
796                 MMPLAYER_STATE_GET_NAME(prev_state),
797                 MMPLAYER_STATE_GET_NAME(current_state),
798                 MMPLAYER_STATE_GET_NAME(pending_state),
799                 MMPLAYER_STATE_GET_NAME(target_state),
800                 player->streamer->is_buffering);
801
802         if (!player->streamer->is_buffering) {
803                 /* NOTE : if buffering has done, player has to go to target state. */
804                 switch (target_state) {
805                 case MM_PLAYER_STATE_PAUSED:
806                         {
807                                 switch (pending_state) {
808                                 case MM_PLAYER_STATE_PLAYING:
809                                         __gst_pause(player, TRUE);
810                                         break;
811
812                                 case MM_PLAYER_STATE_PAUSED:
813                                         LOGD("player is already going to paused state, there is nothing to do.\n");
814                                         break;
815
816                                 case MM_PLAYER_STATE_NONE:
817                                 case MM_PLAYER_STATE_NULL:
818                                 case MM_PLAYER_STATE_READY:
819                                 default:
820                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
821                                         break;
822                                 }
823                         }
824                         break;
825
826                 case MM_PLAYER_STATE_PLAYING:
827                         {
828                                 switch (pending_state) {
829                                 case MM_PLAYER_STATE_NONE:
830                                         {
831                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
832                                                         __gst_resume(player, TRUE);
833                                         }
834                                         break;
835
836                                 case MM_PLAYER_STATE_PAUSED:
837                                         /* NOTE: It should be worked as asynchronously.
838                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
839                                          */
840                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
841                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
842                                                  * The current state should be changed to paused purposely to prevent state conflict.
843                                                  */
844                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
845                                         }
846                                         __gst_resume(player, TRUE);
847                                         break;
848
849                                 case MM_PLAYER_STATE_PLAYING:
850                                         LOGD("player is already going to playing state, there is nothing to do.\n");
851                                         break;
852
853                                 case MM_PLAYER_STATE_NULL:
854                                 case MM_PLAYER_STATE_READY:
855                                 default:
856                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
857                                         break;
858                                 }
859                         }
860                         break;
861
862                 case MM_PLAYER_STATE_NULL:
863                 case MM_PLAYER_STATE_READY:
864                 case MM_PLAYER_STATE_NONE:
865                 default:
866                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
867                         break;
868                 }
869         } else {
870                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
871                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
872                  */
873                 switch (pending_state) {
874                 case MM_PLAYER_STATE_NONE:
875                         {
876                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
877                                         /* rtsp streaming pause makes rtsp server stop sending data. */
878                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
879                                                 LOGD("set pause state during buffering\n");
880                                                 __gst_pause(player, TRUE);
881                                         }
882                                 }
883                         }
884                         break;
885
886                 case MM_PLAYER_STATE_PLAYING:
887                         /* rtsp streaming pause makes rtsp server stop sending data. */
888                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
889                                 __gst_pause(player, TRUE);
890                         break;
891
892                 case MM_PLAYER_STATE_PAUSED:
893                         break;
894
895                 case MM_PLAYER_STATE_NULL:
896                 case MM_PLAYER_STATE_READY:
897                 default:
898                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
899                         break;
900                 }
901         }
902
903 exit:
904         return ret;
905 }
906
907 static void
908 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
909 {
910         MMPlayerGstElement *textbin;
911         MMPLAYER_FENTER();
912
913         MMPLAYER_RETURN_IF_FAIL(player &&
914                                         player->pipeline &&
915                                         player->pipeline->textbin);
916
917         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
918
919         textbin = player->pipeline->textbin;
920
921         if (is_drop) {
922                 LOGD("Drop subtitle text after getting EOS\n");
923
924                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
925                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
926
927                 player->is_subtitle_force_drop = TRUE;
928         } else {
929                 if (player->is_subtitle_force_drop == TRUE) {
930                         LOGD("Enable subtitle data path without drop\n");
931
932                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
933                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
934
935                         LOGD("non-connected with external display");
936
937                         player->is_subtitle_force_drop = FALSE;
938                 }
939         }
940 }
941
942 static VariantData *
943 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
944 {
945         VariantData *var_info = NULL;
946         g_return_val_if_fail(self != NULL, NULL);
947
948         var_info = g_new0(VariantData, 1);
949         if (!var_info) return NULL;
950         var_info->bandwidth = self->bandwidth;
951         var_info->width = self->width;
952         var_info->height = self->height;
953         return var_info;
954 }
955
956 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
957 {
958         mm_player_t* player = (mm_player_t*)hplayer;
959
960         MMPLAYER_FENTER();
961         MMPLAYER_RETURN_IF_FAIL(player);
962
963         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
964
965         /* destroy the gst bus msg thread */
966         if (player->bus_msg_thread) {
967                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
968                 player->bus_msg_thread_exit = TRUE;
969                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
970                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
971
972                 LOGD("gst bus msg thread exit.");
973                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
974                 player->bus_msg_thread = NULL;
975
976                 g_mutex_clear(&player->bus_msg_thread_mutex);
977                 g_cond_clear(&player->bus_msg_thread_cond);
978         }
979
980         MMPLAYER_FLEAVE();
981 }
982
983 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
984 {
985         mm_player_t *player = (mm_player_t*)(data);
986         GstMessage *msg = NULL;
987         GstBus *bus = NULL;
988
989         MMPLAYER_FENTER();
990         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
991                                                 player->pipeline &&
992                                                 player->pipeline->mainbin &&
993                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
994                                                 NULL);
995
996         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
997         if (!bus) {
998                 LOGE("cannot get BUS from the pipeline");
999                 return NULL;
1000         }
1001
1002         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1003
1004         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1005         while (!player->bus_msg_thread_exit) {
1006                 msg = gst_bus_pop(bus);
1007                 if (msg == NULL) {
1008                         int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1009                         MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1010                         continue;
1011                 }
1012
1013                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1014                 /* handle the gst msg */
1015                 __mmplayer_gst_callback(msg, player);
1016                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1017                 gst_message_unref(msg);
1018         }
1019
1020         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1021         gst_object_unref(GST_OBJECT(bus));
1022
1023         MMPLAYER_FLEAVE();
1024         return NULL;
1025 }
1026
1027 static void
1028 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1029 {
1030         mm_player_t* player = (mm_player_t*)(data);
1031         static gboolean async_done = FALSE;
1032
1033         MMPLAYER_RETURN_IF_FAIL(player);
1034         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1035
1036         switch (GST_MESSAGE_TYPE(msg)) {
1037         case GST_MESSAGE_UNKNOWN:
1038                 LOGD("unknown message received\n");
1039                 break;
1040
1041         case GST_MESSAGE_EOS:
1042                 {
1043                         MMHandleType attrs = 0;
1044                         gint count = 0;
1045
1046                         LOGD("GST_MESSAGE_EOS received\n");
1047
1048                         /* NOTE : EOS event is comming multiple time. watch out it */
1049                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1050                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1051                                 LOGD("EOS received on non-playing state. ignoring it\n");
1052                                 break;
1053                         }
1054
1055                         if (player->pipeline) {
1056                                 if (player->pipeline->textbin)
1057                                         __mmplayer_drop_subtitle(player, TRUE);
1058
1059                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1060                                         GstPad *pad = NULL;
1061
1062                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1063
1064                                         LOGD("release audio callback\n");
1065
1066                                         /* release audio callback */
1067                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1068                                         player->audio_cb_probe_id = 0;
1069                                         /* audio callback should be free because it can be called even though probe remove.*/
1070                                         player->audio_stream_cb = NULL;
1071                                         player->audio_stream_cb_user_param = NULL;
1072
1073                                 }
1074                         }
1075                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1076                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1077
1078                         /* rewind if repeat count is greater then zero */
1079                         /* get play count */
1080                         attrs = MMPLAYER_GET_ATTRS(player);
1081
1082                         if (attrs) {
1083                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1084
1085                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1086
1087                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1088                                         if (player->playback_rate < 0.0) {
1089                                                 player->resumed_by_rewind = TRUE;
1090                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1091                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1092                                         }
1093
1094                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1095
1096                                         /* initialize */
1097                                         player->sent_bos = FALSE;
1098
1099                                         /* not posting eos when repeating */
1100                                         break;
1101                                 }
1102                         }
1103
1104                         if (player->pipeline)
1105                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1106
1107                         /* post eos message to application */
1108                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1109
1110                         /* reset last position */
1111                         player->last_position = 0;
1112                 }
1113                 break;
1114
1115         case GST_MESSAGE_ERROR:
1116                 {
1117                         GError *error = NULL;
1118                         gchar* debug = NULL;
1119
1120                         /* generating debug info before returning error */
1121                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1122
1123                         /* get error code */
1124                         gst_message_parse_error(msg, &error, &debug);
1125
1126                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1127                                 /* Note : the streaming error from the streaming source is handled
1128                                  *   using __mmplayer_handle_streaming_error.
1129                                  */
1130                                 __mmplayer_handle_streaming_error(player, msg);
1131
1132                                 /* dump state of all element */
1133                                 __mmplayer_dump_pipeline_state(player);
1134                         } else {
1135                                 /* traslate gst error code to msl error code. then post it
1136                                  * to application if needed
1137                                  */
1138                                 __mmplayer_handle_gst_error(player, msg, error);
1139
1140                                 if (debug)
1141                                         LOGE("error debug : %s", debug);
1142                         }
1143
1144                         if (MMPLAYER_IS_HTTP_PD(player))
1145                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1146
1147                         MMPLAYER_FREEIF(debug);
1148                         g_error_free(error);
1149                 }
1150                 break;
1151
1152         case GST_MESSAGE_WARNING:
1153                 {
1154                         char* debug = NULL;
1155                         GError* error = NULL;
1156
1157                         gst_message_parse_warning(msg, &error, &debug);
1158
1159                         LOGD("warning : %s\n", error->message);
1160                         LOGD("debug : %s\n", debug);
1161
1162                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1163
1164                         MMPLAYER_FREEIF(debug);
1165                         g_error_free(error);
1166                 }
1167                 break;
1168
1169         case GST_MESSAGE_TAG:
1170                 {
1171                         LOGD("GST_MESSAGE_TAG\n");
1172                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1173                                 LOGW("failed to extract tags from gstmessage\n");
1174                 }
1175                 break;
1176
1177         case GST_MESSAGE_BUFFERING:
1178                 {
1179                         MMMessageParamType msg_param = {0, };
1180                         int bRet = MM_ERROR_NONE;
1181
1182                         if (!(player->pipeline && player->pipeline->mainbin)) {
1183                                 LOGE("player pipeline handle is null");
1184                                 break;
1185                         }
1186
1187                         if (!MMPLAYER_IS_STREAMING(player))
1188                                 break;
1189
1190                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1191                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1192                                         /* skip the playback control by buffering msg while user request is handled. */
1193                                         gint per = 0;
1194
1195                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1196
1197                                         gst_message_parse_buffering(msg, &per);
1198                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1199
1200                                         msg_param.connection.buffering = per;
1201                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1202                                         break;
1203                                 }
1204                         } else {
1205                                 MMPLAYER_CMD_LOCK(player);
1206                         }
1207
1208                         /* ignore the prev buffering message */
1209                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1210                                 && (player->streamer->is_buffering_done == TRUE)) {
1211                                 gint buffer_percent = 0;
1212
1213                                 gst_message_parse_buffering(msg, &buffer_percent);
1214
1215                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1216                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1217                                         player->streamer->is_buffering_done = FALSE;
1218                                 }
1219                                 MMPLAYER_CMD_UNLOCK(player);
1220                                 break;
1221                         }
1222
1223                         __mmplayer_update_buffer_setting(player, msg);
1224
1225                         bRet = __mmplayer_handle_buffering_message(player);
1226
1227                         if (bRet == MM_ERROR_NONE) {
1228                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1229                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1230
1231                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1232                                         player->pending_resume &&
1233                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1234
1235                                         player->is_external_subtitle_added_now = FALSE;
1236                                         player->pending_resume = FALSE;
1237                                         _mmplayer_resume((MMHandleType)player);
1238                                 }
1239
1240                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1241                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1242
1243                                         if (player->doing_seek) {
1244                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1245                                                         player->doing_seek = FALSE;
1246                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1247                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1248                                                         async_done = TRUE;
1249                                                 }
1250                                         }
1251                                 }
1252                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1253                                 if (!player->streamer) {
1254                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1255                                         MMPLAYER_CMD_UNLOCK(player);
1256                                         break;
1257                                 }
1258
1259                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1260
1261                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1262                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1263
1264                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1265                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1266                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1267                                         } else {
1268                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1269                                         }
1270                                 } else {
1271                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1272                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1273                                 }
1274                         }
1275                         MMPLAYER_CMD_UNLOCK(player);
1276                 }
1277                 break;
1278
1279         case GST_MESSAGE_STATE_CHANGED:
1280                 {
1281                         MMPlayerGstElement *mainbin;
1282                         const GValue *voldstate, *vnewstate, *vpending;
1283                         GstState oldstate = GST_STATE_NULL;
1284                         GstState newstate = GST_STATE_NULL;
1285                         GstState pending = GST_STATE_NULL;
1286
1287                         if (!(player->pipeline && player->pipeline->mainbin)) {
1288                                 LOGE("player pipeline handle is null");
1289                                 break;
1290                         }
1291
1292                         mainbin = player->pipeline->mainbin;
1293
1294                         /* we only handle messages from pipeline */
1295                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1296                                 break;
1297
1298                         /* get state info from msg */
1299                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1300                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1301                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1302
1303                         if (!voldstate || !vnewstate) {
1304                                 LOGE("received msg has wrong format.");
1305                                 break;
1306                         }
1307
1308                         oldstate = (GstState)voldstate->data[0].v_int;
1309                         newstate = (GstState)vnewstate->data[0].v_int;
1310                         if (vpending)
1311                                 pending = (GstState)vpending->data[0].v_int;
1312
1313                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1314                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1315                                 gst_element_state_get_name((GstState)oldstate),
1316                                 gst_element_state_get_name((GstState)newstate),
1317                                 gst_element_state_get_name((GstState)pending));
1318
1319                         if (newstate == GST_STATE_PLAYING) {
1320                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1321
1322                                         int retVal = MM_ERROR_NONE;
1323                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1324
1325                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1326
1327                                         if (MM_ERROR_NONE != retVal)
1328                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1329
1330                                         player->pending_seek.is_pending = FALSE;
1331                                 }
1332                         }
1333
1334                         if (oldstate == newstate) {
1335                                 LOGD("pipeline reports state transition to old state");
1336                                 break;
1337                         }
1338
1339                         switch (newstate) {
1340                         case GST_STATE_VOID_PENDING:
1341                                 break;
1342
1343                         case GST_STATE_NULL:
1344                                 break;
1345
1346                         case GST_STATE_READY:
1347                                 break;
1348
1349                         case GST_STATE_PAUSED:
1350                                 {
1351                                         gboolean prepare_async = FALSE;
1352                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1353
1354                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1355                                                 __mmplayer_configure_audio_callback(player);
1356
1357                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1358                                                 // managed prepare async case
1359                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1360                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1361                                         }
1362
1363                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1364                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1365
1366                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1367                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1368                                                                 player->total_maximum_bitrate, player->total_bitrate);
1369
1370                                                 if (player->pending_seek.is_pending) {
1371                                                         LOGW("trying to do pending seek");
1372                                                         MMPLAYER_CMD_LOCK(player);
1373                                                         __gst_pending_seek(player);
1374                                                         MMPLAYER_CMD_UNLOCK(player);
1375                                                 }
1376                                         }
1377                                 }
1378                                 break;
1379
1380                         case GST_STATE_PLAYING:
1381                                 {
1382                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1383
1384                                         if (MMPLAYER_IS_STREAMING(player)) {
1385                                                 // managed prepare async case when buffering is completed
1386                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1387                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1388                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1389                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1390
1391                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1392
1393                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1394                                                         if (player->streamer->buffering_percent < 100) {
1395
1396                                                                 MMMessageParamType msg_param = {0, };
1397                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1398
1399                                                                 msg_param.connection.buffering = 100;
1400                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1401                                                         }
1402                                                 }
1403                                         }
1404
1405                                         if (player->gapless.stream_changed) {
1406                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1407                                                 player->gapless.stream_changed = FALSE;
1408                                         }
1409
1410                                         if (player->doing_seek && async_done) {
1411                                                 player->doing_seek = FALSE;
1412                                                 async_done = FALSE;
1413                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1414                                         }
1415                                 }
1416                                 break;
1417
1418                         default:
1419                                 break;
1420                         }
1421                 }
1422                 break;
1423
1424         case GST_MESSAGE_CLOCK_LOST:
1425                         {
1426                                 GstClock *clock = NULL;
1427                                 gboolean need_new_clock = FALSE;
1428
1429                                 gst_message_parse_clock_lost(msg, &clock);
1430                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1431
1432                                 if (!player->videodec_linked)
1433                                         need_new_clock = TRUE;
1434                                 else if (!player->ini.use_system_clock)
1435                                         need_new_clock = TRUE;
1436
1437                                 if (need_new_clock) {
1438                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1439                                         __gst_pause(player, FALSE);
1440                                         __gst_resume(player, FALSE);
1441                                 }
1442                         }
1443                         break;
1444
1445         case GST_MESSAGE_NEW_CLOCK:
1446                         {
1447                                 GstClock *clock = NULL;
1448                                 gst_message_parse_new_clock(msg, &clock);
1449                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1450                         }
1451                         break;
1452
1453         case GST_MESSAGE_ELEMENT:
1454                         {
1455                                 const gchar *structure_name;
1456                                 gint count = 0, idx = 0;
1457                                 MMHandleType attrs = 0;
1458
1459                                 attrs = MMPLAYER_GET_ATTRS(player);
1460                                 if (!attrs) {
1461                                         LOGE("cannot get content attribute");
1462                                         break;
1463                                 }
1464
1465                                 if (gst_message_get_structure(msg) == NULL)
1466                                         break;
1467
1468                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1469                                 if (!structure_name)
1470                                         break;
1471
1472                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1473
1474                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1475                                         const GValue *var_info = NULL;
1476
1477                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1478                                         if (var_info != NULL) {
1479                                                 if (player->adaptive_info.var_list)
1480                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1481
1482                                                 /* share addr or copy the list */
1483                                                 player->adaptive_info.var_list =
1484                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1485
1486                                                 count = g_list_length(player->adaptive_info.var_list);
1487                                                 if (count > 0) {
1488                                                         VariantData *temp = NULL;
1489
1490                                                         /* print out for debug */
1491                                                         LOGD("num of variant_info %d", count);
1492                                                         for (idx = 0; idx < count; idx++) {
1493                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1494                                                                 if (temp)
1495                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1496                                                         }
1497                                                 }
1498                                         }
1499                                 }
1500
1501                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1502                                         gint num_buffers = 0;
1503                                         gint extra_num_buffers = 0;
1504
1505                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1506                                                 player->video_num_buffers = num_buffers;
1507                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1508                                         }
1509
1510                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1511                                                 player->video_extra_num_buffers = extra_num_buffers;
1512                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1513                                         }
1514                                         break;
1515                                 }
1516
1517                                 if (!strcmp(structure_name, "Language_list")) {
1518                                         const GValue *lang_list = NULL;
1519                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1520                                         if (lang_list != NULL) {
1521                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1522                                                 if (count > 1)
1523                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1524                                         }
1525                                 }
1526
1527                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1528                                         const GValue *lang_list = NULL;
1529                                         MMPlayerLangStruct *temp = NULL;
1530
1531                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1532                                         if (lang_list != NULL) {
1533                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1534                                                 if (count) {
1535                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1536                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1537                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1538                                                         if (mmf_attrs_commit(attrs))
1539                                                                 LOGE("failed to commit.\n");
1540                                                         LOGD("Total subtitle tracks = %d \n", count);
1541
1542                                                         while (count) {
1543                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1544                                                                 if (temp)
1545                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1546                                                                                                 temp->language_key, temp->language_code);
1547                                                                 count--;
1548                                                         }
1549                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1550                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1551                                                 }
1552                                         }
1553                                 }
1554
1555                                 /* custom message */
1556                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1557                                         MMMessageParamType msg_param = {0,};
1558                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1559                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1560                                 }
1561
1562                                 /* custom message for RTSP attribute :
1563                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1564                                     sdp which has contents info is received when rtsp connection is opened.
1565                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1566                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1567
1568                                         gchar *audio_codec = NULL;
1569                                         gchar *video_codec = NULL;
1570                                         gchar *video_frame_size = NULL;
1571
1572                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1573                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1574                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1575                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1576
1577                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1578                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1579                                         if (audio_codec)
1580                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1581
1582                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1583                                         LOGD("rtsp_video_codec : %s", video_codec);
1584                                         if (video_codec)
1585                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1586
1587                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1588                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1589                                         if (video_frame_size) {
1590
1591                                                 char *seperator = strchr(video_frame_size, '-');
1592                                                 if (seperator) {
1593
1594                                                         char video_width[10] = {0,};
1595                                                         int frame_size_len = strlen(video_frame_size);
1596                                                         int separtor_len = strlen(seperator);
1597
1598                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1599                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1600
1601                                                         seperator++;
1602                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1603                                                 }
1604                                         }
1605
1606                                         if (mmf_attrs_commit(attrs))
1607                                                 LOGE("failed to commit.\n");
1608                                 }
1609                         }
1610                         break;
1611
1612         case GST_MESSAGE_DURATION_CHANGED:
1613                 {
1614                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1615                         if (!__mmplayer_gst_handle_duration(player, msg))
1616                                 LOGW("failed to update duration");
1617                 }
1618
1619                 break;
1620
1621         case GST_MESSAGE_ASYNC_START:
1622                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1623                 break;
1624
1625         case GST_MESSAGE_ASYNC_DONE:
1626                 {
1627                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1628
1629                         /* we only handle messages from pipeline */
1630                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1631                                 break;
1632
1633                         if (player->doing_seek) {
1634                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1635                                         player->doing_seek = FALSE;
1636                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1637                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1638                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1639                                                 (player->streamer) &&
1640                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1641                                                 (player->streamer->is_buffering == FALSE)) {
1642                                                 GstQuery *query = NULL;
1643                                                 gboolean busy = FALSE;
1644                                                 gint percent = 0;
1645
1646                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1647                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1648                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1649                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1650                                                         gst_query_unref(query);
1651
1652                                                         LOGD("buffered percent(%s): %d\n",
1653                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1654                                                 }
1655
1656                                                 if (percent >= 100) {
1657                                                         player->streamer->is_buffering = FALSE;
1658                                                         __mmplayer_handle_buffering_message(player);
1659                                                 }
1660                                         }
1661
1662                                         async_done = TRUE;
1663                                 }
1664                         }
1665                 }
1666                 break;
1667
1668         #if 0 /* delete unnecessary logs */
1669         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1670         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1671         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1672         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1673         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1674         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1675         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1676         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1677         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1678         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1679         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1680         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1681         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1682         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1683         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1684         #endif
1685
1686         default:
1687                 break;
1688         }
1689
1690         /* should not call 'gst_message_unref(msg)' */
1691         return;
1692 }
1693
1694 static gboolean
1695 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1696 {
1697         gint64 bytes = 0;
1698
1699         MMPLAYER_FENTER();
1700
1701         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1702         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1703
1704         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1705                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1706                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1707
1708                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1709                         LOGD("data total size of http content: %lld", bytes);
1710                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1711                 }
1712         } else
1713                 /* handling audio clip which has vbr. means duration is keep changing */
1714                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1715
1716         MMPLAYER_FLEAVE();
1717
1718         return TRUE;
1719 }
1720
1721 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1722                 mm_player_spherical_metadata_t *metadata) {
1723         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1724         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1725         gst_tag_list_get_string(tags, "stitching_software",
1726                         &metadata->stitching_software);
1727         gst_tag_list_get_string(tags, "projection_type",
1728                         &metadata->projection_type_string);
1729         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1730         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1731         gst_tag_list_get_int(tags, "init_view_heading",
1732                         &metadata->init_view_heading);
1733         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1734         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1735         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1736         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1737                         &metadata->full_pano_width_pixels);
1738         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1739                         &metadata->full_pano_height_pixels);
1740         gst_tag_list_get_int(tags, "cropped_area_image_width",
1741                         &metadata->cropped_area_image_width);
1742         gst_tag_list_get_int(tags, "cropped_area_image_height",
1743                         &metadata->cropped_area_image_height);
1744         gst_tag_list_get_int(tags, "cropped_area_left",
1745                         &metadata->cropped_area_left);
1746         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1747         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1748         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1749         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1750 }
1751
1752 static gboolean
1753 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1754 {
1755
1756 /* macro for better code readability */
1757 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1758 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1759         if (string != NULL) { \
1760                 SECURE_LOGD("update tag string : %s\n", string); \
1761                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1762                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1763                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1764                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1765                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1766                         g_free(new_string); \
1767                         new_string = NULL; \
1768                 } else { \
1769                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1770                 } \
1771                 g_free(string); \
1772                 string = NULL; \
1773         } \
1774 }
1775
1776 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1777 do {    \
1778         GstSample *sample = NULL;\
1779         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1780                 GstMapInfo info = GST_MAP_INFO_INIT;\
1781                 buffer = gst_sample_get_buffer(sample);\
1782                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1783                         LOGD("failed to get image data from tag");\
1784                         gst_sample_unref(sample);\
1785                         return FALSE;\
1786                 } \
1787                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1788                 MMPLAYER_FREEIF(player->album_art);\
1789                 player->album_art = (gchar *)g_malloc(info.size);\
1790                 if (player->album_art) {\
1791                         memcpy(player->album_art, info.data, info.size);\
1792                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1793                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1794                                 msg_param.data = (void *)player->album_art;\
1795                                 msg_param.size = info.size;\
1796                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1797                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1798                         } \
1799                 } \
1800                 gst_buffer_unmap(buffer, &info);\
1801                 gst_sample_unref(sample);\
1802         }       \
1803 } while (0)
1804
1805 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1806 do {    \
1807         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1808                 if (v_uint) { \
1809                         int i = 0; \
1810                         gchar *tag_list_str = NULL; \
1811                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1812                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1813                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1814                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1815                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1816                         else \
1817                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1818                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1819                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1820                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1821                                 player->bitrate[track_type] = v_uint; \
1822                                 player->total_bitrate = 0; \
1823                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1824                                         player->total_bitrate += player->bitrate[i]; \
1825                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1826                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1827                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1828                                 player->maximum_bitrate[track_type] = v_uint; \
1829                                 player->total_maximum_bitrate = 0; \
1830                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1831                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1832                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1833                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1834                         } else { \
1835                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1836                         } \
1837                         v_uint = 0;\
1838                         g_free(tag_list_str); \
1839                 } \
1840         } \
1841 } while (0)
1842
1843 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1844 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1845         if (date != NULL) {\
1846                 string = g_strdup_printf("%d", g_date_get_year(date));\
1847                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1848                 SECURE_LOGD("metainfo year : %s\n", string);\
1849                 MMPLAYER_FREEIF(string);\
1850                 g_date_free(date);\
1851         } \
1852 }
1853
1854 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1856         if (datetime != NULL) {\
1857                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1858                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1859                 SECURE_LOGD("metainfo year : %s\n", string);\
1860                 MMPLAYER_FREEIF(string);\
1861                 gst_date_time_unref(datetime);\
1862         } \
1863 }
1864
1865 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1866 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1867         if (v_uint64) {\
1868                 /* FIXIT : don't know how to store date */\
1869                 g_assert(1);\
1870                 v_uint64 = 0;\
1871         } \
1872 }
1873
1874 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1875 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1876         if (v_double) {\
1877                 /* FIXIT : don't know how to store date */\
1878                 g_assert(1);\
1879                 v_double = 0;\
1880         } \
1881 }
1882
1883         /* function start */
1884         GstTagList* tag_list = NULL;
1885
1886         MMHandleType attrs = 0;
1887
1888         char *string = NULL;
1889         guint v_uint = 0;
1890         GDate *date = NULL;
1891         GstDateTime *datetime = NULL;
1892         /* album cover */
1893         GstBuffer *buffer = NULL;
1894         gint index = 0;
1895         MMMessageParamType msg_param = {0, };
1896
1897         /* currently not used. but those are needed for above macro */
1898         //guint64 v_uint64 = 0;
1899         //gdouble v_double = 0;
1900
1901         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1902
1903         attrs = MMPLAYER_GET_ATTRS(player);
1904
1905         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1906
1907         /* get tag list from gst message */
1908         gst_message_parse_tag(msg, &tag_list);
1909
1910         /* store tags to player attributes */
1911         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1912         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1913         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1914         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1915         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1916         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1917         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1918         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1919         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1920         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1922         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1923         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1924         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1925         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1926         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1927         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1928         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1929         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1930         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1931         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1932         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1933         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1934         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1937         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1938         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1939         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1940         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1941         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1942         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1943         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1944         MMPLAYER_UPDATE_TAG_LOCK(player);
1945         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1946         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1947         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1948         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1949         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1950         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1951         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1952         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1953         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1954         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1955         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1956         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1957         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1958         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1959         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1960
1961         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1962                 if (player->video360_metadata.is_spherical == -1) {
1963                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1964                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1965                                         player->video360_metadata.is_spherical);
1966                         if (player->video360_metadata.is_spherical == 1) {
1967                                 LOGD("This is spherical content for 360 playback.");
1968                                 player->is_content_spherical = TRUE;
1969                         } else {
1970                                 LOGD("This is not spherical content");
1971                                 player->is_content_spherical = FALSE;
1972                         }
1973
1974                         if (player->video360_metadata.projection_type_string) {
1975                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1976                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1977                                 } else {
1978                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1979                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1980                                 }
1981                         }
1982
1983                         if (player->video360_metadata.stereo_mode_string) {
1984                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1985                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1986                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1987                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1988                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1989                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1990                                 } else {
1991                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1992                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1993                                 }
1994                         }
1995                 }
1996         }
1997
1998         if (mmf_attrs_commit(attrs))
1999                 LOGE("failed to commit.\n");
2000
2001         gst_tag_list_free(tag_list);
2002
2003         return TRUE;
2004 }
2005
2006 static void
2007 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2008 {
2009         mm_player_t* player = (mm_player_t*) data;
2010
2011         MMPLAYER_FENTER();
2012
2013         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2014           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2015           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2016           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2017
2018           * [1] audio and video will be dumped with filesink.
2019           * [2] autoplugging is done by just using pad caps.
2020           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2021           * and the video will be dumped via filesink.
2022           */
2023         if (player->num_dynamic_pad == 0) {
2024                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2025
2026                 if (!__mmplayer_gst_remove_fakesink(player,
2027                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2028                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2029                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2030                          * source element are not same. To overcome this situation, this function will called
2031                          * several places and several times. Therefore, this is not an error case.
2032                          */
2033                         return;
2034         }
2035
2036         /* create dot before error-return. for debugging */
2037         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2038
2039         player->no_more_pad = TRUE;
2040
2041         MMPLAYER_FLEAVE();
2042 }
2043
2044 static gboolean
2045 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2046 {
2047         GstElement* parent = NULL;
2048
2049         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2050
2051         /* if we have no fakesink. this meas we are using decodebin which doesn'
2052         t need to add extra fakesink */
2053         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2054
2055         /* lock */
2056         MMPLAYER_FSINK_LOCK(player);
2057
2058         if (!fakesink->gst)
2059                 goto ERROR;
2060
2061         /* get parent of fakesink */
2062         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2063         if (!parent) {
2064                 LOGD("fakesink already removed\n");
2065                 goto ERROR;
2066         }
2067
2068         gst_element_set_locked_state(fakesink->gst, TRUE);
2069
2070         /* setting the state to NULL never returns async
2071          * so no need to wait for completion of state transiton
2072          */
2073         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2074                 LOGE("fakesink state change failure!\n");
2075                 /* FIXIT : should I return here? or try to proceed to next? */
2076                 /* return FALSE; */
2077
2078         /* remove fakesink from it's parent */
2079         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2080                 LOGE("failed to remove fakesink\n");
2081
2082                 gst_object_unref(parent);
2083
2084                 goto ERROR;
2085         }
2086
2087         gst_object_unref(parent);
2088
2089         LOGD("state-holder removed\n");
2090
2091         gst_element_set_locked_state(fakesink->gst, FALSE);
2092
2093         MMPLAYER_FSINK_UNLOCK(player);
2094         return TRUE;
2095
2096 ERROR:
2097         if (fakesink->gst)
2098                 gst_element_set_locked_state(fakesink->gst, FALSE);
2099
2100         MMPLAYER_FSINK_UNLOCK(player);
2101         return FALSE;
2102 }
2103
2104
2105 static void
2106 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2107 {
2108         GstPad *sinkpad = NULL;
2109         GstCaps* caps = NULL;
2110         GstElement* new_element = NULL;
2111         GstStructure* str = NULL;
2112         const gchar* name = NULL;
2113
2114         mm_player_t* player = (mm_player_t*) data;
2115
2116         MMPLAYER_FENTER();
2117
2118         MMPLAYER_RETURN_IF_FAIL(element && pad);
2119         MMPLAYER_RETURN_IF_FAIL(player &&
2120                                         player->pipeline &&
2121                                         player->pipeline->mainbin);
2122
2123
2124         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2125          * num_dynamic_pad will decreased after creating a sinkbin.
2126          */
2127         player->num_dynamic_pad++;
2128         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2129
2130         caps = gst_pad_query_caps(pad, NULL);
2131
2132         MMPLAYER_CHECK_NULL(caps);
2133
2134         /* clear  previous result*/
2135         player->have_dynamic_pad = FALSE;
2136
2137         str = gst_caps_get_structure(caps, 0);
2138
2139         if (!str) {
2140                 LOGE("cannot get structure from caps.\n");
2141                 goto ERROR;
2142         }
2143
2144         name = gst_structure_get_name(str);
2145         if (!name) {
2146                 LOGE("cannot get mimetype from structure.\n");
2147                 goto ERROR;
2148         }
2149
2150         if (strstr(name, "video")) {
2151                 gint stype = 0;
2152                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2153
2154                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2155                         if (player->v_stream_caps) {
2156                                 gst_caps_unref(player->v_stream_caps);
2157                                 player->v_stream_caps = NULL;
2158                         }
2159
2160                         new_element = gst_element_factory_make("fakesink", NULL);
2161                         player->num_dynamic_pad--;
2162                         goto NEW_ELEMENT;
2163                 }
2164         }
2165
2166         /* clear  previous result*/
2167         player->have_dynamic_pad = FALSE;
2168
2169         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2170                 LOGE("failed to autoplug for caps");
2171                 goto ERROR;
2172         }
2173
2174         /* check if there's dynamic pad*/
2175         if (player->have_dynamic_pad) {
2176                 LOGE("using pad caps assums there's no dynamic pad !\n");
2177                 goto ERROR;
2178         }
2179
2180         gst_caps_unref(caps);
2181         caps = NULL;
2182
2183 NEW_ELEMENT:
2184
2185         /* excute new_element if created*/
2186         if (new_element) {
2187                 LOGD("adding new element to pipeline\n");
2188
2189                 /* set state to READY before add to bin */
2190                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2191
2192                 /* add new element to the pipeline */
2193                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2194                         LOGE("failed to add autoplug element to bin\n");
2195                         goto ERROR;
2196                 }
2197
2198                 /* get pad from element */
2199                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2200                 if (!sinkpad) {
2201                         LOGE("failed to get sinkpad from autoplug element\n");
2202                         goto ERROR;
2203                 }
2204
2205                 /* link it */
2206                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2207                         LOGE("failed to link autoplug element\n");
2208                         goto ERROR;
2209                 }
2210
2211                 gst_object_unref(sinkpad);
2212                 sinkpad = NULL;
2213
2214                 /* run. setting PLAYING here since streamming source is live source */
2215                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2216         }
2217
2218         if (caps)
2219                 gst_caps_unref(caps);
2220
2221         MMPLAYER_FLEAVE();
2222
2223         return;
2224
2225 STATE_CHANGE_FAILED:
2226 ERROR:
2227         /* FIXIT : take care if new_element has already added to pipeline */
2228         if (new_element)
2229                 gst_object_unref(GST_OBJECT(new_element));
2230
2231         if (sinkpad)
2232                 gst_object_unref(GST_OBJECT(sinkpad));
2233
2234         if (caps)
2235                 gst_caps_unref(caps);
2236
2237         /* FIXIT : how to inform this error to MSL ????? */
2238         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2239          * then post an error to application
2240          */
2241 }
2242
2243 static GstPadProbeReturn
2244 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2245 {
2246         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2247         return GST_PAD_PROBE_OK;
2248 }
2249
2250 static GstPadProbeReturn
2251 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2252 {
2253         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2254         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2255         mm_player_t* player = (mm_player_t*)data;
2256         GstCaps* caps = NULL;
2257         GstStructure* str = NULL;
2258         const gchar* name = NULL;
2259         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2260
2261
2262         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2263                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2264                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2265                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2266                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2267                         return ret;
2268         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2269                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2270                         return ret;
2271         }
2272
2273         caps = gst_pad_query_caps(pad, NULL);
2274         if (!caps) {
2275                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2276                 return ret;
2277         }
2278
2279         str = gst_caps_get_structure(caps, 0);
2280         if (!str) {
2281                 LOGE("failed to get structure from caps");
2282                 goto ERROR;
2283         }
2284
2285         name = gst_structure_get_name(str);
2286         if (!name) {
2287                 LOGE("failed to get name from str");
2288                 goto ERROR;
2289         }
2290
2291         if (strstr(name, "audio")) {
2292                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2293         } else if (strstr(name, "video")) {
2294                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2295         } else {
2296                 /* text track is not supportable */
2297                 LOGE("invalid name %s", name);
2298                 goto ERROR;
2299         }
2300
2301         switch (GST_EVENT_TYPE(event)) {
2302         case GST_EVENT_EOS:
2303                 {
2304                         /* in case of gapless, drop eos event not to send it to sink */
2305                         if (player->gapless.reconfigure && !player->msg_posted) {
2306                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2307                                 ret = GST_PAD_PROBE_DROP;
2308                         }
2309                         break;
2310                 }
2311         case GST_EVENT_STREAM_START:
2312                 {
2313                         gint64 stop_running_time = 0;
2314                         gint64 position_running_time = 0;
2315                         gint64 position = 0;
2316                         gint idx = 0;
2317
2318                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2319                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2320                                         !(player->selector[idx].event_probe_id)) {
2321                                         /* LOGW("[%d] skip", idx); */
2322                                         continue;
2323                                 }
2324
2325                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2326                                         stop_running_time =
2327                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2328                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2329                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2330                                         stop_running_time =
2331                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2332                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2333                                 } else {
2334                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2335                                         stop_running_time =
2336                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2337                                                                 GST_FORMAT_TIME, player->duration);
2338                                 }
2339
2340                                 position_running_time =
2341                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2342                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2343
2344                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2345                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2346                                         idx,
2347                                         GST_TIME_ARGS(stop_running_time),
2348                                         GST_TIME_ARGS(position_running_time),
2349                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2350                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2351
2352                                 position_running_time = MAX(position_running_time, stop_running_time);
2353                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2354                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2355                                 position_running_time = MAX(0, position_running_time);
2356                                 position = MAX(position, position_running_time);
2357                         }
2358
2359                         if (position != 0) {
2360                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2361                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2362                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2363
2364                                 player->gapless.start_time[stream_type] += position;
2365                         }
2366                         break;
2367                 }
2368         case GST_EVENT_FLUSH_STOP:
2369                 {
2370                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2371                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2372                         player->gapless.start_time[stream_type] = 0;
2373                         break;
2374                 }
2375         case GST_EVENT_SEGMENT:
2376                 {
2377                         GstSegment segment;
2378                         GstEvent *tmpev;
2379
2380                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2381                         gst_event_copy_segment(event, &segment);
2382
2383                         if (segment.format == GST_FORMAT_TIME) {
2384                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2385                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2386                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2387                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2388                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2389                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2390
2391                                 /* keep the all the segment ev to cover the seeking */
2392                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2393                                 player->gapless.update_segment[stream_type] = TRUE;
2394
2395                                 if (!player->gapless.running)
2396                                         break;
2397
2398                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2399
2400                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2401
2402                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2403                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2404                                 gst_event_unref(event);
2405                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2406                         }
2407                         break;
2408                 }
2409         case GST_EVENT_QOS:
2410                 {
2411                         gdouble proportion = 0.0;
2412                         GstClockTimeDiff diff = 0;
2413                         GstClockTime timestamp = 0;
2414                         gint64 running_time_diff = -1;
2415                         GstQOSType type = 0;
2416                         GstEvent *tmpev = NULL;
2417
2418                         running_time_diff = player->gapless.segment[stream_type].base;
2419
2420                         if (running_time_diff <= 0) /* don't need to adjust */
2421                                 break;
2422
2423                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2424                         gst_event_unref(event);
2425
2426                         if (timestamp < running_time_diff) {
2427                                 LOGW("QOS event from previous group");
2428                                 ret = GST_PAD_PROBE_DROP;
2429                                 break;
2430                         }
2431
2432                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2433                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2434                                                 stream_type, GST_TIME_ARGS(timestamp),
2435                                                 GST_TIME_ARGS(running_time_diff),
2436                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2437
2438                         timestamp -= running_time_diff;
2439
2440                         /* That case is invalid for QoS events */
2441                         if (diff < 0 && -diff > timestamp) {
2442                                 LOGW("QOS event from previous group");
2443                                 ret = GST_PAD_PROBE_DROP;
2444                                 break;
2445                         }
2446
2447                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2448                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2449
2450                         break;
2451                 }
2452         default:
2453                 break;
2454         }
2455
2456 ERROR:
2457         if (caps)
2458                 gst_caps_unref(caps);
2459         return ret;
2460 }
2461
2462 static void
2463 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2464 {
2465         mm_player_t* player = NULL;
2466         GstElement* pipeline = NULL;
2467         GstElement* selector = NULL;
2468         GstElement* fakesink = NULL;
2469         GstCaps* caps = NULL;
2470         GstStructure* str = NULL;
2471         const gchar* name = NULL;
2472         GstPad* sinkpad = NULL;
2473         GstPad* srcpad = NULL;
2474         gboolean first_track = FALSE;
2475
2476         enum MainElementID elemId = MMPLAYER_M_NUM;
2477         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2478
2479         /* check handles */
2480         player = (mm_player_t*)data;
2481
2482         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2483         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2484
2485         //LOGD("pad-added signal handling\n");
2486
2487         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2488
2489         /* get mimetype from caps */
2490         caps = gst_pad_query_caps(pad, NULL);
2491         if (!caps) {
2492                 LOGE("cannot get caps from pad.\n");
2493                 goto ERROR;
2494         }
2495
2496         str = gst_caps_get_structure(caps, 0);
2497         if (!str) {
2498                 LOGE("cannot get structure from caps.\n");
2499                 goto ERROR;
2500         }
2501
2502         name = gst_structure_get_name(str);
2503         if (!name) {
2504                 LOGE("cannot get mimetype from structure.\n");
2505                 goto ERROR;
2506         }
2507
2508         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2509         //LOGD("detected mimetype : %s\n", name);
2510
2511         if (strstr(name, "video")) {
2512                 gint stype = 0;
2513
2514                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2515                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2516
2517                 /* don't make video because of not required, and not support multiple track */
2518                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2519                         LOGD("no video sink by null surface");
2520
2521                         gchar *caps_str = gst_caps_to_string(caps);
2522                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2523                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2524                                 player->set_mode.video_zc = TRUE;
2525
2526                         MMPLAYER_FREEIF(caps_str);
2527
2528                         if (player->v_stream_caps) {
2529                                 gst_caps_unref(player->v_stream_caps);
2530                                 player->v_stream_caps = NULL;
2531                         }
2532
2533                         LOGD("create fakesink instead of videobin");
2534
2535                         /* fake sink */
2536                         fakesink = gst_element_factory_make("fakesink", NULL);
2537                         if (fakesink == NULL) {
2538                                 LOGE("ERROR : fakesink create error\n");
2539                                 goto ERROR;
2540                         }
2541
2542                         if (player->ini.set_dump_element_flag)
2543                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2544
2545                         player->video_fakesink = fakesink;
2546
2547                         /* store it as it's sink element */
2548                         __mmplayer_add_sink(player, player->video_fakesink);
2549
2550                         gst_bin_add(GST_BIN(pipeline), fakesink);
2551
2552                         // link
2553                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2554
2555                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2556                                 LOGW("failed to link fakesink\n");
2557                                 gst_object_unref(GST_OBJECT(fakesink));
2558                                 goto ERROR;
2559                         }
2560
2561                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2562                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2563                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2564                         }
2565
2566                         if (player->set_mode.media_packet_video_stream) {
2567                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2568
2569                                 MMPLAYER_SIGNAL_CONNECT(player,
2570                                                                                 G_OBJECT(fakesink),
2571                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2572                                                                                 "handoff",
2573                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2574                                                                                 (gpointer)player);
2575
2576                                 MMPLAYER_SIGNAL_CONNECT(player,
2577                                                                                 G_OBJECT(fakesink),
2578                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2579                                                                                 "preroll-handoff",
2580                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2581                                                                                 (gpointer)player);
2582                         }
2583
2584                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2585                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2586                         goto DONE;
2587                 }
2588
2589                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2590                         __mmplayer_gst_decode_callback(elem, pad, player);
2591                         goto DONE;
2592                 }
2593
2594                 LOGD("video selector \n");
2595                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2596                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2597         } else {
2598                 if (strstr(name, "audio")) {
2599                         gint samplerate = 0;
2600                         gint channels = 0;
2601
2602                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2603                                 __mmplayer_gst_decode_callback(elem, pad, player);
2604                                 goto DONE;
2605                         }
2606
2607                         LOGD("audio selector \n");
2608                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2609                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2610
2611                         gst_structure_get_int(str, "rate", &samplerate);
2612                         gst_structure_get_int(str, "channels", &channels);
2613
2614                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2615                                 /* fake sink */
2616                                 fakesink = gst_element_factory_make("fakesink", NULL);
2617                                 if (fakesink == NULL) {
2618                                         LOGE("ERROR : fakesink create error\n");
2619                                         goto ERROR;
2620                                 }
2621
2622                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2623
2624                                 /* link */
2625                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2626
2627                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2628                                         LOGW("failed to link fakesink\n");
2629                                         gst_object_unref(GST_OBJECT(fakesink));
2630                                         goto ERROR;
2631                                 }
2632
2633                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2634                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2635                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2636
2637                                 goto DONE;
2638                         }
2639                 } else if (strstr(name, "text")) {
2640                         LOGD("text selector \n");
2641                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2642                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2643                 } else {
2644                         LOGE("wrong elem id \n");
2645                         goto ERROR;
2646                 }
2647         }
2648
2649         selector = player->pipeline->mainbin[elemId].gst;
2650         if (selector == NULL) {
2651                 selector = gst_element_factory_make("input-selector", NULL);
2652                 LOGD("Creating input-selector\n");
2653                 if (selector == NULL) {
2654                         LOGE("ERROR : input-selector create error\n");
2655                         goto ERROR;
2656                 }
2657                 g_object_set(selector, "sync-streams", TRUE, NULL);
2658
2659                 player->pipeline->mainbin[elemId].id = elemId;
2660                 player->pipeline->mainbin[elemId].gst = selector;
2661
2662                 first_track = TRUE;
2663                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2664
2665                 srcpad = gst_element_get_static_pad(selector, "src");
2666
2667                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2668                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2669                         __mmplayer_gst_selector_blocked, NULL, NULL);
2670                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2671                         __mmplayer_gst_selector_event_probe, player, NULL);
2672
2673                 gst_element_set_state(selector, GST_STATE_PAUSED);
2674                 gst_bin_add(GST_BIN(pipeline), selector);
2675         } else
2676                 LOGD("input-selector is already created.\n");
2677
2678         // link
2679         LOGD("Calling request pad with selector %p \n", selector);
2680         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2681
2682         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2683
2684         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2685                 LOGW("failed to link selector\n");
2686                 gst_object_unref(GST_OBJECT(selector));
2687                 goto ERROR;
2688         }
2689
2690         if (first_track) {
2691                 LOGD("this is first track --> active track \n");
2692                 g_object_set(selector, "active-pad", sinkpad, NULL);
2693         }
2694
2695         _mmplayer_track_update_info(player, stream_type, sinkpad);
2696
2697
2698 DONE:
2699 ERROR:
2700
2701         if (caps)
2702                 gst_caps_unref(caps);
2703
2704         if (sinkpad) {
2705                 gst_object_unref(GST_OBJECT(sinkpad));
2706                 sinkpad = NULL;
2707         }
2708
2709         if (srcpad) {
2710                 gst_object_unref(GST_OBJECT(srcpad));
2711                 srcpad = NULL;
2712         }
2713
2714         return;
2715 }
2716
2717 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2718 {
2719         GstPad* srcpad = NULL;
2720         MMHandleType attrs = 0;
2721         gint active_index = 0;
2722
2723         // [link] input-selector :: textbin
2724         srcpad = gst_element_get_static_pad(text_selector, "src");
2725         if (!srcpad) {
2726                 LOGE("failed to get srcpad from selector\n");
2727                 return;
2728         }
2729
2730         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2731
2732         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2733         if ((active_index != DEFAULT_TRACK) &&
2734                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2735                 LOGW("failed to change text track\n");
2736                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2737         }
2738
2739         player->no_more_pad = TRUE;
2740         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2741
2742         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2743         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2744                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2745                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2746         }
2747
2748         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2749
2750         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2751                 player->has_closed_caption = TRUE;
2752
2753         attrs = MMPLAYER_GET_ATTRS(player);
2754         if (attrs) {
2755                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2756                 if (mmf_attrs_commit(attrs))
2757                         LOGE("failed to commit.\n");
2758         } else
2759                 LOGE("cannot get content attribute");
2760
2761         if (srcpad) {
2762                 gst_object_unref(GST_OBJECT(srcpad));
2763                 srcpad = NULL;
2764         }
2765 }
2766
2767 static void
2768 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2769 {
2770         mm_player_t* player = (mm_player_t*)data;
2771         GstElement* selector = NULL;
2772         GstElement* queue = NULL;
2773
2774         GstPad* srcpad = NULL;
2775         GstPad* sinkpad = NULL;
2776         GstCaps* caps = NULL;
2777         gchar* caps_str = NULL;
2778
2779         MMPLAYER_FENTER();
2780         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2781
2782         caps = gst_pad_get_current_caps(pad);
2783         caps_str = gst_caps_to_string(caps);
2784         LOGD("deinterleave new caps : %s\n", caps_str);
2785         MMPLAYER_FREEIF(caps_str);
2786         gst_caps_unref(caps);
2787
2788         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2789                 LOGE("ERROR : queue create error\n");
2790                 goto ERROR;
2791         }
2792
2793         g_object_set(G_OBJECT(queue),
2794                                 "max-size-buffers", 10,
2795                                 "max-size-bytes", 0,
2796                                 "max-size-time", (guint64)0,
2797                                 NULL);
2798
2799         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2800
2801         if (!selector) {
2802                 LOGE("there is no audio channel selector.\n");
2803                 goto ERROR;
2804         }
2805
2806         srcpad = gst_element_get_static_pad(queue, "src");
2807         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2808
2809         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2810
2811         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2812                 LOGW("failed to link deinterleave - selector\n");
2813                 goto ERROR;
2814         }
2815
2816         gst_element_set_state(queue, GST_STATE_PAUSED);
2817         player->audio_mode.total_track_num++;
2818
2819 ERROR:
2820
2821         if (srcpad) {
2822                 gst_object_unref(GST_OBJECT(srcpad));
2823                 srcpad = NULL;
2824         }
2825
2826         if (sinkpad) {
2827                 gst_object_unref(GST_OBJECT(sinkpad));
2828                 sinkpad = NULL;
2829         }
2830
2831         MMPLAYER_FLEAVE();
2832         return;
2833 }
2834
2835 static void
2836 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2837 {
2838         mm_player_t* player = NULL;
2839         GstElement* selector = NULL;
2840         GstPad* sinkpad = NULL;
2841         gint active_index = 0;
2842         gchar* change_pad_name = NULL;
2843         GstCaps* caps = NULL;   // no need to unref
2844         gint default_audio_ch = 0;
2845
2846         MMPLAYER_FENTER();
2847         player = (mm_player_t*) data;
2848
2849         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2850
2851         if (!selector) {
2852                 LOGE("there is no audio channel selector.\n");
2853                 goto ERROR;
2854         }
2855
2856         active_index = player->audio_mode.active_pad_index;
2857
2858         if (active_index != default_audio_ch) {
2859                 gint audio_ch = default_audio_ch;
2860
2861                 /*To get the new pad from the selector*/
2862                 change_pad_name = g_strdup_printf("sink%d", active_index);
2863                 if (change_pad_name != NULL) {
2864                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2865                         if (sinkpad != NULL) {
2866                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2867                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2868
2869                                 audio_ch = active_index;
2870
2871                                 caps = gst_pad_get_current_caps(sinkpad);
2872                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2873
2874                                 __mmplayer_set_audio_attrs(player, caps);
2875                                 gst_caps_unref(caps);
2876                         }
2877                         MMPLAYER_FREEIF(change_pad_name);
2878                 }
2879
2880                 player->audio_mode.active_pad_index = audio_ch;
2881                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2882         }
2883
2884 ERROR:
2885
2886         if (sinkpad)
2887                 gst_object_unref(sinkpad);
2888
2889         MMPLAYER_FLEAVE();
2890         return;
2891 }
2892
2893 static void
2894 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2895 {
2896         mm_player_t* player = NULL;
2897         MMPlayerGstElement *mainbin = NULL;
2898
2899         GstElement* tee = NULL;
2900         GstElement* stereo_queue = NULL;
2901         GstElement* mono_queue = NULL;
2902         GstElement* conv = NULL;
2903         GstElement* filter = NULL;
2904         GstElement* deinterleave = NULL;
2905         GstElement* selector = NULL;
2906
2907         GstPad* srcpad = NULL;
2908         GstPad* selector_srcpad = NULL;
2909         GstPad* sinkpad = NULL;
2910         GstCaps* caps = NULL;
2911         gulong block_id = 0;
2912
2913         MMPLAYER_FENTER();
2914
2915         /* check handles */
2916         player = (mm_player_t*) data;
2917
2918         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2919         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2920
2921         mainbin = player->pipeline->mainbin;
2922
2923         /* tee */
2924         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2925                 LOGE("ERROR : tee create error\n");
2926                 goto ERROR;
2927         }
2928
2929         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2930         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2931
2932         gst_element_set_state(tee, GST_STATE_PAUSED);
2933
2934         /* queue */
2935         srcpad = gst_element_get_request_pad(tee, "src_%u");
2936         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2937                 LOGE("ERROR : stereo queue create error\n");
2938                 goto ERROR;
2939         }
2940
2941         g_object_set(G_OBJECT(stereo_queue),
2942                                 "max-size-buffers", 10,
2943                                 "max-size-bytes", 0,
2944                                 "max-size-time", (guint64)0,
2945                                 NULL);
2946
2947         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2948         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2949
2950         if (srcpad) {
2951                 gst_object_unref(GST_OBJECT(srcpad));
2952                 srcpad = NULL;
2953         }
2954
2955         srcpad = gst_element_get_request_pad(tee, "src_%u");
2956
2957         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2958                 LOGE("ERROR : mono queue create error\n");
2959                 goto ERROR;
2960         }
2961
2962         g_object_set(G_OBJECT(mono_queue),
2963                                 "max-size-buffers", 10,
2964                                 "max-size-bytes", 0,
2965                                 "max-size-time", (guint64)0,
2966                                 NULL);
2967
2968         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2969         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2970
2971         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2972         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2973
2974         /* audioconvert */
2975         srcpad = gst_element_get_static_pad(mono_queue, "src");
2976         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2977                 LOGE("ERROR : audioconvert create error\n");
2978                 goto ERROR;
2979         }
2980
2981         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2982         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2983
2984         /* caps filter */
2985         if (srcpad) {
2986                 gst_object_unref(GST_OBJECT(srcpad));
2987                 srcpad = NULL;
2988         }
2989         srcpad = gst_element_get_static_pad(conv, "src");
2990
2991         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2992                 LOGE("ERROR : capsfilter create error\n");
2993                 goto ERROR;
2994         }
2995
2996         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2997         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2998
2999         caps = gst_caps_from_string("audio/x-raw-int, "
3000                                 "width = (int) 16, "
3001                                 "depth = (int) 16, "
3002                                 "channels = (int) 2");
3003
3004         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3005         gst_caps_unref(caps);
3006
3007         gst_element_set_state(conv, GST_STATE_PAUSED);
3008         gst_element_set_state(filter, GST_STATE_PAUSED);
3009
3010         /* deinterleave */
3011         if (srcpad) {
3012                 gst_object_unref(GST_OBJECT(srcpad));
3013                 srcpad = NULL;
3014         }
3015         srcpad = gst_element_get_static_pad(filter, "src");
3016
3017         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3018                 LOGE("ERROR : deinterleave create error\n");
3019                 goto ERROR;
3020         }
3021
3022         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3023
3024         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3025                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3026
3027         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3028                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3029
3030         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3031         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3032
3033         /* selector */
3034         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3035         if (selector == NULL) {
3036                 LOGE("ERROR : audio-selector create error\n");
3037                 goto ERROR;
3038         }
3039
3040         g_object_set(selector, "sync-streams", TRUE, NULL);
3041         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3042
3043         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3044         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3045
3046         selector_srcpad = gst_element_get_static_pad(selector, "src");
3047
3048         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3049         block_id =
3050                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3051                         __mmplayer_gst_selector_blocked, NULL, NULL);
3052
3053         if (srcpad) {
3054                 gst_object_unref(GST_OBJECT(srcpad));
3055                 srcpad = NULL;
3056         }
3057
3058         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3059         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3060
3061         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3062                 LOGW("failed to link queue_stereo - selector\n");
3063                 goto ERROR;
3064         }
3065
3066         player->audio_mode.total_track_num++;
3067
3068         g_object_set(selector, "active-pad", sinkpad, NULL);
3069         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3070         gst_element_set_state(selector, GST_STATE_PAUSED);
3071
3072         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3073
3074 ERROR:
3075
3076         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3077         if (block_id != 0) {
3078                 gst_pad_remove_probe(selector_srcpad, block_id);
3079                 block_id = 0;
3080         }
3081
3082         if (sinkpad) {
3083                 gst_object_unref(GST_OBJECT(sinkpad));
3084                 sinkpad = NULL;
3085         }
3086
3087         if (srcpad) {
3088                 gst_object_unref(GST_OBJECT(srcpad));
3089                 srcpad = NULL;
3090         }
3091
3092         if (selector_srcpad) {
3093                 gst_object_unref(GST_OBJECT(selector_srcpad));
3094                 selector_srcpad = NULL;
3095         }
3096
3097         MMPLAYER_FLEAVE();
3098         return;
3099 }
3100
3101 static void
3102 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3103 {
3104         mm_player_t* player = NULL;
3105         GstPad* srcpad = NULL;
3106         GstElement* video_selector = NULL;
3107         GstElement* audio_selector = NULL;
3108         GstElement* text_selector = NULL;
3109         MMHandleType attrs = 0;
3110         gint active_index = 0;
3111         gint64 dur_bytes = 0L;
3112
3113         player = (mm_player_t*) data;
3114
3115         LOGD("no-more-pad signal handling\n");
3116
3117         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3118                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3119                 LOGW("no need to go more");
3120
3121                 if (player->gapless.reconfigure) {
3122                         player->gapless.reconfigure = FALSE;
3123                         MMPLAYER_PLAYBACK_UNLOCK(player);
3124                 }
3125
3126                 return;
3127         }
3128
3129         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3130                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3131                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3132                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3133                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3134
3135                 if (NULL == player->streamer) {
3136                         LOGW("invalid state for buffering");
3137                         goto ERROR;
3138                 }
3139
3140                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3141                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3142
3143                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3144                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3145
3146                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3147
3148                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3149                         LOGE("fail to get duration.\n");
3150
3151                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3152                 // use file information was already set on Q2 when it was created.
3153                 __mm_player_streaming_set_queue2(player->streamer,
3154                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3155                                                 TRUE,                                                           // use_buffering
3156                                                 buffer_bytes,
3157                                                 init_buffering_time,
3158                                                 1.0,                                                            // low percent
3159                                                 player->ini.http_buffering_limit,       // high percent
3160                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3161                                                 NULL,
3162                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3163         }
3164
3165         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3166         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3167         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3168         if (video_selector) {
3169                 // [link] input-selector :: videobin
3170                 srcpad = gst_element_get_static_pad(video_selector, "src");
3171                 if (!srcpad) {
3172                         LOGE("failed to get srcpad from video selector\n");
3173                         goto ERROR;
3174                 }
3175
3176                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3177                 if (!text_selector && !audio_selector)
3178                         player->no_more_pad = TRUE;
3179
3180                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3181
3182                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3183                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3184                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3185                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3186                 }
3187         }
3188
3189         if (audio_selector) {
3190                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3191                 if ((active_index != DEFAULT_TRACK) &&
3192                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3193                         LOGW("failed to change audio track\n");
3194                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3195                 }
3196
3197                 // [link] input-selector :: audiobin
3198                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3199                 if (!srcpad) {
3200                         LOGE("failed to get srcpad from selector\n");
3201                         goto ERROR;
3202                 }
3203
3204                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3205                 if (!text_selector)
3206                         player->no_more_pad = TRUE;
3207
3208                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3209                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3210                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3211                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3212                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3213                         }
3214
3215                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3216                 } else {
3217                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3218
3219                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3220                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3221                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3222                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3223                         }
3224                 }
3225
3226                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3227
3228                 attrs = MMPLAYER_GET_ATTRS(player);
3229                 if (attrs) {
3230                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3231                         if (mmf_attrs_commit(attrs))
3232                                 LOGE("failed to commit.\n");
3233                 } else
3234                         LOGE("cannot get content attribute");
3235         } else {
3236                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3237                         LOGD("There is no audio track : remove audiobin");
3238
3239                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3240                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3241
3242                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3243                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3244                 }
3245
3246                 if (player->num_dynamic_pad == 0)
3247                         __mmplayer_pipeline_complete(NULL, player);
3248         }
3249
3250         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3251                 if (text_selector)
3252                         __mmplayer_handle_text_decode_path(player, text_selector);
3253         }
3254
3255         MMPLAYER_FLEAVE();
3256
3257 ERROR:
3258         if (srcpad) {
3259                 gst_object_unref(GST_OBJECT(srcpad));
3260                 srcpad = NULL;
3261         }
3262
3263         if (player->gapless.reconfigure) {
3264                 player->gapless.reconfigure = FALSE;
3265                 MMPLAYER_PLAYBACK_UNLOCK(player);
3266         }
3267 }
3268
3269 static void
3270 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3271 {
3272         mm_player_t* player = NULL;
3273         MMHandleType attrs = 0;
3274         GstElement* pipeline = NULL;
3275         GstCaps* caps = NULL;
3276         gchar* caps_str = NULL;
3277         GstStructure* str = NULL;
3278         const gchar* name = NULL;
3279         GstPad* sinkpad = NULL;
3280         GstElement* sinkbin = NULL;
3281         gboolean reusing = FALSE;
3282         GstElement *text_selector = NULL;
3283
3284         /* check handles */
3285         player = (mm_player_t*) data;
3286
3287         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3288         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3289
3290         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3291
3292         attrs = MMPLAYER_GET_ATTRS(player);
3293         if (!attrs) {
3294                 LOGE("cannot get content attribute\n");
3295                 goto ERROR;
3296         }
3297
3298         /* get mimetype from caps */
3299         caps = gst_pad_query_caps(pad, NULL);
3300         if (!caps) {
3301                 LOGE("cannot get caps from pad.\n");
3302                 goto ERROR;
3303         }
3304         caps_str = gst_caps_to_string(caps);
3305
3306         str = gst_caps_get_structure(caps, 0);
3307         if (!str) {
3308                 LOGE("cannot get structure from caps.\n");
3309                 goto ERROR;
3310         }
3311
3312         name = gst_structure_get_name(str);
3313         if (!name) {
3314                 LOGE("cannot get mimetype from structure.\n");
3315                 goto ERROR;
3316         }
3317
3318         //LOGD("detected mimetype : %s\n", name);
3319
3320         if (strstr(name, "audio")) {
3321                 if (player->pipeline->audiobin == NULL) {
3322                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3323                                 LOGE("failed to create audiobin. continuing without audio\n");
3324                                 goto ERROR;
3325                         }
3326
3327                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3328                         LOGD("creating audiosink bin success\n");
3329                 } else {
3330                         reusing = TRUE;
3331                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3332                         LOGD("reusing audiobin\n");
3333                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3334                 }
3335
3336                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3337                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3338
3339                 player->audiosink_linked  = 1;
3340
3341                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3342                 if (!sinkpad) {
3343                         LOGE("failed to get pad from sinkbin\n");
3344                         goto ERROR;
3345                 }
3346         } else if (strstr(name, "video")) {
3347                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3348                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3349                         player->set_mode.video_zc = TRUE;
3350
3351                 if (player->pipeline->videobin == NULL) {
3352                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3353                         /* get video surface type */
3354                         int surface_type = 0;
3355                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3356                         LOGD("display_surface_type(%d)\n", surface_type);
3357
3358                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3359                                 LOGD("not make videobin because it dose not want\n");
3360                                 goto ERROR;
3361                         }
3362
3363                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3364                                 /* mark video overlay for acquire */
3365                                 if (player->video_overlay_resource == NULL) {
3366                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3367                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3368                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3369                                                         &player->video_overlay_resource)
3370                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3371                                                 LOGE("could not mark video_overlay resource for acquire\n");
3372                                                 goto ERROR;
3373                                         }
3374                                 }
3375                         }
3376
3377                         player->interrupted_by_resource = FALSE;
3378                         /* acquire resources for video overlay */
3379                         if (mm_resource_manager_commit(player->resource_manager) !=
3380                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3381                                 LOGE("could not acquire resources for video playing\n");
3382                                 goto ERROR;
3383                         }
3384
3385                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3386                                 LOGE("failed to create videobin. continuing without video\n");
3387                                 goto ERROR;
3388                         }
3389
3390                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3391                         LOGD("creating videosink bin success\n");
3392                 } else {
3393                         reusing = TRUE;
3394                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3395                         LOGD("re-using videobin\n");
3396                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3397                 }
3398
3399                 player->videosink_linked  = 1;
3400
3401                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3402                 if (!sinkpad) {
3403                         LOGE("failed to get pad from sinkbin\n");
3404                         goto ERROR;
3405                 }
3406         } else if (strstr(name, "text")) {
3407                 if (player->pipeline->textbin == NULL) {
3408                         MMPlayerGstElement* mainbin = NULL;
3409
3410                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3411                                 LOGE("failed to create text sink bin. continuing without text\n");
3412                                 goto ERROR;
3413                         }
3414
3415                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3416                         LOGD("creating textsink bin success\n");
3417
3418                         /* FIXIT : track number shouldn't be hardcoded */
3419                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3420
3421                         player->textsink_linked  = 1;
3422                         LOGI("player->textsink_linked set to 1\n");
3423
3424                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3425                         if (!sinkpad) {
3426                                 LOGE("failed to get pad from sinkbin\n");
3427                                 goto ERROR;
3428                         }
3429
3430                         mainbin = player->pipeline->mainbin;
3431
3432                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3433                                 /* input selector */
3434                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3435                                 if (!text_selector) {
3436                                         LOGE("failed to create subtitle input selector element\n");
3437                                         goto ERROR;
3438                                 }
3439                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3440
3441                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3442                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3443
3444                                 /* warm up */
3445                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3446                                         LOGE("failed to set state(READY) to sinkbin\n");
3447                                         goto ERROR;
3448                                 }
3449
3450                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3451                                         LOGW("failed to add subtitle input selector\n");
3452                                         goto ERROR;
3453                                 }
3454
3455                                 LOGD("created element input-selector");
3456
3457                         } else {
3458                                 LOGD("already having subtitle input selector");
3459                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3460                         }
3461                 } else {
3462                         if (!player->textsink_linked) {
3463                                 LOGD("re-using textbin\n");
3464
3465                                 reusing = TRUE;
3466                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3467
3468                                 player->textsink_linked  = 1;
3469                                 LOGI("player->textsink_linked set to 1\n");
3470                         } else
3471                                 LOGD("ignoring internal subtutle since external subtitle is available");
3472                 }
3473         } else {
3474                 LOGW("unknown type of elementary stream!ignoring it...\n");
3475                 goto ERROR;
3476         }
3477
3478         if (sinkbin) {
3479                 if (!reusing) {
3480                         /* warm up */
3481                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3482                                 LOGE("failed to set state(READY) to sinkbin\n");
3483                                 goto ERROR;
3484                         }
3485
3486                         /* Added for multi audio support to avoid adding audio bin again*/
3487                         /* add */
3488                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3489                                 LOGE("failed to add sinkbin to pipeline\n");
3490                                 goto ERROR;
3491                         }
3492                 }
3493
3494                 /* link */
3495                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3496                         LOGE("failed to get pad from sinkbin\n");
3497                         goto ERROR;
3498                 }
3499
3500                 if (!reusing) {
3501                         /* run */
3502                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3503                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3504                                 goto ERROR;
3505                         }
3506
3507                         if (text_selector) {
3508                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3509                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3510                                         goto ERROR;
3511                                 }
3512                         }
3513                 }
3514
3515                 gst_object_unref(sinkpad);
3516                 sinkpad = NULL;
3517         }
3518
3519         LOGD("[handle: %p] linking sink bin success", player);
3520
3521         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3522          * streaming task. if the task blocked, then buffer will not flow to the next element
3523          *(autoplugging element). so this is special hack for streaming. please try to remove it
3524          */
3525         /* dec stream count. we can remove fakesink if it's zero */
3526         if (player->num_dynamic_pad)
3527                 player->num_dynamic_pad--;
3528
3529         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3530
3531         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3532                 __mmplayer_pipeline_complete(NULL, player);
3533
3534 ERROR:
3535
3536         MMPLAYER_FREEIF(caps_str);
3537
3538         if (caps)
3539                 gst_caps_unref(caps);
3540
3541         if (sinkpad)
3542                 gst_object_unref(GST_OBJECT(sinkpad));
3543
3544         /* flusing out new attributes */
3545         if (mmf_attrs_commit(attrs))
3546                 LOGE("failed to comit attributes\n");
3547
3548         return;
3549 }
3550
3551 static gboolean
3552 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3553 {
3554         int pro_value = 0; // in the case of expection, default will be returned.
3555         int dest_angle = rotation_angle;
3556         int rotation_type = -1;
3557
3558         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3559         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3560         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3561
3562         if (rotation_angle >= 360)
3563                 dest_angle = rotation_angle - 360;
3564
3565         /* chech if supported or not */
3566         if (dest_angle % 90) {
3567                 LOGD("not supported rotation angle = %d", rotation_angle);
3568                 return FALSE;
3569         }
3570
3571         /*
3572           * tizenwlsink (A)
3573           * custom_convert - none (B)
3574           * videoflip - none (C)
3575           */
3576         if (player->set_mode.video_zc) {
3577                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3578                         rotation_type = ROTATION_USING_CUSTOM;
3579                 else // A
3580                         rotation_type = ROTATION_USING_SINK;
3581         } else {
3582                 int surface_type = 0;
3583                 rotation_type = ROTATION_USING_FLIP;
3584
3585                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3586                 LOGD("check display surface type attribute: %d", surface_type);
3587
3588                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3589                         rotation_type = ROTATION_USING_SINK;
3590                 else
3591                         rotation_type = ROTATION_USING_FLIP; //C
3592
3593                 LOGD("using %d type for rotation", rotation_type);
3594         }
3595
3596         /* get property value for setting */
3597         switch (rotation_type) {
3598         case ROTATION_USING_SINK: // tizenwlsink
3599                 {
3600                         switch (dest_angle) {
3601                         case 0:
3602                                 break;
3603                         case 90:
3604                                 pro_value = 3; // clockwise 90
3605                                 break;
3606                         case 180:
3607                                 pro_value = 2;
3608                                 break;
3609                         case 270:
3610                                 pro_value = 1; // counter-clockwise 90
3611                                 break;
3612                         }
3613                 }
3614                 break;
3615         case ROTATION_USING_CUSTOM:
3616                 {
3617                         gchar *ename = NULL;
3618                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3619
3620                         if (g_strrstr(ename, "fimcconvert")) {
3621                                 switch (dest_angle) {
3622                                 case 0:
3623                                         break;
3624                                 case 90:
3625                                         pro_value = 90; // clockwise 90
3626                                         break;
3627                                 case 180:
3628                                         pro_value = 180;
3629                                         break;
3630                                 case 270:
3631                                         pro_value = 270; // counter-clockwise 90
3632                                         break;
3633                                 }
3634                         }
3635                 }
3636                 break;
3637         case ROTATION_USING_FLIP: // videoflip
3638                 {
3639                                 switch (dest_angle) {
3640                                 case 0:
3641                                         break;
3642                                 case 90:
3643                                         pro_value = 1; // clockwise 90
3644                                         break;
3645                                 case 180:
3646                                         pro_value = 2;
3647                                         break;
3648                                 case 270:
3649                                         pro_value = 3; // counter-clockwise 90
3650                                         break;
3651                                 }
3652                 }
3653                 break;
3654         }
3655
3656         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3657
3658         *value = pro_value;
3659
3660         return TRUE;
3661 }
3662
3663 int
3664 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3665 {
3666         /* check video sinkbin is created */
3667         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3668                 player->pipeline &&
3669                 player->pipeline->videobin &&
3670                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3671                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3672                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3673
3674         return MM_ERROR_NONE;
3675 }
3676
3677 void
3678 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3679 {
3680         int rotation_value = 0;
3681         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3682         int user_angle = 0;
3683         MMPLAYER_FENTER();
3684
3685         /* check video sinkbin is created */
3686         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3687                 return;
3688
3689         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3690
3691         /* get rotation value to set */
3692         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3693         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3694         LOGD("set video param : rotate %d", rotation_value);
3695 }
3696
3697 void
3698 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3699 {
3700         MMHandleType attrs = 0;
3701         int visible = 0;
3702         MMPLAYER_FENTER();
3703
3704         /* check video sinkbin is created */
3705         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3706                 return;
3707
3708         attrs = MMPLAYER_GET_ATTRS(player);
3709         MMPLAYER_RETURN_IF_FAIL(attrs);
3710
3711         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3712         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3713         LOGD("set video param : visible %d", visible);
3714 }
3715
3716 void
3717 __mmplayer_video_param_set_display_method(mm_player_t* player)
3718 {
3719         MMHandleType attrs = 0;
3720         int display_method = 0;
3721         MMPLAYER_FENTER();
3722
3723         /* check video sinkbin is created */
3724         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3725                 return;
3726
3727         attrs = MMPLAYER_GET_ATTRS(player);
3728         MMPLAYER_RETURN_IF_FAIL(attrs);
3729
3730         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3731         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3732         LOGD("set video param : method %d", display_method);
3733 }
3734
3735 void
3736 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3737 {
3738         MMHandleType attrs = 0;
3739         void *handle = NULL;
3740         /*set wl_display*/
3741         int wl_window_x = 0;
3742         int wl_window_y = 0;
3743         int wl_window_width = 0;
3744         int wl_window_height = 0;
3745         MMPLAYER_FENTER();
3746
3747         /* check video sinkbin is created */
3748         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3749                 return;
3750
3751         attrs = MMPLAYER_GET_ATTRS(player);
3752         MMPLAYER_RETURN_IF_FAIL(attrs);
3753
3754         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3755
3756         if (handle) {
3757                 /*It should be set after setting window*/
3758                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3759                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3760                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3761                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3762
3763                 /* After setting window handle, set render      rectangle */
3764                 gst_video_overlay_set_render_rectangle(
3765                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3766                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3767                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3768                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3769
3770         }
3771 }
3772 void
3773 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3774 {
3775         MMHandleType attrs = 0;
3776         void *handle = NULL;
3777
3778         /* check video sinkbin is created */
3779         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3780                 return;
3781
3782         attrs = MMPLAYER_GET_ATTRS(player);
3783         MMPLAYER_RETURN_IF_FAIL(attrs);
3784
3785         /* common case if using overlay surface */
3786         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3787
3788         if (handle) {
3789                 /* default is using wl_surface_id */
3790                 unsigned int wl_surface_id      = 0;
3791                 wl_surface_id = *(int*)handle;
3792                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3793                 gst_video_overlay_set_wl_window_wl_surface_id(
3794                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3795                                 *(int*)handle);
3796         } else
3797                 /* FIXIT : is it error case? */
3798                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3799 }
3800
3801
3802 int
3803 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3804 {
3805         bool update_all_param = FALSE;
3806         MMPLAYER_FENTER();
3807
3808         /* check video sinkbin is created */
3809         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3810                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3811
3812         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3813                 LOGE("can not find tizenwlsink");
3814                 return MM_ERROR_PLAYER_INTERNAL;
3815         }
3816
3817         LOGD("param_name : %s", param_name);
3818         if (!g_strcmp0(param_name, "update_all_param"))
3819                 update_all_param = TRUE;
3820
3821         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3822                 __mmplayer_video_param_set_display_overlay(player);
3823         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3824                 __mmplayer_video_param_set_display_method(player);
3825         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3826                 __mmplayer_video_param_set_render_rectangle(player);
3827         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3828                 __mmplayer_video_param_set_display_visible(player);
3829         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3830                 __mmplayer_video_param_set_display_rotation(player);
3831
3832         return MM_ERROR_NONE;
3833 }
3834
3835 int
3836 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3837 {
3838         MMHandleType attrs = 0;
3839         int surface_type = 0;
3840         int ret = MM_ERROR_NONE;
3841
3842         MMPLAYER_FENTER();
3843
3844         /* check video sinkbin is created */
3845         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3846                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3847
3848         attrs = MMPLAYER_GET_ATTRS(player);
3849         if (!attrs) {
3850                 LOGE("cannot get content attribute");
3851                 return MM_ERROR_PLAYER_INTERNAL;
3852         }
3853         LOGD("param_name : %s", param_name);
3854
3855         /* update display surface */
3856         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3857         LOGD("check display surface type attribute: %d", surface_type);
3858
3859         /* configuring display */
3860         switch (surface_type) {
3861         case MM_DISPLAY_SURFACE_OVERLAY:
3862                 {
3863                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3864                         if (ret != MM_ERROR_NONE)
3865                                 return ret;
3866                 }
3867                 break;
3868         }
3869
3870         MMPLAYER_FLEAVE();
3871
3872         return MM_ERROR_NONE;
3873 }
3874
3875 int
3876 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3877 {
3878         gboolean disable_overlay = FALSE;
3879         mm_player_t* player = (mm_player_t*) hplayer;
3880         int ret = MM_ERROR_NONE;
3881
3882         MMPLAYER_FENTER();
3883         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3885                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3886                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3887
3888         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3889                 LOGW("Display control is not supported");
3890                 return MM_ERROR_PLAYER_INTERNAL;
3891         }
3892
3893         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3894
3895         if (audio_only == (bool)disable_overlay) {
3896                 LOGE("It's the same with current setting: (%d)", audio_only);
3897                 return MM_ERROR_NONE;
3898         }
3899
3900         if (audio_only) {
3901                 LOGE("disable overlay");
3902                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3903
3904                 /* release overlay resource */
3905                 if (player->video_overlay_resource != NULL) {
3906                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3907                                         player->video_overlay_resource);
3908                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3909                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3910                                 goto ERROR;
3911                         }
3912                         player->video_overlay_resource = NULL;
3913                 }
3914
3915                 ret = mm_resource_manager_commit(player->resource_manager);
3916                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3917                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3918                         goto ERROR;
3919                 }
3920         } else {
3921                 /* mark video overlay for acquire */
3922                 if (player->video_overlay_resource == NULL) {
3923                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3924                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3925                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3926                                         &player->video_overlay_resource);
3927                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3928                                 LOGE("could not prepare for video_overlay resource\n");
3929                                 goto ERROR;
3930                         }
3931                 }
3932
3933                 player->interrupted_by_resource = FALSE;
3934                 /* acquire resources for video overlay */
3935                 ret = mm_resource_manager_commit(player->resource_manager);
3936                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3937                         LOGE("could not acquire resources for video playing\n");
3938                         goto ERROR;
3939                 }
3940
3941                 LOGD("enable overlay");
3942                 __mmplayer_video_param_set_display_overlay(player);
3943                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3944         }
3945
3946 ERROR:
3947         MMPLAYER_FLEAVE();
3948         return MM_ERROR_NONE;
3949 }
3950
3951 int
3952 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3953 {
3954         mm_player_t* player = (mm_player_t*) hplayer;
3955         gboolean disable_overlay = FALSE;
3956
3957         MMPLAYER_FENTER();
3958
3959         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3960         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3961         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3962                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3963                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3964
3965         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3966                 LOGW("Display control is not supported");
3967                 return MM_ERROR_PLAYER_INTERNAL;
3968         }
3969
3970         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3971
3972         *paudio_only = (bool)(disable_overlay);
3973
3974         LOGD("audio_only : %d", *paudio_only);
3975
3976         MMPLAYER_FLEAVE();
3977
3978         return MM_ERROR_NONE;
3979 }
3980
3981 static int
3982 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3983 {
3984         GList* bucket = element_bucket;
3985         MMPlayerGstElement* element = NULL;
3986         MMPlayerGstElement* prv_element = NULL;
3987         gint successful_link_count = 0;
3988
3989         MMPLAYER_FENTER();
3990
3991         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3992
3993         prv_element = (MMPlayerGstElement*)bucket->data;
3994         bucket = bucket->next;
3995
3996         for (; bucket; bucket = bucket->next) {
3997                 element = (MMPlayerGstElement*)bucket->data;
3998
3999                 if (element && element->gst) {
4000                         /* If next element is audio appsrc then make a separate audio pipeline */
4001                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4002                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4003                                 prv_element = element;
4004                                 continue;
4005                         }
4006
4007                         if (prv_element && prv_element->gst) {
4008                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4009                                         LOGD("linking [%s] to [%s] success\n",
4010                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4011                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4012                                         successful_link_count++;
4013                                 } else {
4014                                         LOGD("linking [%s] to [%s] failed\n",
4015                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4017                                         return -1;
4018                                 }
4019                         }
4020                 }
4021
4022                 prv_element = element;
4023         }
4024
4025         MMPLAYER_FLEAVE();
4026
4027         return successful_link_count;
4028 }
4029
4030 static int
4031 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4032 {
4033         GList* bucket = element_bucket;
4034         MMPlayerGstElement* element = NULL;
4035         int successful_add_count = 0;
4036
4037         MMPLAYER_FENTER();
4038
4039         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4040         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4041
4042         for (; bucket; bucket = bucket->next) {
4043                 element = (MMPlayerGstElement*)bucket->data;
4044
4045                 if (element && element->gst) {
4046                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4047                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4048                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4049                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4050                                 return 0;
4051                         }
4052                         successful_add_count++;
4053                 }
4054         }
4055
4056         MMPLAYER_FLEAVE();
4057
4058         return successful_add_count;
4059 }
4060
4061 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4062 {
4063         mm_player_t* player = (mm_player_t*) data;
4064         GstCaps *caps = NULL;
4065         GstStructure *str = NULL;
4066         const char *name;
4067
4068         MMPLAYER_FENTER();
4069
4070         MMPLAYER_RETURN_IF_FAIL(pad)
4071         MMPLAYER_RETURN_IF_FAIL(unused)
4072         MMPLAYER_RETURN_IF_FAIL(data)
4073
4074         caps = gst_pad_get_current_caps(pad);
4075         if (!caps)
4076                 return;
4077
4078         str = gst_caps_get_structure(caps, 0);
4079         if (!str)
4080                 goto ERROR;
4081
4082         name = gst_structure_get_name(str);
4083         if (!name)
4084                 goto ERROR;
4085
4086         LOGD("name = %s\n", name);
4087
4088         if (strstr(name, "audio")) {
4089                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4090
4091                 if (player->audio_stream_changed_cb) {
4092                         LOGE("call the audio stream changed cb\n");
4093                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4094                 }
4095         } else if (strstr(name, "video")) {
4096                 if ((name = gst_structure_get_string(str, "format")))
4097                         player->set_mode.video_zc = name[0] == 'S';
4098
4099                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4100
4101                 if (player->video_stream_changed_cb) {
4102                         LOGE("call the video stream changed cb\n");
4103                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4104                 }
4105         } else
4106                 goto ERROR;
4107
4108 ERROR:
4109
4110         gst_caps_unref(caps);
4111
4112         MMPLAYER_FLEAVE();
4113
4114         return;
4115 }
4116
4117
4118
4119 /**
4120  * This function is to create audio pipeline for playing.
4121  *
4122  * @param       player          [in]    handle of player
4123  *
4124  * @return      This function returns zero on success.
4125  * @remark
4126  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4127  */
4128 /* macro for code readability. just for sinkbin-creation functions */
4129 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4130 do {\
4131         x_bin[x_id].id = x_id;\
4132         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4133         if (!x_bin[x_id].gst) {\
4134                 LOGE("failed to create %s \n", x_factory);\
4135                 goto ERROR;\
4136         } else {\
4137                 if (x_player->ini.set_dump_element_flag)\
4138                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4139         } \
4140         if (x_add_bucket)\
4141                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4142 } while (0);
4143
4144 static void
4145 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4146 {
4147         GList *l = NULL;
4148
4149         MMPLAYER_FENTER();
4150         MMPLAYER_RETURN_IF_FAIL(player);
4151
4152         if (player->audio_stream_buff_list) {
4153                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4154                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4155                         if (tmp) {
4156                                 if (send_all) {
4157                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4158                                         __mmplayer_audio_stream_send_data(player, tmp);
4159                                 }
4160                                 if (tmp->pcm_data)
4161                                         g_free(tmp->pcm_data);
4162                                 g_free(tmp);
4163                         }
4164                 }
4165                 g_list_free(player->audio_stream_buff_list);
4166                 player->audio_stream_buff_list = NULL;
4167         }
4168
4169         MMPLAYER_FLEAVE();
4170 }
4171
4172 static void
4173 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4174 {
4175         MMPlayerAudioStreamDataType audio_stream = { 0, };
4176
4177         MMPLAYER_FENTER();
4178         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4179
4180         audio_stream.bitrate = a_buffer->bitrate;
4181         audio_stream.channel = a_buffer->channel;
4182         audio_stream.depth = a_buffer->depth;
4183         audio_stream.is_little_endian = a_buffer->is_little_endian;
4184         audio_stream.channel_mask = a_buffer->channel_mask;
4185         audio_stream.data_size = a_buffer->data_size;
4186         audio_stream.data = a_buffer->pcm_data;
4187
4188         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4189         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4190
4191         MMPLAYER_FLEAVE();
4192 }
4193
4194 static void
4195 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4196 {
4197         mm_player_t* player = (mm_player_t*) data;
4198
4199         gint channel = 0;
4200         gint rate = 0;
4201         gint depth = 0;
4202         gint endianness = 0;
4203         guint64 channel_mask = 0;
4204         void *a_data = NULL;
4205         gint a_size = 0;
4206         mm_player_audio_stream_buff_t *a_buffer = NULL;
4207         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4208         GList *l = NULL;
4209
4210         MMPLAYER_FENTER();
4211         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4212
4213         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4214         a_data = mapinfo.data;
4215         a_size = mapinfo.size;
4216
4217         GstCaps *caps = gst_pad_get_current_caps(pad);
4218         GstStructure *structure = gst_caps_get_structure(caps, 0);
4219
4220         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4221         gst_structure_get_int(structure, "rate", &rate);
4222         gst_structure_get_int(structure, "channels", &channel);
4223         gst_structure_get_int(structure, "depth", &depth);
4224         gst_structure_get_int(structure, "endianness", &endianness);
4225         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4226         gst_caps_unref(GST_CAPS(caps));
4227
4228         /* In case of the sync is false, use buffer list.              *
4229          * The num of buffer list depends on the num of audio channels */
4230         if (player->audio_stream_buff_list) {
4231                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4232                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4233                         if (tmp) {
4234                                 if (channel_mask == tmp->channel_mask) {
4235                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4236                                         if (tmp->data_size + a_size < tmp->buff_size) {
4237                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4238                                                 tmp->data_size += a_size;
4239                                         } else {
4240                                                 /* send data to client */
4241                                                 __mmplayer_audio_stream_send_data(player, tmp);
4242
4243                                                 if (a_size > tmp->buff_size) {
4244                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4245                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4246                                                         if (tmp->pcm_data == NULL) {
4247                                                                 LOGE("failed to realloc data.");
4248                                                                 goto DONE;
4249                                                         }
4250                                                         tmp->buff_size = a_size;
4251                                                 }
4252                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4253                                                 memcpy(tmp->pcm_data, a_data, a_size);
4254                                                 tmp->data_size = a_size;
4255                                         }
4256                                         goto DONE;
4257                                 }
4258                         } else {
4259                                 LOGE("data is empty in list.");
4260                                 goto DONE;
4261                         }
4262                 }
4263         }
4264
4265         /* create new audio stream data */
4266         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4267         if (a_buffer == NULL) {
4268                 LOGE("failed to alloc data.");
4269                 goto DONE;
4270         }
4271         a_buffer->bitrate = rate;
4272         a_buffer->channel = channel;
4273         a_buffer->depth = depth;
4274         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4275         a_buffer->channel_mask = channel_mask;
4276         a_buffer->data_size = a_size;
4277
4278         if (!player->audio_stream_sink_sync) {
4279                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4280                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4281                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4282                 if (a_buffer->pcm_data == NULL) {
4283                         LOGE("failed to alloc data.");
4284                         g_free(a_buffer);
4285                         goto DONE;
4286                 }
4287                 memcpy(a_buffer->pcm_data, a_data, a_size);
4288                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4289                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4290         } else {
4291                 /* If sync is TRUE, send data directly. */
4292                 a_buffer->pcm_data = a_data;
4293                 __mmplayer_audio_stream_send_data(player, a_buffer);
4294                 g_free(a_buffer);
4295         }
4296
4297 DONE:
4298         gst_buffer_unmap(buffer, &mapinfo);
4299         MMPLAYER_FLEAVE();
4300 }
4301
4302 static void
4303 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4304 {
4305         mm_player_t* player = (mm_player_t*)data;
4306         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4307         GstPad* sinkpad = NULL;
4308         GstElement *queue = NULL, *sink = NULL;
4309
4310         MMPLAYER_FENTER();
4311         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4312
4313         queue = gst_element_factory_make("queue", NULL);
4314         if (queue == NULL) {
4315                 LOGD("fail make queue\n");
4316                 goto ERROR;
4317         }
4318
4319         sink = gst_element_factory_make("fakesink", NULL);
4320         if (sink == NULL) {
4321                 LOGD("fail make fakesink\n");
4322                 goto ERROR;
4323         }
4324
4325         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4326
4327         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4328                 LOGW("failed to link queue & sink\n");
4329                 goto ERROR;
4330         }
4331
4332         sinkpad = gst_element_get_static_pad(queue, "sink");
4333
4334         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4335                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4336                 goto ERROR;
4337         }
4338
4339         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4340
4341         gst_object_unref(sinkpad);
4342         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4343         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4344
4345         gst_element_set_state(sink, GST_STATE_PAUSED);
4346         gst_element_set_state(queue, GST_STATE_PAUSED);
4347
4348         MMPLAYER_SIGNAL_CONNECT(player,
4349                 G_OBJECT(sink),
4350                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4351                 "handoff",
4352                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4353                 (gpointer)player);
4354
4355         MMPLAYER_FLEAVE();
4356         return;
4357
4358 ERROR:
4359         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4360         if (queue) {
4361                 gst_object_unref(GST_OBJECT(queue));
4362                 queue = NULL;
4363         }
4364         if (sink) {
4365                 gst_object_unref(GST_OBJECT(sink));
4366                 sink = NULL;
4367         }
4368         if (sinkpad) {
4369                 gst_object_unref(GST_OBJECT(sinkpad));
4370                 sinkpad = NULL;
4371         }
4372
4373         return;
4374 }
4375
4376 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4377 {
4378         #define MAX_PROPS_LEN 128
4379         gint latency_mode = 0;
4380         gchar *stream_type = NULL;
4381         gchar *latency = NULL;
4382         gint stream_id = 0;
4383         gchar stream_props[MAX_PROPS_LEN] = {0,};
4384         GstStructure *props = NULL;
4385
4386         /* set volume table
4387          * It should be set after player creation through attribute.
4388          * But, it can not be changed during playing.
4389          */
4390         MMPLAYER_FENTER();
4391         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4392         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4393
4394         if (!stream_type) {
4395                 LOGE("stream_type is null.\n");
4396         } else {
4397                 if (player->sound.focus_id)
4398                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4399                                         stream_type, stream_id, player->sound.focus_id);
4400                 else
4401                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4402                                         stream_type, stream_id);
4403                 props = gst_structure_from_string(stream_props, NULL);
4404                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4405                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4406                         stream_type, stream_id, player->sound.focus_id, stream_props);
4407                 gst_structure_free(props);
4408         }
4409
4410         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4411
4412         switch (latency_mode) {
4413         case AUDIO_LATENCY_MODE_LOW:
4414                 latency = g_strndup("low", 3);
4415                 break;
4416         case AUDIO_LATENCY_MODE_MID:
4417                 latency = g_strndup("mid", 3);
4418                 break;
4419         case AUDIO_LATENCY_MODE_HIGH:
4420                 latency = g_strndup("high", 4);
4421                 break;
4422         };
4423
4424         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4425                         "latency", latency,
4426                         NULL);
4427
4428         LOGD("audiosink property - latency=%s \n", latency);
4429
4430         g_free(latency);
4431
4432         MMPLAYER_FLEAVE();
4433 }
4434
4435 static int
4436 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4437 {
4438         MMPlayerGstElement* first_element = NULL;
4439         MMPlayerGstElement* audiobin = NULL;
4440         MMHandleType attrs = 0;
4441         GstPad *pad = NULL;
4442         GstPad *ghostpad = NULL;
4443         GList* element_bucket = NULL;
4444         gboolean link_audio_sink_now = TRUE;
4445         int i = 0;
4446         GstCaps *acaps;
4447
4448         MMPLAYER_FENTER();
4449
4450         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4451
4452         /* alloc handles */
4453         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4454         if (!audiobin) {
4455                 LOGE("failed to allocate memory for audiobin\n");
4456                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4457         }
4458
4459         attrs = MMPLAYER_GET_ATTRS(player);
4460
4461         /* create bin */
4462         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4463         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4464         if (!audiobin[MMPLAYER_A_BIN].gst) {
4465                 LOGE("failed to create audiobin\n");
4466                 goto ERROR;
4467         }
4468
4469         /* take it */
4470         player->pipeline->audiobin = audiobin;
4471
4472         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4473
4474         /* Adding audiotp plugin for reverse trickplay feature */
4475 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4476
4477         /* converter */
4478         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4479
4480         /* replaygain volume */
4481         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4482         if (player->sound.rg_enable)
4483                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4484         else
4485                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4486
4487         /* resampler */
4488         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4489
4490         if (player->set_mode.pcm_extraction) {
4491                 // pcm extraction only and no sound output
4492                 if (player->audio_stream_render_cb_ex) {
4493                         char *caps_str = NULL;
4494                         GstCaps* caps = NULL;
4495                         gchar *format = NULL;
4496
4497                         /* capsfilter */
4498                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4499
4500                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4501
4502                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4503
4504                         caps = gst_caps_new_simple("audio/x-raw",
4505                                         "format", G_TYPE_STRING, format,
4506                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4507                                         "channels", G_TYPE_INT, player->pcm_channel,
4508                                         NULL);
4509                         caps_str = gst_caps_to_string(caps);
4510                         LOGD("new caps : %s\n", caps_str);
4511
4512                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4513
4514                         /* clean */
4515                         gst_caps_unref(caps);
4516                         MMPLAYER_FREEIF(caps_str);
4517
4518                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4519
4520                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4521                         /* raw pad handling signal */
4522                         MMPLAYER_SIGNAL_CONNECT(player,
4523                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4524                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4525                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4526                 } else {
4527                         int dst_samplerate = 0;
4528                         int dst_channels = 0;
4529                         int dst_depth = 0;
4530                         char *caps_str = NULL;
4531                         GstCaps* caps = NULL;
4532
4533                         /* get conf. values */
4534                         mm_attrs_multiple_get(player->attrs,
4535                                                 NULL,
4536                                                 "pcm_extraction_samplerate", &dst_samplerate,
4537                                                 "pcm_extraction_channels", &dst_channels,
4538                                                 "pcm_extraction_depth", &dst_depth,
4539                                                 NULL);
4540
4541                         /* capsfilter */
4542                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4543                         caps = gst_caps_new_simple("audio/x-raw",
4544                                         "rate", G_TYPE_INT, dst_samplerate,
4545                                         "channels", G_TYPE_INT, dst_channels,
4546                                         "depth", G_TYPE_INT, dst_depth,
4547                                         NULL);
4548                         caps_str = gst_caps_to_string(caps);
4549                         LOGD("new caps : %s\n", caps_str);
4550
4551                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4552
4553                         /* clean */
4554                         gst_caps_unref(caps);
4555                         MMPLAYER_FREEIF(caps_str);
4556
4557                         /* fake sink */
4558                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4559
4560                         /* set sync */
4561                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4562                 }
4563         } else {
4564                 // normal playback
4565                 //GstCaps* caps = NULL;
4566                 gint channels = 0;
4567
4568                 /* for logical volume control */
4569                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4570                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4571
4572                 if (player->sound.mute) {
4573                         LOGD("mute enabled\n");
4574                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4575                 }
4576
4577 #if 0
4578                 /*capsfilter */
4579                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4580                 caps = gst_caps_from_string("audio/x-raw-int, "
4581                                         "endianness = (int) LITTLE_ENDIAN, "
4582                                         "signed = (boolean) true, "
4583                                         "width = (int) 16, "
4584                                         "depth = (int) 16");
4585                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4586                 gst_caps_unref(caps);
4587 #endif
4588
4589                 /* check if multi-channels */
4590                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4591                         GstPad *srcpad = NULL;
4592                         GstCaps *caps = NULL;
4593
4594                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4595                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4596                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4597                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4598                                         if (str)
4599                                                 gst_structure_get_int(str, "channels", &channels);
4600                                         gst_caps_unref(caps);
4601                                 }
4602                                 gst_object_unref(srcpad);
4603                         }
4604                 }
4605
4606                 /* audio effect element. if audio effect is enabled */
4607                 if ((strcmp(player->ini.audioeffect_element, ""))
4608                         && (channels <= 2)
4609                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4610                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4611
4612                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4613
4614                         if ((!player->bypass_audio_effect)
4615                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4616                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4617                                         if (!_mmplayer_audio_effect_custom_apply(player))
4618                                                 LOGI("apply audio effect(custom) setting success\n");
4619                                 }
4620                         }
4621
4622                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4623                                 && (player->set_mode.rich_audio))
4624                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4625                 }
4626
4627                 /* create audio sink */
4628                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4629                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4630                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4631
4632                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4633                 if (player->is_360_feature_enabled &&
4634                         player->is_content_spherical &&
4635                         channels == 4 &&
4636                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4637                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4638                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4639
4640                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4641
4642                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4643
4644                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4645                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4646                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4647                         gst_caps_unref(acaps);
4648
4649                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4650                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4651                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4652                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4653
4654                         player->is_openal_plugin_used = TRUE;
4655
4656                         if (player->video360_yaw_radians <= M_PI &&
4657                                         player->video360_yaw_radians >= -M_PI &&
4658                                         player->video360_pitch_radians <= M_PI_2 &&
4659                                         player->video360_pitch_radians >= -M_PI_2) {
4660                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4661                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4662                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4663                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4664                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4665                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4666                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4667                         }
4668                 } else {
4669                         if (player->is_360_feature_enabled && player->is_content_spherical)
4670                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4671                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4672                 }
4673
4674                 /* qos on */
4675                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4676                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4677
4678
4679                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4680                         (player->videodec_linked && player->ini.use_system_clock)) {
4681                         LOGD("system clock will be used.\n");
4682                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4683                 }
4684
4685                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4686                         __mmplayer_gst_set_audiosink_property(player, attrs);
4687         }
4688
4689         if (audiobin[MMPLAYER_A_SINK].gst) {
4690                 GstPad *sink_pad = NULL;
4691                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4692                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4693                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4694                 gst_object_unref(GST_OBJECT(sink_pad));
4695         }
4696
4697         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4698
4699         /* adding created elements to bin */
4700         LOGD("adding created elements to bin\n");
4701         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4702                 LOGE("failed to add elements\n");
4703                 goto ERROR;
4704         }
4705
4706         /* linking elements in the bucket by added order. */
4707         LOGD("Linking elements in the bucket by added order.\n");
4708         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4709                 LOGE("failed to link elements\n");
4710                 goto ERROR;
4711         }
4712
4713         /* get first element's sinkpad for creating ghostpad */
4714         first_element = (MMPlayerGstElement *)element_bucket->data;
4715         if (!first_element) {
4716                 LOGE("failed to get first elem\n");
4717                 goto ERROR;
4718         }
4719
4720         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4721         if (!pad) {
4722                 LOGE("failed to get pad from first element of audiobin\n");
4723                 goto ERROR;
4724         }
4725
4726         ghostpad = gst_ghost_pad_new("sink", pad);
4727         if (!ghostpad) {
4728                 LOGE("failed to create ghostpad\n");
4729                 goto ERROR;
4730         }
4731
4732         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4733                 LOGE("failed to add ghostpad to audiobin\n");
4734                 goto ERROR;
4735         }
4736
4737         gst_object_unref(pad);
4738
4739         g_list_free(element_bucket);
4740         MMPLAYER_FLEAVE();
4741
4742         return MM_ERROR_NONE;
4743
4744 ERROR:
4745
4746         LOGD("ERROR : releasing audiobin\n");
4747
4748         if (pad)
4749                 gst_object_unref(GST_OBJECT(pad));
4750
4751         if (ghostpad)
4752                 gst_object_unref(GST_OBJECT(ghostpad));
4753
4754         if (element_bucket)
4755                 g_list_free(element_bucket);
4756
4757         /* release element which are not added to bin */
4758         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4759                 /* NOTE : skip bin */
4760                 if (audiobin[i].gst) {
4761                         GstObject* parent = NULL;
4762                         parent = gst_element_get_parent(audiobin[i].gst);
4763
4764                         if (!parent) {
4765                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4766                                 audiobin[i].gst = NULL;
4767                         } else
4768                                 gst_object_unref(GST_OBJECT(parent));
4769                 }
4770         }
4771
4772         /* release audiobin with it's childs */
4773         if (audiobin[MMPLAYER_A_BIN].gst)
4774                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4775
4776         MMPLAYER_FREEIF(audiobin);
4777
4778         player->pipeline->audiobin = NULL;
4779
4780         return MM_ERROR_PLAYER_INTERNAL;
4781 }
4782
4783 static GstPadProbeReturn
4784 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4785 {
4786         mm_player_t* player = (mm_player_t*) u_data;
4787         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4788         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4789
4790         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4791
4792         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4793                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4794
4795         return GST_PAD_PROBE_OK;
4796 }
4797
4798 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4799 {
4800         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4801 }
4802
4803 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4804 {
4805         int ret = MM_ERROR_NONE;
4806         GList *l = NULL;
4807         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4808         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4809
4810         MMPLAYER_VIDEO_BO_LOCK(player);
4811
4812         if (player->video_bo_list) {
4813                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4814                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4815                         if (tmp && tmp->bo == bo) {
4816                                 tmp->using = FALSE;
4817                                 LOGD("release bo %p", bo);
4818                                 tbm_bo_unref(tmp->bo);
4819                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4820                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4821                                 return ret;
4822                         }
4823                 }
4824         } else {
4825                 /* hw codec is running or the list was reset for DRC. */
4826                 LOGW("there is no bo list.");
4827         }
4828         MMPLAYER_VIDEO_BO_UNLOCK(player);
4829
4830         LOGW("failed to find bo %p", bo);
4831         return ret;
4832 }
4833
4834 static void
4835 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4836 {
4837         GList *l = NULL;
4838
4839         MMPLAYER_FENTER();
4840         MMPLAYER_RETURN_IF_FAIL(player);
4841
4842         MMPLAYER_VIDEO_BO_LOCK(player);
4843         if (player->video_bo_list) {
4844                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4845                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4846                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4847                         if (tmp) {
4848                                 if (tmp->bo)
4849                                         tbm_bo_unref(tmp->bo);
4850                                 g_free(tmp);
4851                         }
4852                 }
4853                 g_list_free(player->video_bo_list);
4854                 player->video_bo_list = NULL;
4855         }
4856         player->video_bo_size = 0;
4857         MMPLAYER_VIDEO_BO_UNLOCK(player);
4858
4859         MMPLAYER_FLEAVE();
4860         return;
4861 }
4862
4863 static void*
4864 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4865 {
4866         GList *l = NULL;
4867         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4868         gboolean ret = TRUE;
4869
4870         /* check DRC, if it is, destroy the prev bo list to create again */
4871         if (player->video_bo_size != size) {
4872                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4873                 __mmplayer_video_stream_destroy_bo_list(player);
4874                 player->video_bo_size = size;
4875         }
4876
4877         MMPLAYER_VIDEO_BO_LOCK(player);
4878
4879         if ((!player->video_bo_list) ||
4880                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4881
4882                 /* create bo list */
4883                 int idx = 0;
4884                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4885
4886                 if (player->video_bo_list) {
4887                         /* if bo list did not created all, try it again. */
4888                         idx = g_list_length(player->video_bo_list);
4889                         LOGD("bo list exist(len: %d)", idx);
4890                 }
4891
4892                 for (; idx < player->ini.num_of_video_bo; idx++) {
4893                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4894                         if (!bo_info) {
4895                                 LOGE("Fail to alloc bo_info.");
4896                                 break;
4897                         }
4898                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4899                         if (!bo_info->bo) {
4900                                 LOGE("Fail to tbm_bo_alloc.");
4901                                 g_free(bo_info);
4902                                 break;
4903                         }
4904                         bo_info->using = FALSE;
4905                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4906                 }
4907
4908                 /* update video num buffers */
4909                 player->video_num_buffers = idx;
4910                 if (idx == player->ini.num_of_video_bo)
4911                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4912
4913                 if (idx == 0) {
4914                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4915                         return NULL;
4916                 }
4917
4918                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4919         }
4920
4921         while (TRUE) {
4922                 /* get bo from list*/
4923                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4924                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4925                         if (tmp && (tmp->using == FALSE)) {
4926                                 LOGD("found bo %p to use", tmp->bo);
4927                                 tmp->using = TRUE;
4928                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4929                                 return tbm_bo_ref(tmp->bo);
4930                         }
4931                 }
4932                 if (!ret) {
4933                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4934                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4935                         return NULL;
4936                 }
4937
4938                 if (player->ini.video_bo_timeout <= 0) {
4939                         MMPLAYER_VIDEO_BO_WAIT(player);
4940                 } else {
4941                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4942                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4943                 }
4944                 continue;
4945         }
4946 }
4947
4948 static void
4949 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4950 {
4951         mm_player_t* player = (mm_player_t*)data;
4952         MMPLAYER_FENTER();
4953         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4954
4955         /* send prerolled pkt */
4956         player->video_stream_prerolled = FALSE;
4957
4958         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4959
4960         /* not to send prerolled pkt again */
4961         player->video_stream_prerolled = TRUE;
4962 }
4963
4964 static void
4965 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4966 {
4967         mm_player_t* player = (mm_player_t*)data;
4968         GstCaps *caps = NULL;
4969         MMPlayerVideoStreamDataType *stream = NULL;
4970         MMVideoBuffer *video_buffer = NULL;
4971         GstMemory *dataBlock = NULL;
4972         GstMemory *metaBlock = NULL;
4973         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4974         GstStructure *structure = NULL;
4975         const gchar *string_format = NULL;
4976         unsigned int fourcc = 0;
4977
4978         MMPLAYER_FENTER();
4979         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4980
4981         if (player->video_stream_prerolled) {
4982                 player->video_stream_prerolled = FALSE;
4983                 LOGD("skip the prerolled pkt not to send it again");
4984                 return;
4985         }
4986
4987         caps = gst_pad_get_current_caps(pad);
4988         if (caps == NULL) {
4989                 LOGE("Caps is NULL.");
4990                 return;
4991         }
4992
4993         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4994
4995         /* clear stream data structure */
4996         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4997         if (!stream) {
4998                 LOGE("failed to alloc mem for video data");
4999                 return;
5000         }
5001
5002         structure = gst_caps_get_structure(caps, 0);
5003         gst_structure_get_int(structure, "width", &(stream->width));
5004         gst_structure_get_int(structure, "height", &(stream->height));
5005         string_format = gst_structure_get_string(structure, "format");
5006         if (string_format)
5007                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5008         stream->format = util_get_pixtype(fourcc);
5009         gst_caps_unref(caps);
5010         caps = NULL;
5011
5012     /*
5013         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5014                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5015     */
5016
5017         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5018                 LOGE("Wrong condition!!");
5019                 goto ERROR;
5020         }
5021
5022         /* set size and timestamp */
5023         dataBlock = gst_buffer_peek_memory(buffer, 0);
5024         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5025         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5026
5027         /* check zero-copy */
5028         if (player->set_mode.video_zc &&
5029                 player->set_mode.media_packet_video_stream &&
5030                 gst_buffer_n_memory(buffer) > 1) {
5031                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5032                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5033                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5034         }
5035
5036         if (video_buffer) { /* hw codec */
5037                 /* set tbm bo */
5038                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5039                         int i = 0;
5040
5041                         /* copy pointer of tbm bo, stride, elevation */
5042                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5043                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5044                                 i++;
5045                         }
5046                 } else {
5047                         LOGE("Not support video buffer format");
5048                         goto ERROR;
5049                 }
5050                 memcpy(stream->stride, video_buffer->stride_width,
5051                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5052                 memcpy(stream->elevation, video_buffer->stride_height,
5053                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5054
5055                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5056                 stream->internal_buffer = gst_buffer_ref(buffer);
5057         } else { /* sw codec */
5058                 int i = 0;
5059                 int j = 0;
5060                 int k = 0;
5061                 int ret = TBM_SURFACE_ERROR_NONE;
5062                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5063                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5064                 int size = 0;
5065                 unsigned char *src = NULL;
5066                 unsigned char *dest = NULL;
5067                 tbm_bo_handle thandle;
5068                 tbm_surface_h surface;
5069                 tbm_surface_info_s info;
5070                 gboolean gst_ret;
5071
5072                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5073                 if (!gst_ret) {
5074                         LOGE("fail to gst_memory_map");
5075                         goto ERROR;
5076                 }
5077
5078
5079                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5080                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5081
5082                         ret = tbm_surface_get_info(surface, &info);
5083
5084                         if (ret != TBM_SURFACE_ERROR_NONE) {
5085                                 tbm_surface_destroy(surface);
5086                                 goto ERROR;
5087                         }
5088                         tbm_surface_destroy(surface);
5089
5090                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5091                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5092                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5093                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5094                         stream->stride[0] = info.planes[0].stride;
5095                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5096                         stream->stride[1] = info.planes[1].stride;
5097                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5098                         stream->stride[2] = info.planes[2].stride;
5099                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5100                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5101                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5102                         stream->stride[0] = stream->width * 4;
5103                         stream->elevation[0] = stream->height;
5104                         size = stream->stride[0] * stream->height;
5105                 } else {
5106                         LOGE("Not support format %d", stream->format);
5107                         goto ERROR;
5108                 }
5109
5110                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5111                 if (!stream->bo[0]) {
5112                         LOGE("Fail to tbm_bo_alloc!!");
5113                         goto ERROR;
5114                 }
5115
5116                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5117                 if (thandle.ptr && mapinfo.data) {
5118                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5119                                 for (i = 0; i < 3; i++) {
5120                                         src = mapinfo.data + src_offset[i];
5121                                         dest = thandle.ptr + info.planes[i].offset;
5122
5123                                         if (i > 0) k = 1;
5124                                         for (j = 0; j < stream->height>>k; j++) {
5125                                                 memcpy(dest, src, stream->width>>k);
5126                                                 src += src_stride[i];
5127                                                 dest += stream->stride[i];
5128                                         }
5129                                 }
5130                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5131                                 memcpy(thandle.ptr, mapinfo.data, size);
5132                         } else {
5133                                 LOGE("Not support format %d", stream->format);
5134                                 goto ERROR;
5135                         }
5136                 } else {
5137                         LOGE("data pointer is wrong. dest : %p, src : %p",
5138                                         thandle.ptr, mapinfo.data);
5139                         goto ERROR;
5140                 }
5141                 tbm_bo_unmap(stream->bo[0]);
5142         }
5143
5144         if (player->video_stream_cb) { /* This has been already checked at the entry */
5145                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5146                         LOGE("failed to send video stream data.");
5147                         goto ERROR;
5148                 }
5149         }
5150
5151         if (metaBlock)
5152                 gst_memory_unmap(metaBlock, &mapinfo);
5153         else
5154                 gst_memory_unmap(dataBlock, &mapinfo);
5155
5156         return;
5157
5158 ERROR:
5159         LOGE("release video stream resource.");
5160         if (metaBlock) {
5161                 int i = 0;
5162                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5163                         if (stream->bo[i])
5164                                 tbm_bo_unref(stream->bo[i]);
5165                 }
5166                 gst_memory_unmap(metaBlock, &mapinfo);
5167
5168                 /* unref gst buffer */
5169                 if (stream->internal_buffer)
5170                         gst_buffer_unref(stream->internal_buffer);
5171         } else if (dataBlock) {
5172                 if (stream->bo[0])
5173                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5174                 gst_memory_unmap(dataBlock, &mapinfo);
5175         }
5176
5177         g_free(stream);
5178         return;
5179 }
5180
5181 static int
5182 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5183 {
5184         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5185         GList* element_bucket = NULL;
5186
5187         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5188
5189         MMPLAYER_FENTER();
5190
5191         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5192                 LOGD("do not need to add video filters.");
5193                 return MM_ERROR_NONE;
5194         }
5195
5196         /* in case of sw codec except 360 playback,
5197          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5198         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5199         LOGD("using video converter: %s", video_csc);
5200
5201         /* set video rotator */
5202         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5203
5204         *bucket = element_bucket;
5205         MMPLAYER_FLEAVE();
5206         return MM_ERROR_NONE;
5207
5208 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5209         g_list_free(element_bucket);
5210
5211         *bucket = NULL;
5212         MMPLAYER_FLEAVE();
5213         return MM_ERROR_PLAYER_INTERNAL;
5214 }
5215
5216 /**
5217  * This function is to create video pipeline.
5218  *
5219  * @param       player          [in]    handle of player
5220  *              caps            [in]    src caps of decoder
5221  *              surface_type    [in]    surface type for video rendering
5222  *
5223  * @return      This function returns zero on success.
5224  * @remark
5225  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5226  */
5227 /**
5228   * VIDEO PIPELINE
5229   * - video overlay surface(arm/x86) : tizenwlsink
5230   */
5231 static int
5232 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5233 {
5234         GstPad *pad = NULL;
5235         MMHandleType attrs;
5236         GList*element_bucket = NULL;
5237         MMPlayerGstElement* first_element = NULL;
5238         MMPlayerGstElement* videobin = NULL;
5239         gchar *videosink_element = NULL;
5240
5241         MMPLAYER_FENTER();
5242
5243         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244
5245         /* alloc handles */
5246         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5247         if (!videobin)
5248                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5249
5250         player->pipeline->videobin = videobin;
5251
5252         attrs = MMPLAYER_GET_ATTRS(player);
5253         if (!attrs) {
5254                 LOGE("cannot get content attribute");
5255                 return MM_ERROR_PLAYER_INTERNAL;
5256         }
5257
5258         /* create bin */
5259         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5260         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5261         if (!videobin[MMPLAYER_V_BIN].gst) {
5262                 LOGE("failed to create videobin");
5263                 goto ERROR;
5264         }
5265
5266         int enable_video_decoded_cb = 0;
5267         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5268
5269         if (player->is_360_feature_enabled && player->is_content_spherical) {
5270                 LOGD("video360 elem will be added.");
5271
5272                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5273                                 "video-360", TRUE, player);
5274
5275                 /* Set spatial media metadata and/or user settings to the element.
5276                  * */
5277                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5278                                 "projection-type", player->video360_metadata.projection_type, NULL);
5279
5280                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5281                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5282
5283                 if (player->video360_metadata.full_pano_width_pixels &&
5284                                 player->video360_metadata.full_pano_height_pixels &&
5285                                 player->video360_metadata.cropped_area_image_width &&
5286                                 player->video360_metadata.cropped_area_image_height) {
5287                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5288                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5289                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5290                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5291                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5292                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5293                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5294                                         NULL);
5295                 }
5296
5297                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5298                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5299                                         "horizontal-fov", player->video360_horizontal_fov,
5300                                         "vertical-fov", player->video360_vertical_fov, NULL);
5301                 }
5302
5303                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5304                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5305                                         "zoom", 1.0f / player->video360_zoom, NULL);
5306                 }
5307
5308                 if (player->video360_yaw_radians <= M_PI &&
5309                                 player->video360_yaw_radians >= -M_PI &&
5310                                 player->video360_pitch_radians <= M_PI_2 &&
5311                                 player->video360_pitch_radians >= -M_PI_2) {
5312                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5313                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5314                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5315                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5316                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5317                                         "pose-yaw", player->video360_metadata.init_view_heading,
5318                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5319                 }
5320
5321                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5322                                 "passthrough", !player->is_video360_enabled, NULL);
5323         }
5324
5325         /* set video sink */
5326         switch (surface_type) {
5327         case MM_DISPLAY_SURFACE_OVERLAY:
5328                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5329                         goto ERROR;
5330                 if (strlen(player->ini.videosink_element_overlay) > 0)
5331                         videosink_element = player->ini.videosink_element_overlay;
5332                 else
5333                         goto ERROR;
5334                 break;
5335         case MM_DISPLAY_SURFACE_NULL:
5336                 if (strlen(player->ini.videosink_element_fake) > 0)
5337                         videosink_element = player->ini.videosink_element_fake;
5338                 else
5339                         goto ERROR;
5340                 break;
5341         case MM_DISPLAY_SURFACE_REMOTE:
5342                 if (strlen(player->ini.videosink_element_fake) > 0)
5343                         videosink_element = player->ini.videosink_element_fake;
5344                 else
5345                         goto ERROR;
5346                 break;
5347         default:
5348                 LOGE("unidentified surface type");
5349                 goto ERROR;
5350         }
5351         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5352
5353         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5354
5355         /* additional setting for sink plug-in */
5356         switch (surface_type) {
5357         case MM_DISPLAY_SURFACE_OVERLAY:
5358         {
5359                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5360                 if (!use_tbm) {
5361                         LOGD("selected videosink name: %s", videosink_element);
5362
5363                         /* support shard memory with S/W codec on HawkP */
5364                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5365                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5366                                         "use-tbm", use_tbm, NULL);
5367                         }
5368                 } else {
5369                         if (attrs) {
5370                                 int gapless = 0;
5371
5372                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5373
5374                                 if (gapless > 0) {
5375                                         LOGD("disable last-sample");
5376                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5377                                 }
5378                         }
5379                 }
5380                 if (player->set_mode.media_packet_video_stream) {
5381                         int enable = 0;
5382                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5383                         if (enable)
5384                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5385
5386                         MMPLAYER_SIGNAL_CONNECT(player,
5387                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5388                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5389                                                                         "handoff",
5390                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5391                                                                         (gpointer)player);
5392
5393                         MMPLAYER_SIGNAL_CONNECT(player,
5394                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5395                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5396                                                                         "preroll-handoff",
5397                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5398                                                                         (gpointer)player);
5399                 }
5400                 break;
5401         }
5402         case MM_DISPLAY_SURFACE_REMOTE:
5403         {
5404                 if (player->set_mode.media_packet_video_stream) {
5405                         LOGE("add data probe at videosink");
5406                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5407                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5408
5409                         MMPLAYER_SIGNAL_CONNECT(player,
5410                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5411                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5412                                                                         "handoff",
5413                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5414                                                                         (gpointer)player);
5415
5416                         MMPLAYER_SIGNAL_CONNECT(player,
5417                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5418                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5419                                                                         "preroll-handoff",
5420                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5421                                                                         (gpointer)player);
5422                         if (attrs) {
5423                                 int gapless = 0;
5424
5425                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5426
5427                                 if (gapless > 0) {
5428                                         LOGD("disable last-sample");
5429                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5430                                 }
5431                         }
5432                 }
5433                 break;
5434         }
5435         default:
5436                 break;
5437         }
5438
5439         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5440                 goto ERROR;
5441
5442         if (videobin[MMPLAYER_V_SINK].gst) {
5443                 GstPad *sink_pad = NULL;
5444                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5445                 if (sink_pad) {
5446                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5447                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5448                         gst_object_unref(GST_OBJECT(sink_pad));
5449                 } else
5450                         LOGW("failed to get sink pad from videosink\n");
5451         }
5452
5453         /* store it as it's sink element */
5454         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5455
5456         /* adding created elements to bin */
5457         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5458                 LOGE("failed to add elements\n");
5459                 goto ERROR;
5460         }
5461
5462         /* Linking elements in the bucket by added order */
5463         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5464                 LOGE("failed to link elements\n");
5465                 goto ERROR;
5466         }
5467
5468         /* get first element's sinkpad for creating ghostpad */
5469         if (element_bucket)
5470                 first_element = (MMPlayerGstElement *)element_bucket->data;
5471         if (!first_element) {
5472                 LOGE("failed to get first element from bucket\n");
5473                 goto ERROR;
5474         }
5475
5476         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5477         if (!pad) {
5478                 LOGE("failed to get pad from first element\n");
5479                 goto ERROR;
5480         }
5481
5482         /* create ghostpad */
5483         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5484         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5485                 LOGE("failed to add ghostpad to videobin\n");
5486                 goto ERROR;
5487         }
5488         gst_object_unref(pad);
5489
5490         /* done. free allocated variables */
5491         if (element_bucket)
5492                 g_list_free(element_bucket);
5493
5494         MMPLAYER_FLEAVE();
5495
5496         return MM_ERROR_NONE;
5497
5498 ERROR:
5499         LOGE("ERROR : releasing videobin\n");
5500
5501         g_list_free(element_bucket);
5502
5503         if (pad)
5504                 gst_object_unref(GST_OBJECT(pad));
5505
5506         /* release videobin with it's childs */
5507         if (videobin[MMPLAYER_V_BIN].gst)
5508                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5509
5510
5511         MMPLAYER_FREEIF(videobin);
5512
5513         player->pipeline->videobin = NULL;
5514
5515         return MM_ERROR_PLAYER_INTERNAL;
5516 }
5517
5518 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5519 {
5520         GList *element_bucket = NULL;
5521         MMPlayerGstElement *textbin = player->pipeline->textbin;
5522
5523         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5524         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5525         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5526                                                         "signal-handoffs", FALSE,
5527                                                         NULL);
5528
5529         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5530         MMPLAYER_SIGNAL_CONNECT(player,
5531                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5532                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5533                                                         "handoff",
5534                                                         G_CALLBACK(__mmplayer_update_subtitle),
5535                                                         (gpointer)player);
5536
5537         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5538         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5539         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5540
5541         if (!player->play_subtitle) {
5542                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5543                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5544         }
5545
5546         /* adding created elements to bin */
5547         LOGD("adding created elements to bin\n");
5548         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5549                 LOGE("failed to add elements\n");
5550                 goto ERROR;
5551         }
5552
5553         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5554         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5555         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5556
5557         /* linking elements in the bucket by added order. */
5558         LOGD("Linking elements in the bucket by added order.\n");
5559         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5560                 LOGE("failed to link elements\n");
5561                 goto ERROR;
5562         }
5563
5564         /* done. free allocated variables */
5565         g_list_free(element_bucket);
5566
5567         if (textbin[MMPLAYER_T_QUEUE].gst) {
5568                 GstPad *pad = NULL;
5569                 GstPad *ghostpad = NULL;
5570
5571                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5572                 if (!pad) {
5573                         LOGE("failed to get sink pad of text queue");
5574                         goto ERROR;
5575                 }
5576
5577                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5578                 gst_object_unref(pad);
5579
5580                 if (!ghostpad) {
5581                         LOGE("failed to create ghostpad of textbin\n");
5582                         goto ERROR;
5583                 }
5584
5585                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5586                         LOGE("failed to add ghostpad to textbin\n");
5587                         gst_object_unref(ghostpad);
5588                         goto ERROR;
5589                 }
5590         }
5591
5592         return MM_ERROR_NONE;
5593
5594 ERROR:
5595         g_list_free(element_bucket);
5596
5597         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5598                 LOGE("remove textbin sink from sink list");
5599                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5600         }
5601
5602         /* release element at __mmplayer_gst_create_text_sink_bin */
5603         return MM_ERROR_PLAYER_INTERNAL;
5604 }
5605
5606 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5607 {
5608         MMPlayerGstElement *textbin = NULL;
5609         GList *element_bucket = NULL;
5610         int surface_type = 0;
5611         gint i = 0;
5612
5613         MMPLAYER_FENTER();
5614
5615         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5616
5617         /* alloc handles */
5618         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5619         if (!textbin) {
5620                 LOGE("failed to allocate memory for textbin\n");
5621                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5622         }
5623
5624         /* create bin */
5625         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5626         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5627         if (!textbin[MMPLAYER_T_BIN].gst) {
5628                 LOGE("failed to create textbin\n");
5629                 goto ERROR;
5630         }
5631
5632         /* take it */
5633         player->pipeline->textbin = textbin;
5634
5635         /* fakesink */
5636         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5637         LOGD("surface type for subtitle : %d", surface_type);
5638         switch (surface_type) {
5639         case MM_DISPLAY_SURFACE_OVERLAY:
5640         case MM_DISPLAY_SURFACE_NULL:
5641         case MM_DISPLAY_SURFACE_REMOTE:
5642                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5643                         LOGE("failed to make plain text elements\n");
5644                         goto ERROR;
5645                 }
5646                 break;
5647         default:
5648                 goto ERROR;
5649                 break;
5650         }
5651
5652         MMPLAYER_FLEAVE();
5653
5654         return MM_ERROR_NONE;
5655
5656 ERROR:
5657
5658         LOGD("ERROR : releasing textbin\n");
5659
5660         g_list_free(element_bucket);
5661
5662         /* release signal */
5663         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5664
5665         /* release element which are not added to bin */
5666         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5667                 /* NOTE : skip bin */
5668                 if (textbin[i].gst) {
5669                         GstObject* parent = NULL;
5670                         parent = gst_element_get_parent(textbin[i].gst);
5671
5672                         if (!parent) {
5673                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5674                                 textbin[i].gst = NULL;
5675                         } else {
5676                                 gst_object_unref(GST_OBJECT(parent));
5677                         }
5678                 }
5679         }
5680
5681         /* release textbin with it's childs */
5682         if (textbin[MMPLAYER_T_BIN].gst)
5683                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5684
5685         MMPLAYER_FREEIF(player->pipeline->textbin);
5686         player->pipeline->textbin = NULL;
5687
5688         MMPLAYER_FLEAVE();
5689         return MM_ERROR_PLAYER_INTERNAL;
5690 }
5691
5692
5693 static int
5694 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5695 {
5696         MMPlayerGstElement* mainbin = NULL;
5697         MMPlayerGstElement* textbin = NULL;
5698         MMHandleType attrs = 0;
5699         GstElement *subsrc = NULL;
5700         GstElement *subparse = NULL;
5701         gchar *subtitle_uri = NULL;
5702         const gchar *charset = NULL;
5703         GstPad *pad = NULL;
5704
5705         MMPLAYER_FENTER();
5706
5707         /* get mainbin */
5708         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5709                                                                 player->pipeline &&
5710                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5711
5712         mainbin = player->pipeline->mainbin;
5713
5714         attrs = MMPLAYER_GET_ATTRS(player);
5715         if (!attrs) {
5716                 LOGE("cannot get content attribute\n");
5717                 return MM_ERROR_PLAYER_INTERNAL;
5718         }
5719
5720         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5721         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5722                 LOGE("subtitle uri is not proper filepath.\n");
5723                 return MM_ERROR_PLAYER_INVALID_URI;
5724         }
5725
5726         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5727                 LOGE("failed to get storage info of subtitle path");
5728                 return MM_ERROR_PLAYER_INVALID_URI;
5729         }
5730
5731         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5732
5733         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5734         player->subtitle_language_list = NULL;
5735         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5736
5737         /* create the subtitle source */
5738         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5739         if (!subsrc) {
5740                 LOGE("failed to create filesrc element\n");
5741                 goto ERROR;
5742         }
5743         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5744
5745         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5746         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5747
5748         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5749                 LOGW("failed to add queue\n");
5750                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5751                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5752                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5753                 goto ERROR;
5754         }
5755
5756         /* subparse */
5757         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5758         if (!subparse) {
5759                 LOGE("failed to create subparse element\n");
5760                 goto ERROR;
5761         }
5762
5763         charset = util_get_charset(subtitle_uri);
5764         if (charset) {
5765                 LOGD("detected charset is %s\n", charset);
5766                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5767         }
5768
5769         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5770         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5771
5772         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5773                 LOGW("failed to add subparse\n");
5774                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5775                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5776                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5777                 goto ERROR;
5778         }
5779
5780         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5781                 LOGW("failed to link subsrc and subparse\n");
5782                 goto ERROR;
5783         }
5784
5785         player->play_subtitle = TRUE;
5786         player->adjust_subtitle_pos = 0;
5787
5788         LOGD("play subtitle using subtitle file\n");
5789
5790         if (player->pipeline->textbin == NULL) {
5791                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5792                         LOGE("failed to create text sink bin. continuing without text\n");
5793                         goto ERROR;
5794                 }
5795
5796                 textbin = player->pipeline->textbin;
5797
5798                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5799                         LOGW("failed to add textbin\n");
5800
5801                         /* release signal */
5802                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5803
5804                         /* release textbin with it's childs */
5805                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5806                         MMPLAYER_FREEIF(player->pipeline->textbin);
5807                         player->pipeline->textbin = textbin = NULL;
5808                         goto ERROR;
5809                 }
5810
5811                 LOGD("link text input selector and textbin ghost pad");
5812
5813                 player->textsink_linked = 1;
5814                 player->external_text_idx = 0;
5815                 LOGI("player->textsink_linked set to 1\n");
5816         } else {
5817                 textbin = player->pipeline->textbin;
5818                 LOGD("text bin has been created. reuse it.");
5819                 player->external_text_idx = 1;
5820         }
5821
5822         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5823                 LOGW("failed to link subparse and textbin\n");
5824                 goto ERROR;
5825         }
5826
5827         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5828         if (!pad) {
5829                 LOGE("failed to get sink pad from textsink to probe data");
5830                 goto ERROR;
5831         }
5832
5833         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5834                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5835
5836         gst_object_unref(pad);
5837         pad = NULL;
5838
5839         /* create dot. for debugging */
5840         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5841         MMPLAYER_FLEAVE();
5842
5843         return MM_ERROR_NONE;
5844
5845 ERROR:
5846         /* release text pipeline resource */
5847         player->textsink_linked = 0;
5848
5849         /* release signal */
5850         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5851
5852         if (player->pipeline->textbin) {
5853                 LOGE("remove textbin");
5854
5855                 /* release textbin with it's childs */
5856                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5857                 MMPLAYER_FREEIF(player->pipeline->textbin);
5858                 player->pipeline->textbin = NULL;
5859
5860         }
5861
5862         /* release subtitle elem */
5863         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5864         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5865
5866         return MM_ERROR_PLAYER_INTERNAL;
5867 }
5868
5869 gboolean
5870 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5871 {
5872         mm_player_t* player = (mm_player_t*) data;
5873         MMMessageParamType msg = {0, };
5874         GstClockTime duration = 0;
5875         gpointer text = NULL;
5876         guint text_size = 0;
5877         gboolean ret = TRUE;
5878         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5879
5880         MMPLAYER_FENTER();
5881
5882         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5883         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5884
5885         if (player->is_subtitle_force_drop) {
5886                 LOGW("subtitle is dropped forcedly.");
5887                 return ret;
5888         }
5889
5890         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5891         text = mapinfo.data;
5892         text_size = mapinfo.size;
5893         duration = GST_BUFFER_DURATION(buffer);
5894
5895         if (player->set_mode.subtitle_off) {
5896                 LOGD("subtitle is OFF.\n");
5897                 return TRUE;
5898         }
5899
5900         if (!text || (text_size == 0)) {
5901                 LOGD("There is no subtitle to be displayed.\n");
5902                 return TRUE;
5903         }
5904
5905         msg.data = (void *) text;
5906         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5907
5908         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5909
5910         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5911         gst_buffer_unmap(buffer, &mapinfo);
5912
5913         MMPLAYER_FLEAVE();
5914
5915         return ret;
5916 }
5917
5918 static GstPadProbeReturn
5919 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5920 {
5921         mm_player_t *player = (mm_player_t *) u_data;
5922         GstClockTime cur_timestamp = 0;
5923         gint64 adjusted_timestamp = 0;
5924         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5925
5926         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5927
5928         if (player->set_mode.subtitle_off) {
5929                 LOGD("subtitle is OFF.\n");
5930                 return TRUE;
5931         }
5932
5933         if (player->adjust_subtitle_pos == 0) {
5934                 LOGD("nothing to do");
5935                 return TRUE;
5936         }
5937
5938         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5939         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5940
5941         if (adjusted_timestamp < 0) {
5942                 LOGD("adjusted_timestamp under zero");
5943                 MMPLAYER_FLEAVE();
5944                 return FALSE;
5945         }
5946
5947         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5948         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5949                                 GST_TIME_ARGS(cur_timestamp),
5950                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5951
5952         return GST_PAD_PROBE_OK;
5953 }
5954 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5955 {
5956         MMPLAYER_FENTER();
5957
5958         /* check player and subtitlebin are created */
5959         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5960         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5961
5962         if (position == 0) {
5963                 LOGD("nothing to do\n");
5964                 MMPLAYER_FLEAVE();
5965                 return MM_ERROR_NONE;
5966         }
5967
5968         switch (format) {
5969         case MM_PLAYER_POS_FORMAT_TIME:
5970                 {
5971                         /* check current postion */
5972                         player->adjust_subtitle_pos = position;
5973
5974                         LOGD("save adjust_subtitle_pos in player") ;
5975                 }
5976                 break;
5977
5978         default:
5979                 {
5980                         LOGW("invalid format.\n");
5981                         MMPLAYER_FLEAVE();
5982                         return MM_ERROR_INVALID_ARGUMENT;
5983                 }
5984         }
5985
5986         MMPLAYER_FLEAVE();
5987
5988         return MM_ERROR_NONE;
5989 }
5990 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5991 {
5992         MMPLAYER_FENTER();
5993         LOGD("adjusting video_pos in player") ;
5994         int current_pos = 0;
5995         /* check player and videobin are created */
5996         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5997         if (!player->pipeline->videobin ||
5998                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5999                 LOGD("no video pipeline or sink is there");
6000                 return MM_ERROR_PLAYER_INVALID_STATE ;
6001         }
6002         if (offset == 0) {
6003                 LOGD("nothing to do\n");
6004                 MMPLAYER_FLEAVE();
6005                 return MM_ERROR_NONE;
6006         }
6007         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6008                 LOGD("failed to get current position");
6009                 return MM_ERROR_PLAYER_INTERNAL;
6010         }
6011         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6012                 LOGD("enter video delay is valid");
6013         } else {
6014                 LOGD("enter video delay is crossing content boundary");
6015                 return MM_ERROR_INVALID_ARGUMENT ;
6016         }
6017         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6018         LOGD("video delay has been done");
6019         MMPLAYER_FLEAVE();
6020
6021         return MM_ERROR_NONE;
6022 }
6023
6024 static void
6025 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6026 {
6027         GstElement *appsrc = element;
6028         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6029         GstBuffer *buffer = NULL;
6030         GstFlowReturn ret = GST_FLOW_OK;
6031         gint len = size;
6032
6033         MMPLAYER_RETURN_IF_FAIL(element);
6034         MMPLAYER_RETURN_IF_FAIL(buf);
6035
6036         buffer = gst_buffer_new();
6037
6038         if (buf->offset >= buf->len) {
6039                 LOGD("call eos appsrc\n");
6040                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6041                 return;
6042         }
6043
6044         if (buf->len - buf->offset < size)
6045                 len = buf->len - buf->offset;
6046
6047         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6048         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6049         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6050
6051         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6052         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6053
6054         buf->offset += len;
6055 }
6056
6057 static gboolean
6058 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6059 {
6060         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6061
6062         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6063
6064         buf->offset  = (int)size;
6065
6066         return TRUE;
6067 }
6068
6069 static GstBusSyncReply
6070 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6071 {
6072         mm_player_t *player = (mm_player_t *)data;
6073         GstBusSyncReply reply = GST_BUS_DROP;
6074
6075         if (!(player->pipeline && player->pipeline->mainbin)) {
6076                 LOGE("player pipeline handle is null");
6077                 return GST_BUS_PASS;
6078         }
6079
6080         if (!__mmplayer_check_useful_message(player, message)) {
6081                 gst_message_unref(message);
6082                 return GST_BUS_DROP;
6083         }
6084
6085         switch (GST_MESSAGE_TYPE(message)) {
6086         case GST_MESSAGE_STATE_CHANGED:
6087                 /* post directly for fast launch */
6088                 if (player->sync_handler) {
6089                         __mmplayer_gst_callback(message, player);
6090                         reply = GST_BUS_DROP;
6091                 } else
6092                         reply = GST_BUS_PASS;
6093                 break;
6094         case GST_MESSAGE_TAG:
6095                 __mmplayer_gst_extract_tag_from_msg(player, message);
6096
6097                 #if 0 // debug
6098                 {
6099                         GstTagList *tags = NULL;
6100
6101                         gst_message_parse_tag(message, &tags);
6102                         if (tags) {
6103                                 LOGE("TAGS received from element \"%s\".\n",
6104                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6105
6106                                 gst_tag_list_foreach(tags, print_tag, NULL);
6107                                 gst_tag_list_free(tags);
6108                                 tags = NULL;
6109                         }
6110                         break;
6111                 }
6112                 #endif
6113                 break;
6114
6115         case GST_MESSAGE_DURATION_CHANGED:
6116                 __mmplayer_gst_handle_duration(player, message);
6117                 break;
6118         case GST_MESSAGE_ASYNC_DONE:
6119                 /* NOTE:Don't call gst_callback directly
6120                  * because previous frame can be showed even though this message is received for seek.
6121                  */
6122         default:
6123                 reply = GST_BUS_PASS;
6124                 break;
6125         }
6126
6127         if (reply == GST_BUS_DROP)
6128                 gst_message_unref(message);
6129
6130         return reply;
6131 }
6132
6133 static gboolean
6134 __mmplayer_gst_create_decoder(mm_player_t *player,
6135                                                                 MMPlayerTrackType track,
6136                                                                 GstPad* srcpad,
6137                                                                 enum MainElementID elemId,
6138                                                                 const gchar* name)
6139 {
6140         gboolean ret = TRUE;
6141         GstPad *sinkpad = NULL;
6142
6143         MMPLAYER_FENTER();
6144
6145         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6146                                                 player->pipeline &&
6147                                                 player->pipeline->mainbin, FALSE);
6148         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6149         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6150         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6151
6152         GstElement *decodebin = NULL;
6153         GstCaps *dec_caps = NULL;
6154
6155         /* create decodebin */
6156         decodebin = gst_element_factory_make("decodebin", name);
6157
6158         if (!decodebin) {
6159                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6160                 ret = FALSE;
6161                 goto ERROR;
6162         }
6163
6164         /* raw pad handling signal */
6165         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6166                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6167
6168         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6169         before looking for any elements that can handle that stream.*/
6170         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6171                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6172
6173         /* This signal is emitted when a element is added to the bin.*/
6174         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6175                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6176
6177         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6178                 LOGE("failed to add new decodebin\n");
6179                 ret = FALSE;
6180                 goto ERROR;
6181         }
6182
6183         dec_caps = gst_pad_query_caps(srcpad, NULL);
6184         if (dec_caps) {
6185                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6186                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6187                 gst_caps_unref(dec_caps);
6188         }
6189
6190         player->pipeline->mainbin[elemId].id = elemId;
6191         player->pipeline->mainbin[elemId].gst = decodebin;
6192
6193         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6194
6195         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6196                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6197                 gst_object_unref(GST_OBJECT(decodebin));
6198         }
6199
6200         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6201                 LOGE("failed to sync second level decodebin state with parent\n");
6202
6203         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6204
6205 ERROR:
6206         if (sinkpad) {
6207                 gst_object_unref(GST_OBJECT(sinkpad));
6208                 sinkpad = NULL;
6209         }
6210         MMPLAYER_FLEAVE();
6211
6212         return ret;
6213 }
6214
6215 /**
6216  * This function is to create  audio or video pipeline for playing.
6217  *
6218  * @param       player          [in]    handle of player
6219  *
6220  * @return      This function returns zero on success.
6221  * @remark
6222  * @see
6223  */
6224 static int
6225 __mmplayer_gst_create_pipeline(mm_player_t* player)
6226 {
6227         GstBus  *bus = NULL;
6228         MMPlayerGstElement *mainbin = NULL;
6229         MMHandleType attrs = 0;
6230         GstElement* element = NULL;
6231         GstElement* elem_src_audio = NULL;
6232         GstElement* elem_src_subtitle = NULL;
6233         GstElement* es_video_queue = NULL;
6234         GstElement* es_audio_queue = NULL;
6235         GstElement* es_subtitle_queue = NULL;
6236         GList* element_bucket = NULL;
6237         gboolean need_state_holder = TRUE;
6238         gint i = 0;
6239 #ifdef SW_CODEC_ONLY
6240         int surface_type = 0;
6241 #endif
6242         MMPLAYER_FENTER();
6243
6244         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6245
6246         /* get profile attribute */
6247         attrs = MMPLAYER_GET_ATTRS(player);
6248         if (!attrs) {
6249                 LOGE("cannot get content attribute\n");
6250                 goto INIT_ERROR;
6251         }
6252
6253         /* create pipeline handles */
6254         if (player->pipeline) {
6255                 LOGW("pipeline should be released before create new one\n");
6256                 goto INIT_ERROR;
6257         }
6258
6259         player->video360_metadata.is_spherical = -1;
6260         player->is_openal_plugin_used = FALSE;
6261
6262         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6263         if (player->pipeline == NULL)
6264                 goto INIT_ERROR;
6265
6266         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6267
6268         /* create mainbin */
6269         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6270         if (mainbin == NULL)
6271                 goto INIT_ERROR;
6272
6273         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6274
6275         /* create pipeline */
6276         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6277         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6278         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6279                 LOGE("failed to create pipeline\n");
6280                 goto INIT_ERROR;
6281         }
6282         player->demux_pad_index = 0;
6283         player->subtitle_language_list = NULL;
6284
6285         player->is_subtitle_force_drop = FALSE;
6286         player->last_multiwin_status = FALSE;
6287
6288         _mmplayer_track_initialize(player);
6289         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6290
6291         /* create source element */
6292         switch (player->profile.uri_type) {
6293         /* rtsp streamming */
6294         case MM_PLAYER_URI_TYPE_URL_RTSP:
6295                 {
6296                         gchar *user_agent;
6297
6298                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6299
6300                         if (!element) {
6301                                 LOGE("failed to create streaming source element\n");
6302                                 break;
6303                         }
6304
6305                         /* make it zero */
6306                         user_agent = NULL;
6307
6308                         /* get attribute */
6309                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6310
6311                         SECURE_LOGD("user_agent : %s\n", user_agent);
6312
6313                         /* setting property to streaming source */
6314                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6315                         if (user_agent)
6316                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6317
6318                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6319                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6320                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6321                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6322                 }
6323                 break;
6324
6325         /* http streaming*/
6326         case MM_PLAYER_URI_TYPE_URL_HTTP:
6327                 {
6328                         gchar *user_agent, *cookies, **cookie_list;
6329                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6330                         user_agent = cookies = NULL;
6331                         cookie_list = NULL;
6332                         gint mode = MM_PLAYER_PD_MODE_NONE;
6333
6334                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6335
6336                         player->pd_mode = mode;
6337
6338                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6339
6340                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6341                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6342                                 if (!element) {
6343                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6344                                         break;
6345                                 }
6346                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6347
6348                                 /* get attribute */
6349                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6350                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6351
6352                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6353                                         LOGD("get timeout from ini\n");
6354                                         http_timeout = player->ini.http_timeout;
6355                                 }
6356
6357                                 /* get attribute */
6358                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6359                                 SECURE_LOGD("cookies : %s\n", cookies);
6360                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6361                                 LOGD("timeout : %d\n",  http_timeout);
6362
6363                                 /* setting property to streaming source */
6364                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6365                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6366                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6367
6368                                 /* parsing cookies */
6369                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6370                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6371                                         g_strfreev(cookie_list);
6372                                 }
6373                                 if (user_agent)
6374                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6375
6376                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6377                                         LOGW("it's dash. and it's still experimental feature.");
6378                         } else {
6379                                 // progressive download
6380                                 gchar* location = NULL;
6381
6382                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6383                                         gchar *path = NULL;
6384
6385                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6386
6387                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6388
6389                                         LOGD("PD Location : %s\n", path);
6390
6391                                         if (path) {
6392                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6393                                                         LOGE("failed to get storage info");
6394                                                         break;
6395                                                 }
6396                                                 player->pd_file_save_path = g_strdup(path);
6397                                         } else {
6398                                                 LOGE("can't find pd location so, it should be set \n");
6399                                                 break;
6400                                         }
6401                                 }
6402
6403                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6404                                 if (!element) {
6405                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6406                                         break;
6407                                 }
6408
6409                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6410                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6411                                 else
6412                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6413                                 g_object_get(element, "location", &location, NULL);
6414                                 LOGD("PD_LOCATION [%s].\n", location);
6415                                 if (location)
6416                                         g_free(location);
6417                         }
6418                 }
6419                 break;
6420
6421         /* file source */
6422         case MM_PLAYER_URI_TYPE_FILE:
6423                 {
6424                         LOGD("using filesrc for 'file://' handler.\n");
6425                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6426                                 LOGE("failed to get storage info");
6427                                 break;
6428                         }
6429
6430                         element = gst_element_factory_make("filesrc", "source");
6431                         if (!element) {
6432                                 LOGE("failed to create filesrc\n");
6433                                 break;
6434                         }
6435
6436                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6437                 }
6438                 break;
6439
6440         case MM_PLAYER_URI_TYPE_SS:
6441                 {
6442                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6443                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6444                         if (!element) {
6445                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6446                                 break;
6447                         }
6448
6449                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6450                                 LOGD("get timeout from ini\n");
6451                                 http_timeout = player->ini.http_timeout;
6452                         }
6453
6454                         /* setting property to streaming source */
6455                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6456                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6457                 }
6458                 break;
6459         case MM_PLAYER_URI_TYPE_MS_BUFF:
6460                 {
6461                         LOGD("MS buff src is selected\n");
6462
6463                         if (player->v_stream_caps) {
6464                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6465                                 if (!element) {
6466                                         LOGF("failed to create video app source element[appsrc].\n");
6467                                         break;
6468                                 }
6469
6470                                 if (player->a_stream_caps) {
6471                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6472                                         if (!elem_src_audio) {
6473                                                 LOGF("failed to create audio app source element[appsrc].\n");
6474                                                 break;
6475                                         }
6476                                 }
6477                         } else if (player->a_stream_caps) {
6478                                 /* no video, only audio pipeline*/
6479                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6480                                 if (!element) {
6481                                         LOGF("failed to create audio app source element[appsrc].\n");
6482                                         break;
6483                                 }
6484                         }
6485
6486                         if (player->s_stream_caps) {
6487                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6488                                 if (!elem_src_subtitle) {
6489                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6490                                         break;
6491                                 }
6492                         }
6493
6494                         LOGD("setting app sources properties.\n");
6495                         LOGD("location : %s\n", player->profile.uri);
6496
6497                         if (player->v_stream_caps && element) {
6498                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6499                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6500                                                                                                 "caps", player->v_stream_caps, NULL);
6501
6502                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6503                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6504                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6505                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6506
6507                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6508                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6509                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6510                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6511
6512                                 if (player->a_stream_caps && elem_src_audio) {
6513                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6514                                                                                                                         "caps", player->a_stream_caps, NULL);
6515
6516                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6517                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6518                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6519                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6520
6521                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6522                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6523                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6524                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6525                                 }
6526                         } else if (player->a_stream_caps && element) {
6527                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6528                                                                                                 "caps", player->a_stream_caps, NULL);
6529
6530                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6531                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6532                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6533                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6534
6535                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6536                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6537                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6538                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6539                         }
6540
6541                         if (player->s_stream_caps && elem_src_subtitle) {
6542                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6543                                                                                                                  "caps", player->s_stream_caps, NULL);
6544
6545                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6546                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6547                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6548                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6549
6550                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6551
6552                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6553                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6554                         }
6555
6556                         if (player->v_stream_caps && element) {
6557                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6558                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6559                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6560                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6561
6562                                 if (player->a_stream_caps && elem_src_audio) {
6563                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6564                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6565                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6566                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6567                                 }
6568                         } else if (player->a_stream_caps && element) {
6569                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6570                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6571                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6572                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6573                         }
6574
6575                         if (player->s_stream_caps && elem_src_subtitle)
6576                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6577                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6578
6579                         need_state_holder = FALSE;
6580
6581                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6582                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6583                                 LOGE("failed to commit\n");
6584                 }
6585                 break;
6586         /* appsrc */
6587         case MM_PLAYER_URI_TYPE_MEM:
6588                 {
6589                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6590
6591                         LOGD("mem src is selected\n");
6592
6593                         element = gst_element_factory_make("appsrc", "mem-source");
6594                         if (!element) {
6595                                 LOGE("failed to create appsrc element\n");
6596                                 break;
6597                         }
6598
6599                         g_object_set(element, "stream-type", stream_type, NULL);
6600                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6601                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6602
6603                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6604                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6605                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6606                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6607                 }
6608                 break;
6609         case MM_PLAYER_URI_TYPE_URL:
6610                 break;
6611
6612         case MM_PLAYER_URI_TYPE_TEMP:
6613                 break;
6614
6615         case MM_PLAYER_URI_TYPE_NONE:
6616         default:
6617                 break;
6618         }
6619
6620         /* check source element is OK */
6621         if (!element) {
6622                 LOGE("no source element was created.\n");
6623                 goto INIT_ERROR;
6624         }
6625
6626         /* take source element */
6627         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6628         mainbin[MMPLAYER_M_SRC].gst = element;
6629         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6630
6631         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6632                 player->streamer = __mm_player_streaming_create();
6633                 __mm_player_streaming_initialize(player->streamer);
6634         }
6635
6636         if (MMPLAYER_IS_HTTP_PD(player)) {
6637                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6638
6639                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6640                 element = gst_element_factory_make("queue2", "queue2");
6641                 if (!element) {
6642                         LOGE("failed to create http streaming buffer element\n");
6643                         goto INIT_ERROR;
6644                 }
6645
6646                 /* take it */
6647                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6648                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6649                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6650
6651                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6652
6653                 __mm_player_streaming_set_queue2(player->streamer,
6654                                 element,
6655                                 TRUE,
6656                                 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6657                                 pre_buffering_time,
6658                                 1.0,
6659                                 player->ini.http_buffering_limit,
6660                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6661                                 NULL,
6662                                 0);
6663         }
6664         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6665                 if (player->v_stream_caps) {
6666                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6667                         if (!es_video_queue) {
6668                                 LOGE("create es_video_queue for es player failed\n");
6669                                 goto INIT_ERROR;
6670                         }
6671                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6672                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6673                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6674                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6675
6676                         /* Adding audio appsrc to bucket */
6677                         if (player->a_stream_caps && elem_src_audio) {
6678                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6679                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6680                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6681
6682                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6683                                 if (!es_audio_queue) {
6684                                         LOGE("create es_audio_queue for es player failed\n");
6685                                         goto INIT_ERROR;
6686                                 }
6687                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6688
6689                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6690                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6691                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6692                         }
6693                 } else if (player->a_stream_caps) {
6694                         /* Only audio stream, no video */
6695                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6696                         if (!es_audio_queue) {
6697                                 LOGE("create es_audio_queue for es player failed\n");
6698                                 goto INIT_ERROR;
6699                         }
6700                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6701                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6702                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6703                 }
6704
6705                 if (player->s_stream_caps && elem_src_subtitle) {
6706                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6707                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6708                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6709
6710                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6711                         if (!es_subtitle_queue) {
6712                                 LOGE("create es_subtitle_queue for es player failed\n");
6713                                 goto INIT_ERROR;
6714                         }
6715                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6716                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6717                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6718                 }
6719         }
6720
6721         /* create autoplugging element if src element is not a rtsp src */
6722         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6723                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6724                 element = NULL;
6725                 enum MainElementID elemId = MMPLAYER_M_NUM;
6726
6727                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6728                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6729                         elemId = MMPLAYER_M_AUTOPLUG;
6730                         element = __mmplayer_create_decodebin(player);
6731                         if (element) {
6732                                 /* default size of mq in decodebin is 2M
6733                                  * but it can cause blocking issue during seeking depends on content. */
6734                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6735                         }
6736                         need_state_holder = FALSE;
6737                 } else {
6738                         elemId = MMPLAYER_M_TYPEFIND;
6739                         element = gst_element_factory_make("typefind", "typefinder");
6740                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6741                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6742                 }
6743
6744
6745                 /* check autoplug element is OK */
6746                 if (!element) {
6747                         LOGE("can not create element(%d)\n", elemId);
6748                         goto INIT_ERROR;
6749                 }
6750
6751                 mainbin[elemId].id = elemId;
6752                 mainbin[elemId].gst = element;
6753
6754                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6755         }
6756
6757         /* add elements to pipeline */
6758         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6759                 LOGE("Failed to add elements to pipeline\n");
6760                 goto INIT_ERROR;
6761         }
6762
6763
6764         /* linking elements in the bucket by added order. */
6765         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6766                 LOGE("Failed to link some elements\n");
6767                 goto INIT_ERROR;
6768         }
6769
6770
6771         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6772         if (need_state_holder) {
6773                 /* create */
6774                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6775                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6776
6777                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6778                         LOGE("fakesink element could not be created\n");
6779                         goto INIT_ERROR;
6780                 }
6781                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6782
6783                 /* take ownership of fakesink. we are reusing it */
6784                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6785
6786                 /* add */
6787                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6788                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6789                         LOGE("failed to add fakesink to bin\n");
6790                         goto INIT_ERROR;
6791                 }
6792         }
6793
6794         /* now we have completed mainbin. take it */
6795         player->pipeline->mainbin = mainbin;
6796
6797         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6798                 GstPad *srcpad = NULL;
6799
6800                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6801                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6802                         if (srcpad) {
6803                                 __mmplayer_gst_create_decoder(player,
6804                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6805                                                                                                 srcpad,
6806                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6807                                                                                                 "video_decodebin");
6808
6809                                 gst_object_unref(GST_OBJECT(srcpad));
6810                                 srcpad = NULL;
6811                         }
6812                 }
6813
6814                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6815                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6816                         if (srcpad) {
6817                                 __mmplayer_gst_create_decoder(player,
6818                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6819                                                                                                 srcpad,
6820                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6821                                                                                                 "audio_decodebin");
6822
6823                                 gst_object_unref(GST_OBJECT(srcpad));
6824                                 srcpad = NULL;
6825                         } // else error
6826                 } //  else error
6827
6828                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6829                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6830         }
6831
6832         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6833         if (__mmplayer_check_subtitle(player)) {
6834                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6835                         LOGE("fail to create text pipeline");
6836         }
6837
6838         /* connect bus callback */
6839         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6840         if (!bus) {
6841                 LOGE("cannot get bus from pipeline.\n");
6842                 goto INIT_ERROR;
6843         }
6844
6845         /* set sync handler to get tag synchronously */
6846         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6847
6848         /* finished */
6849         gst_object_unref(GST_OBJECT(bus));
6850         g_list_free(element_bucket);
6851
6852         /* create gst bus_msb_cb thread */
6853         g_mutex_init(&player->bus_msg_thread_mutex);
6854         g_cond_init(&player->bus_msg_thread_cond);
6855         player->bus_msg_thread_exit = FALSE;
6856         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6857         player->bus_msg_thread =
6858                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6859         if (!player->bus_msg_thread) {
6860                 LOGE("failed to create gst BUS msg thread");
6861                 g_mutex_clear(&player->bus_msg_thread_mutex);
6862                 g_cond_clear(&player->bus_msg_thread_cond);
6863                 goto INIT_ERROR;
6864         }
6865
6866         MMPLAYER_FLEAVE();
6867
6868         return MM_ERROR_NONE;
6869
6870 INIT_ERROR:
6871         __mmplayer_gst_destroy_pipeline(player);
6872         g_list_free(element_bucket);
6873
6874         if (mainbin) {
6875                 /* release element which are not added to bin */
6876                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6877                         /* NOTE : skip pipeline */
6878                         if (mainbin[i].gst) {
6879                                 GstObject* parent = NULL;
6880                                 parent = gst_element_get_parent(mainbin[i].gst);
6881
6882                                 if (!parent) {
6883                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6884                                         mainbin[i].gst = NULL;
6885                                 } else
6886                                         gst_object_unref(GST_OBJECT(parent));
6887                         }
6888                 }
6889
6890                 /* release pipeline with it's childs */
6891                 if (mainbin[MMPLAYER_M_PIPE].gst)
6892                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6893
6894                 MMPLAYER_FREEIF(mainbin);
6895         }
6896
6897         MMPLAYER_FREEIF(player->pipeline);
6898         return MM_ERROR_PLAYER_INTERNAL;
6899 }
6900
6901 static void
6902 __mmplayer_reset_gapless_state(mm_player_t* player)
6903 {
6904         MMPLAYER_FENTER();
6905         MMPLAYER_RETURN_IF_FAIL(player
6906                 && player->pipeline
6907                 && player->pipeline->audiobin
6908                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6909
6910         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6911
6912         MMPLAYER_FLEAVE();
6913         return;
6914 }
6915
6916 static int
6917 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6918 {
6919         gint timeout = 0;
6920         int ret = MM_ERROR_NONE;
6921
6922         MMPLAYER_FENTER();
6923
6924         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6925
6926         /* cleanup stuffs */
6927         MMPLAYER_FREEIF(player->type);
6928         player->have_dynamic_pad = FALSE;
6929         player->no_more_pad = FALSE;
6930         player->num_dynamic_pad = 0;
6931         player->demux_pad_index = 0;
6932         player->use_deinterleave = FALSE;
6933         player->max_audio_channels = 0;
6934         player->video_share_api_delta = 0;
6935         player->video_share_clock_delta = 0;
6936         player->video_hub_download_mode = 0;
6937
6938         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6939         player->subtitle_language_list = NULL;
6940         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6941
6942         __mmplayer_reset_gapless_state(player);
6943
6944         if (player->streamer) {
6945                 __mm_player_streaming_deinitialize(player->streamer);
6946                 __mm_player_streaming_destroy(player->streamer);
6947                 player->streamer = NULL;
6948         }
6949
6950         /* cleanup unlinked mime type */
6951         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6952         MMPLAYER_FREEIF(player->unlinked_video_mime);
6953         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6954
6955         /* cleanup running stuffs */
6956         __mmplayer_cancel_eos_timer(player);
6957
6958         /* cleanup gst stuffs */
6959         if (player->pipeline) {
6960                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6961                 GstTagList* tag_list = player->pipeline->tag_list;
6962
6963                 /* first we need to disconnect all signal hander */
6964                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6965
6966                 if (mainbin) {
6967                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6968                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6969                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6970                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6971                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6972                         gst_object_unref(bus);
6973
6974                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6975                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6976                         if (ret != MM_ERROR_NONE) {
6977                                 LOGE("fail to change state to NULL\n");
6978                                 return MM_ERROR_PLAYER_INTERNAL;
6979                         }
6980
6981                         LOGW("succeeded in chaning state to NULL\n");
6982
6983                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6984
6985                         /* free fakesink */
6986                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6987                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6988
6989                         /* free avsysaudiosink
6990                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6991                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6992                         */
6993                         MMPLAYER_FREEIF(audiobin);
6994                         MMPLAYER_FREEIF(videobin);
6995                         MMPLAYER_FREEIF(textbin);
6996                         MMPLAYER_FREEIF(mainbin);
6997                 }
6998
6999                 if (tag_list)
7000                         gst_tag_list_free(tag_list);
7001
7002                 MMPLAYER_FREEIF(player->pipeline);
7003         }
7004         MMPLAYER_FREEIF(player->album_art);
7005
7006         if (player->v_stream_caps) {
7007                 gst_caps_unref(player->v_stream_caps);
7008                 player->v_stream_caps = NULL;
7009         }
7010         if (player->a_stream_caps) {
7011                 gst_caps_unref(player->a_stream_caps);
7012                 player->a_stream_caps = NULL;
7013         }
7014
7015         if (player->s_stream_caps) {
7016                 gst_caps_unref(player->s_stream_caps);
7017                 player->s_stream_caps = NULL;
7018         }
7019         _mmplayer_track_destroy(player);
7020
7021         if (player->sink_elements)
7022                 g_list_free(player->sink_elements);
7023         player->sink_elements = NULL;
7024
7025         if (player->bufmgr) {
7026                 tbm_bufmgr_deinit(player->bufmgr);
7027                 player->bufmgr = NULL;
7028         }
7029
7030         LOGW("finished destroy pipeline\n");
7031
7032         MMPLAYER_FLEAVE();
7033
7034         return ret;
7035 }
7036
7037 static int __gst_realize(mm_player_t* player)
7038 {
7039         gint timeout = 0;
7040         int ret = MM_ERROR_NONE;
7041
7042         MMPLAYER_FENTER();
7043
7044         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7045
7046         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7047
7048         ret = __mmplayer_gst_create_pipeline(player);
7049         if (ret) {
7050                 LOGE("failed to create pipeline\n");
7051                 return ret;
7052         }
7053
7054         /* set pipeline state to READY */
7055         /* NOTE : state change to READY must be performed sync. */
7056         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7057         ret = __mmplayer_gst_set_state(player,
7058                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7059
7060         if (ret != MM_ERROR_NONE) {
7061                 /* return error if failed to set state */
7062                 LOGE("failed to set READY state");
7063                 return ret;
7064         }
7065
7066         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7067
7068         /* create dot before error-return. for debugging */
7069         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7070
7071         MMPLAYER_FLEAVE();
7072
7073         return ret;
7074 }
7075
7076 static int __gst_unrealize(mm_player_t* player)
7077 {
7078         int ret = MM_ERROR_NONE;
7079
7080         MMPLAYER_FENTER();
7081
7082         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7083
7084         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7085         MMPLAYER_PRINT_STATE(player);
7086
7087         /* release miscellaneous information */
7088         __mmplayer_release_misc(player);
7089
7090         /* destroy pipeline */
7091         ret = __mmplayer_gst_destroy_pipeline(player);
7092         if (ret != MM_ERROR_NONE) {
7093                 LOGE("failed to destory pipeline\n");
7094                 return ret;
7095         }
7096
7097         /* release miscellaneous information.
7098            these info needs to be released after pipeline is destroyed. */
7099         __mmplayer_release_misc_post(player);
7100
7101         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7102
7103         MMPLAYER_FLEAVE();
7104
7105         return ret;
7106 }
7107
7108 static int __gst_pending_seek(mm_player_t* player)
7109 {
7110         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7111         int ret = MM_ERROR_NONE;
7112
7113         MMPLAYER_FENTER();
7114
7115         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7116
7117         if (!player->pending_seek.is_pending) {
7118                 LOGD("pending seek is not reserved. nothing to do.\n");
7119                 return ret;
7120         }
7121
7122         /* check player state if player could pending seek or not. */
7123         current_state = MMPLAYER_CURRENT_STATE(player);
7124
7125         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7126                 LOGW("try to pending seek in %s state, try next time. \n",
7127                         MMPLAYER_STATE_GET_NAME(current_state));
7128                 return ret;
7129         }
7130
7131         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7132
7133         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7134
7135         if (MM_ERROR_NONE != ret)
7136                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7137
7138         player->pending_seek.is_pending = FALSE;
7139
7140         MMPLAYER_FLEAVE();
7141
7142         return ret;
7143 }
7144
7145 static int __gst_start(mm_player_t* player)
7146 {
7147         gboolean sound_extraction = 0;
7148         int ret = MM_ERROR_NONE;
7149         gboolean async = FALSE;
7150
7151         MMPLAYER_FENTER();
7152
7153         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7154
7155         /* get sound_extraction property */
7156         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7157
7158         /* NOTE : if SetPosition was called before Start. do it now */
7159         /* streaming doesn't support it. so it should be always sync */
7160         /* !!create one more api to check if there is pending seek rather than checking variables */
7161         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7162                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7163                 ret = __gst_pause(player, FALSE);
7164                 if (ret != MM_ERROR_NONE) {
7165                         LOGE("failed to set state to PAUSED for pending seek\n");
7166                         return ret;
7167                 }
7168
7169                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7170
7171                 if (sound_extraction) {
7172                         LOGD("setting pcm extraction\n");
7173
7174                         ret = __mmplayer_set_pcm_extraction(player);
7175                         if (MM_ERROR_NONE != ret) {
7176                                 LOGW("failed to set pcm extraction\n");
7177                                 return ret;
7178                         }
7179                 } else {
7180                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7181                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7182                 }
7183         }
7184
7185         LOGD("current state before doing transition");
7186         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7187         MMPLAYER_PRINT_STATE(player);
7188
7189         /* set pipeline state to PLAYING  */
7190         if (player->es_player_push_mode)
7191                 async = TRUE;
7192         /* set pipeline state to PLAYING  */
7193         ret = __mmplayer_gst_set_state(player,
7194                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7195
7196         if (ret == MM_ERROR_NONE) {
7197                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7198         } else {
7199                 LOGE("failed to set state to PLAYING");
7200                 return ret;
7201         }
7202
7203         /* generating debug info before returning error */
7204         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7205
7206         MMPLAYER_FLEAVE();
7207
7208         return ret;
7209 }
7210
7211 static int __gst_stop(mm_player_t* player)
7212 {
7213         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7214         MMHandleType attrs = 0;
7215         gboolean rewind = FALSE;
7216         gint timeout = 0;
7217         int ret = MM_ERROR_NONE;
7218         gboolean async = FALSE;
7219
7220         MMPLAYER_FENTER();
7221
7222         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7223         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7224
7225         LOGD("current state before doing transition");
7226         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7227         MMPLAYER_PRINT_STATE(player);
7228
7229         attrs = MMPLAYER_GET_ATTRS(player);
7230         if (!attrs) {
7231                 LOGE("cannot get content attribute\n");
7232                 return MM_ERROR_PLAYER_INTERNAL;
7233         }
7234
7235         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7236         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7237
7238         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7239                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7240                 rewind = TRUE;
7241
7242         if (player->es_player_push_mode)
7243                 async = TRUE;
7244         /* set gst state */
7245         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7246
7247         /* return if set_state has failed */
7248         if (ret != MM_ERROR_NONE) {
7249                 LOGE("failed to set state.\n");
7250                 return ret;
7251         }
7252
7253         /* rewind */
7254         if (rewind) {
7255                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7256                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7257                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7258                         LOGW("failed to rewind\n");
7259                         ret = MM_ERROR_PLAYER_SEEK;
7260                 }
7261         }
7262
7263         /* initialize */
7264         player->sent_bos = FALSE;
7265
7266         if (player->es_player_push_mode) //for cloudgame
7267                 timeout = 0;
7268
7269         /* wait for seek to complete */
7270         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7271         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7272                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7273         } else {
7274                 LOGE("fail to stop player.\n");
7275                 ret = MM_ERROR_PLAYER_INTERNAL;
7276                 __mmplayer_dump_pipeline_state(player);
7277         }
7278
7279         /* generate dot file if enabled */
7280         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7281
7282         MMPLAYER_FLEAVE();
7283
7284         return ret;
7285 }
7286
7287 int __gst_pause(mm_player_t* player, gboolean async)
7288 {
7289         int ret = MM_ERROR_NONE;
7290
7291         MMPLAYER_FENTER();
7292
7293         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7294         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7295
7296         LOGD("current state before doing transition");
7297         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7298         MMPLAYER_PRINT_STATE(player);
7299
7300         /* set pipeline status to PAUSED */
7301         ret = __mmplayer_gst_set_state(player,
7302                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7303
7304         if (FALSE == async) {
7305                 if (ret != MM_ERROR_NONE) {
7306                         GstMessage *msg = NULL;
7307                         GTimer *timer = NULL;
7308                         gdouble MAX_TIMEOUT_SEC = 3;
7309
7310                         LOGE("failed to set state to PAUSED");
7311
7312                         if (player->msg_posted) {
7313                                 LOGE("error msg is already posted.");
7314                                 return ret;
7315                         }
7316
7317                         timer = g_timer_new();
7318                         g_timer_start(timer);
7319
7320                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7321
7322                         do {
7323                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7324                                 if (msg) {
7325                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7326                                                 GError *error = NULL;
7327
7328                                                 /* parse error code */
7329                                                 gst_message_parse_error(msg, &error, NULL);
7330
7331                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7332                                                         /* Note : the streaming error from the streaming source is handled
7333                                                          *   using __mmplayer_handle_streaming_error.
7334                                                          */
7335                                                         __mmplayer_handle_streaming_error(player, msg);
7336
7337                                                 } else if (error) {
7338                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7339
7340                                                         if (error->domain == GST_STREAM_ERROR)
7341                                                                 ret = __gst_handle_stream_error(player, error, msg);
7342                                                         else if (error->domain == GST_RESOURCE_ERROR)
7343                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7344                                                         else if (error->domain == GST_LIBRARY_ERROR)
7345                                                                 ret = __gst_handle_library_error(player, error->code);
7346                                                         else if (error->domain == GST_CORE_ERROR)
7347                                                                 ret = __gst_handle_core_error(player, error->code);
7348
7349                                                         g_error_free(error);
7350                                                 }
7351                                                 player->msg_posted = TRUE;
7352                                         }
7353                                         gst_message_unref(msg);
7354                                 }
7355                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7356                         /* clean */
7357                         gst_object_unref(bus);
7358                         g_timer_stop(timer);
7359                         g_timer_destroy(timer);
7360
7361                         return ret;
7362
7363                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7364                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7365
7366                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7367
7368                 } else if (ret == MM_ERROR_NONE) {
7369
7370                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7371                 }
7372         }
7373
7374         /* generate dot file before returning error */
7375         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7376
7377         MMPLAYER_FLEAVE();
7378
7379         return ret;
7380 }
7381
7382 int __gst_resume(mm_player_t* player, gboolean async)
7383 {
7384         int ret = MM_ERROR_NONE;
7385         gint timeout = 0;
7386
7387         MMPLAYER_FENTER();
7388
7389         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7390                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7391
7392         LOGD("current state before doing transition");
7393         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7394         MMPLAYER_PRINT_STATE(player);
7395
7396         /* generate dot file before returning error */
7397         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7398
7399         if (async)
7400                 LOGD("do async state transition to PLAYING.\n");
7401
7402         /* set pipeline state to PLAYING */
7403         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7404
7405         ret = __mmplayer_gst_set_state(player,
7406                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7407         if (ret != MM_ERROR_NONE) {
7408                 LOGE("failed to set state to PLAYING\n");
7409                 return ret;
7410         } else {
7411                 if (async == FALSE) {
7412                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7413                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7414                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7415                 }
7416         }
7417
7418         /* generate dot file before returning error */
7419         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7420
7421         MMPLAYER_FLEAVE();
7422
7423         return ret;
7424 }
7425
7426 static int
7427 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7428 {
7429         unsigned long dur_msec = 0;
7430         gint64 dur_nsec = 0;
7431         gint64 pos_nsec = 0;
7432         gboolean ret = TRUE;
7433         gboolean accurated = FALSE;
7434         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7435
7436         MMPLAYER_FENTER();
7437         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7438         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7439
7440         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7441                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7442                 goto PENDING;
7443
7444         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7445                 /* check duration */
7446                 /* NOTE : duration cannot be zero except live streaming.
7447                  *              Since some element could have some timing problemn with quering duration, try again.
7448                  */
7449                 if (!player->duration) {
7450                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7451                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7452                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7453                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7454                                         player->pending_seek.is_pending = TRUE;
7455                                         player->pending_seek.format = format;
7456                                         player->pending_seek.pos = position;
7457                                         player->doing_seek = FALSE;
7458                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7459                                         return MM_ERROR_NONE;
7460                                 } else {
7461                                         goto SEEK_ERROR;
7462                                 }
7463                         }
7464                         player->duration = dur_nsec;
7465                 }
7466
7467                 if (player->duration) {
7468                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7469                 } else {
7470                         LOGE("could not get the duration. fail to seek.\n");
7471                         goto SEEK_ERROR;
7472                 }
7473         }
7474         LOGD("playback rate: %f\n", player->playback_rate);
7475
7476         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7477         if (accurated)
7478                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7479         else
7480                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7481
7482         /* do seek */
7483         switch (format) {
7484         case MM_PLAYER_POS_FORMAT_TIME:
7485         {
7486                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7487                         GstQuery *query = NULL;
7488                         gboolean seekable = FALSE;
7489
7490                         /* check position is valid or not */
7491                         if (position > dur_msec)
7492                                 goto INVALID_ARGS;
7493
7494                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7495                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7496                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7497                                 gst_query_unref(query);
7498
7499                                 if (!seekable) {
7500                                         LOGW("non-seekable content");
7501                                         player->doing_seek = FALSE;
7502                                         return MM_ERROR_PLAYER_NO_OP;
7503                                 }
7504                         } else {
7505                                 LOGW("failed to get seeking query");
7506                                 gst_query_unref(query); /* keep seeking operation */
7507                         }
7508
7509                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7510
7511                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7512                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7513                            This causes problem is position calculation during normal pause resume scenarios also.
7514                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7515                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7516                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7517                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7518                                         LOGW("getting current position failed in seek\n");
7519
7520                                 player->last_position = pos_nsec;
7521                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7522                         }
7523
7524                         if (player->doing_seek) {
7525                                 LOGD("not completed seek");
7526                                 return MM_ERROR_PLAYER_DOING_SEEK;
7527                         }
7528                 }
7529
7530                 if (!internal_called)
7531                         player->doing_seek = TRUE;
7532
7533                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7534
7535                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7536                         gint64 cur_time = 0;
7537
7538                         /* get current position */
7539                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7540
7541                         /* flush */
7542                         GstEvent *event = gst_event_new_seek(1.0,
7543                                                         GST_FORMAT_TIME,
7544                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7545                                                         GST_SEEK_TYPE_SET, cur_time,
7546                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7547                         if (event)
7548                                 __gst_send_event_to_sink(player, event);
7549
7550                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7551                                 __gst_pause(player, FALSE);
7552                 }
7553
7554                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7555                         that's why set position through property. */
7556                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7557                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7558                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7559                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7560
7561                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7562                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7563                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7564                         player->doing_seek = FALSE;
7565                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7566                 } else {
7567                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7568                                                         GST_FORMAT_TIME, seek_flags,
7569                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7570                 }
7571
7572                 if (!ret) {
7573                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7574                         goto SEEK_ERROR;
7575                 }
7576         }
7577         break;
7578
7579         case MM_PLAYER_POS_FORMAT_PERCENT:
7580         {
7581                 LOGD("seeking to(%lu)%% \n", position);
7582
7583                 if (player->doing_seek) {
7584                         LOGD("not completed seek");
7585                         return MM_ERROR_PLAYER_DOING_SEEK;
7586                 }
7587
7588                 if (!internal_called)
7589                         player->doing_seek = TRUE;
7590
7591                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7592                 pos_nsec = (gint64)((position * player->duration) / 100);
7593                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7594                                                 GST_FORMAT_TIME, seek_flags,
7595                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7596                 if (!ret) {
7597                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7598                         goto SEEK_ERROR;
7599                 }
7600         }
7601         break;
7602
7603         default:
7604                 goto INVALID_ARGS;
7605         }
7606
7607         /* NOTE : store last seeking point to overcome some bad operation
7608           *     (returning zero when getting current position) of some elements
7609           */
7610         player->last_position = pos_nsec;
7611
7612         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7613         if (player->playback_rate > 1.0)
7614                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7615
7616         MMPLAYER_FLEAVE();
7617         return MM_ERROR_NONE;
7618
7619 PENDING:
7620         player->pending_seek.is_pending = TRUE;
7621         player->pending_seek.format = format;
7622         player->pending_seek.pos = position;
7623
7624         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7625                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7626
7627         return MM_ERROR_NONE;
7628
7629 INVALID_ARGS:
7630         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7631         return MM_ERROR_INVALID_ARGUMENT;
7632
7633 SEEK_ERROR:
7634         player->doing_seek = FALSE;
7635         return MM_ERROR_PLAYER_SEEK;
7636 }
7637
7638 #define TRICKPLAY_OFFSET GST_MSECOND
7639
7640 static int
7641 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7642 {
7643         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7644         gint64 pos_msec = 0;
7645         gboolean ret = TRUE;
7646
7647         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7648                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7649
7650         current_state = MMPLAYER_CURRENT_STATE(player);
7651
7652         /* NOTE : query position except paused state to overcome some bad operation
7653          * please refer to below comments in details
7654          */
7655         if (current_state != MM_PLAYER_STATE_PAUSED)
7656                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7657
7658         /* NOTE : get last point to overcome some bad operation of some elements
7659          *(returning zero when getting current position in paused state
7660          * and when failed to get postion during seeking
7661          */
7662         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7663                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7664
7665                 if (player->playback_rate < 0.0)
7666                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7667                 else
7668                         pos_msec = player->last_position;
7669
7670                 if (!ret)
7671                         pos_msec = player->last_position;
7672                 else
7673                         player->last_position = pos_msec;
7674
7675                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7676
7677         } else {
7678                 if (player->duration > 0 && pos_msec > player->duration)
7679                         pos_msec = player->duration;
7680
7681                 player->last_position = pos_msec;
7682         }
7683
7684         switch (format) {
7685         case MM_PLAYER_POS_FORMAT_TIME:
7686                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7687                 break;
7688
7689         case MM_PLAYER_POS_FORMAT_PERCENT:
7690         {
7691                 if (player->duration <= 0) {
7692                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7693                         *position = 0;
7694                 } else {
7695                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7696                         *position = pos_msec * 100 / player->duration;
7697                 }
7698                 break;
7699         }
7700         default:
7701                 return MM_ERROR_PLAYER_INTERNAL;
7702         }
7703
7704         return MM_ERROR_NONE;
7705 }
7706
7707
7708 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7709 {
7710 #define STREAMING_IS_FINISHED   0
7711 #define BUFFERING_MAX_PER       100
7712 #define DEFAULT_PER_VALUE       -1
7713 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7714
7715         MMPlayerGstElement *mainbin = NULL;
7716         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7717         gint64 buffered_total = 0;
7718         unsigned long position = 0;
7719         gint buffered_sec = -1;
7720         GstBufferingMode mode = GST_BUFFERING_STREAM;
7721         gint64 content_size_time = player->duration;
7722         guint64 content_size_bytes = player->http_content_size;
7723
7724         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7725                                                 player->pipeline &&
7726                                                 player->pipeline->mainbin,
7727                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7728
7729         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7730
7731         *start_pos = 0;
7732         *stop_pos = 0;
7733
7734         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7735                 /* and rtsp is not ready yet. */
7736                 LOGW("it's only used for http streaming case.\n");
7737                 return MM_ERROR_PLAYER_NO_OP;
7738         }
7739
7740         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7741                 LOGW("Time format is not supported yet.\n");
7742                 return MM_ERROR_INVALID_ARGUMENT;
7743         }
7744
7745         if (content_size_time <= 0 || content_size_bytes <= 0) {
7746                 LOGW("there is no content size.");
7747                 return MM_ERROR_NONE;
7748         }
7749
7750         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7751                 LOGW("fail to get current position.");
7752                 return MM_ERROR_NONE;
7753         }
7754
7755         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7756                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7757
7758         mainbin = player->pipeline->mainbin;
7759         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7760
7761         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7762                 GstQuery *query = NULL;
7763                 gint byte_in_rate = 0, byte_out_rate = 0;
7764                 gint64 estimated_total = 0;
7765
7766                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7767                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7768                         LOGW("fail to get buffering query from queue2");
7769                         if (query)
7770                                 gst_query_unref(query);
7771                         return MM_ERROR_NONE;
7772                 }
7773
7774                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7775                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7776
7777                 if (mode == GST_BUFFERING_STREAM) {
7778                         /* using only queue in case of push mode(ts / mp3) */
7779                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7780                                 GST_FORMAT_BYTES, &buffered_total)) {
7781                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7782                                 stop_per = 100 * buffered_total / content_size_bytes;
7783                         }
7784                 } else {
7785                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7786                         guint idx = 0;
7787                         guint num_of_ranges = 0;
7788                         gint64 start_byte = 0, stop_byte = 0;
7789
7790                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7791                         if (estimated_total != STREAMING_IS_FINISHED) {
7792                                 /* buffered size info from queue2 */
7793                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7794                                 for (idx = 0; idx < num_of_ranges; idx++) {
7795                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7796                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7797
7798                                         buffered_total += (stop_byte - start_byte);
7799                                 }
7800                         } else
7801                                 stop_per = BUFFERING_MAX_PER;
7802                 }
7803                 gst_query_unref(query);
7804         }
7805
7806         if (stop_per == DEFAULT_PER_VALUE) {
7807                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7808                 if (dur_sec > 0) {
7809                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7810
7811                         /* buffered size info from multiqueue */
7812                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7813                                 guint curr_size_bytes = 0;
7814                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7815                                         "curr-size-bytes", &curr_size_bytes, NULL);
7816                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7817                                 buffered_total += curr_size_bytes;
7818                         }
7819
7820                         if (avg_byterate > 0)
7821                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7822                         else if (player->total_maximum_bitrate > 0)
7823                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7824                         else if (player->total_bitrate > 0)
7825                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7826
7827                         if (buffered_sec >= 0)
7828                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7829                 }
7830         }
7831
7832         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7833         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7834
7835         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7836                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7837
7838         return MM_ERROR_NONE;
7839 }
7840
7841 static int
7842 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7843 {
7844         MMPLAYER_FENTER();
7845
7846         if (!player) {
7847                 LOGW("set_message_callback is called with invalid player handle\n");
7848                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7849         }
7850
7851         player->msg_cb = callback;
7852         player->msg_cb_param = user_param;
7853
7854         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7855
7856         MMPLAYER_FLEAVE();
7857
7858         return MM_ERROR_NONE;
7859 }
7860
7861 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7862 {
7863         int ret = MM_ERROR_PLAYER_INVALID_URI;
7864         char *path = NULL;
7865
7866         MMPLAYER_FENTER();
7867
7868         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7869         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7870         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7871
7872         memset(data, 0, sizeof(MMPlayerParseProfile));
7873
7874         if ((path = strstr(uri, "es_buff://"))) {
7875                 if (strlen(path)) {
7876                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7877                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7878                         ret = MM_ERROR_NONE;
7879                 }
7880         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7881                 if (strlen(path)) {
7882                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7883                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7884                         ret = MM_ERROR_NONE;
7885                 }
7886         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7887                 if (strlen(path)) {
7888                         gchar *tmp = NULL;
7889                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7890                         tmp = g_ascii_strdown(uri, strlen(uri));
7891
7892                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7893                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7894                         else
7895                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7896
7897                         ret = MM_ERROR_NONE;
7898                         g_free(tmp);
7899                 }
7900         } else if ((path = strstr(uri, "rtspu://"))) {
7901                 if (strlen(path)) {
7902                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7903                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7904                         ret = MM_ERROR_NONE;
7905                 }
7906         } else if ((path = strstr(uri, "rtspr://"))) {
7907                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7908                 char *separater = strstr(path, "*");
7909
7910                 if (separater) {
7911                         int urgent_len = 0;
7912                         char *urgent = separater + strlen("*");
7913
7914                         if ((urgent_len = strlen(urgent))) {
7915                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7916                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7917                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7918                                 ret = MM_ERROR_NONE;
7919                         }
7920                 }
7921         } else if ((path = strstr(uri, "mms://"))) {
7922                 if (strlen(path)) {
7923                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7924                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7925                         ret = MM_ERROR_NONE;
7926                 }
7927         } else if ((path = strstr(uri, "mem://"))) {
7928                 if (strlen(path)) {
7929                         int mem_size = 0;
7930                         char *buffer = NULL;
7931                         char *seperator = strchr(path, ',');
7932                         char ext[100] = {0,}, size[100] = {0,};
7933
7934                         if (seperator) {
7935                                 if ((buffer = strstr(path, "ext="))) {
7936                                         buffer += strlen("ext=");
7937
7938                                         if (strlen(buffer)) {
7939                                                 strncpy(ext, buffer, 99);
7940
7941                                                 if ((seperator = strchr(ext, ','))
7942                                                         || (seperator = strchr(ext, ' '))
7943                                                         || (seperator = strchr(ext, '\0'))) {
7944                                                         seperator[0] = '\0';
7945                                                 }
7946                                         }
7947                                 }
7948
7949                                 if ((buffer = strstr(path, "size="))) {
7950                                         buffer += strlen("size=");
7951
7952                                         if (strlen(buffer) > 0) {
7953                                                 strncpy(size, buffer, 99);
7954
7955                                                 if ((seperator = strchr(size, ','))
7956                                                         || (seperator = strchr(size, ' '))
7957                                                         || (seperator = strchr(size, '\0'))) {
7958                                                         seperator[0] = '\0';
7959                                                 }
7960
7961                                                 mem_size = atoi(size);
7962                                         }
7963                                 }
7964                         }
7965
7966                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7967                         if (mem_size && param) {
7968                                 if (data->input_mem.buf)
7969                                         free(data->input_mem.buf);
7970                                 data->input_mem.buf = malloc(mem_size);
7971
7972                                 if (data->input_mem.buf) {
7973                                         memcpy(data->input_mem.buf, param, mem_size);
7974                                         data->input_mem.len = mem_size;
7975                                         ret = MM_ERROR_NONE;
7976                                 } else {
7977                                         LOGE("failed to alloc mem %d", mem_size);
7978                                         ret = MM_ERROR_PLAYER_INTERNAL;
7979                                 }
7980
7981                                 data->input_mem.offset = 0;
7982                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7983                         }
7984                 }
7985         } else {
7986                 gchar *location = NULL;
7987                 GError *err = NULL;
7988
7989                 if ((path = strstr(uri, "file://"))) {
7990
7991                         location = g_filename_from_uri(uri, NULL, &err);
7992
7993                         if (!location || (err != NULL)) {
7994                           LOGE("Invalid URI '%s' for filesrc: %s", path,
7995                                  (err != NULL) ? err->message : "unknown error");
7996
7997                           if (err) g_error_free(err);
7998                           if (location) g_free(location);
7999
8000                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8001                           goto exit;
8002                         }
8003
8004                         LOGD("path from uri: %s", location);
8005                 }
8006
8007                 path = (location != NULL) ? (location) : ((char*)uri);
8008                 int file_stat = MM_ERROR_NONE;
8009
8010                 file_stat = util_exist_file_path(path);
8011
8012                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8013                 if (file_stat == MM_ERROR_NONE) {
8014                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8015
8016                         if (util_is_sdp_file(path)) {
8017                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8018                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8019                         } else {
8020                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8021                         }
8022                         ret = MM_ERROR_NONE;
8023                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8024                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8025                 } else {
8026                         LOGE("invalid uri, could not play..\n");
8027                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8028                 }
8029
8030                 if (location) g_free(location);
8031         }
8032
8033 exit:
8034         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8035                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8036         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8037                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8038
8039         /* dump parse result */
8040         SECURE_LOGW("incomming uri : %s\n", uri);
8041         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8042                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8043
8044         MMPLAYER_FLEAVE();
8045
8046         return ret;
8047 }
8048
8049 gboolean
8050 __mmplayer_can_do_interrupt(mm_player_t *player)
8051 {
8052         if (!player || !player->pipeline || !player->attrs) {
8053                 LOGW("not initialized");
8054                 goto FAILED;
8055         }
8056
8057         if (player->set_mode.pcm_extraction) {
8058                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8059                 goto FAILED;
8060         }
8061
8062         /* check if seeking */
8063         if (player->doing_seek) {
8064                 MMMessageParamType msg_param;
8065                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8066                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8067                 player->doing_seek = FALSE;
8068                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8069                 goto FAILED;
8070         }
8071
8072         /* check other thread */
8073         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8074                 LOGW("locked already, cmd state : %d", player->cmd);
8075
8076                 /* check application command */
8077                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8078                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8079
8080                         /* lock will be released at mrp_resource_release_cb() */
8081                         MMPLAYER_CMD_LOCK(player);
8082                         goto INTERRUPT;
8083                 }
8084                 LOGW("nothing to do");
8085                 goto FAILED;
8086         } else {
8087                 LOGW("can interrupt immediately");
8088                 goto INTERRUPT;
8089         }
8090
8091 FAILED:    /* with CMD UNLOCKED */
8092         return FALSE;
8093
8094 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8095         return TRUE;
8096 }
8097
8098 static int
8099 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8100                 void *user_data)
8101 {
8102         mm_player_t *player = NULL;
8103
8104         MMPLAYER_FENTER();
8105
8106         if (user_data == NULL) {
8107                 LOGE("- user_data is null\n");
8108                 return FALSE;
8109         }
8110         player = (mm_player_t *)user_data;
8111
8112         /* do something to release resource here.
8113          * player stop and interrupt forwarding */
8114         if (!__mmplayer_can_do_interrupt(player)) {
8115                 LOGW("no need to interrupt, so leave");
8116         } else {
8117                 MMMessageParamType msg = {0, };
8118                 unsigned long pos = 0;
8119
8120                 player->interrupted_by_resource = TRUE;
8121
8122                 /* get last play position */
8123                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8124                         LOGW("failed to get play position.");
8125                 } else {
8126                         msg.union_type = MM_MSG_UNION_TIME;
8127                         msg.time.elapsed = (unsigned int)pos;
8128                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8129                 }
8130                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8131                 if (_mmplayer_unrealize((MMHandleType)player))
8132                         LOGW("failed to unrealize");
8133
8134                 /* lock is called in __mmplayer_can_do_interrupt() */
8135                 MMPLAYER_CMD_UNLOCK(player);
8136         }
8137
8138         if (res == player->video_overlay_resource)
8139                 player->video_overlay_resource = FALSE;
8140         else
8141                 player->video_decoder_resource = FALSE;
8142
8143         MMPLAYER_FLEAVE();
8144
8145         return FALSE;
8146 }
8147
8148 int
8149 _mmplayer_create_player(MMHandleType handle)
8150 {
8151         int ret = MM_ERROR_PLAYER_INTERNAL;
8152         bool enabled = false;
8153
8154         mm_player_t* player = MM_PLAYER_CAST(handle);
8155
8156         MMPLAYER_FENTER();
8157
8158         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8159
8160         /* initialize player state */
8161         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8162         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8163         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8164         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8165
8166         /* check current state */
8167         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8168
8169         /* construct attributes */
8170         player->attrs = _mmplayer_construct_attribute(handle);
8171
8172         if (!player->attrs) {
8173                 LOGE("Failed to construct attributes\n");
8174                 return ret;
8175         }
8176
8177         /* initialize gstreamer with configured parameter */
8178         if (!__mmplayer_init_gstreamer(player)) {
8179                 LOGE("Initializing gstreamer failed\n");
8180                 _mmplayer_deconstruct_attribute(handle);
8181                 return ret;
8182         }
8183
8184         /* create lock. note that g_tread_init() has already called in gst_init() */
8185         g_mutex_init(&player->fsink_lock);
8186
8187         /* create update tag lock */
8188         g_mutex_init(&player->update_tag_lock);
8189
8190         /* create next play mutex */
8191         g_mutex_init(&player->next_play_thread_mutex);
8192
8193         /* create next play cond */
8194         g_cond_init(&player->next_play_thread_cond);
8195
8196         /* create next play thread */
8197         player->next_play_thread =
8198                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8199         if (!player->next_play_thread) {
8200                 LOGE("failed to create next play thread");
8201                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8202                 g_mutex_clear(&player->next_play_thread_mutex);
8203                 g_cond_clear(&player->next_play_thread_cond);
8204                 goto ERROR;
8205         }
8206
8207         ret = _mmplayer_initialize_video_capture(player);
8208         if (ret != MM_ERROR_NONE) {
8209                 LOGE("failed to initialize video capture\n");
8210                 goto ERROR;
8211         }
8212
8213         /* initialize resource manager */
8214         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8215                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8216                         &player->resource_manager)) {
8217                 LOGE("failed to initialize resource manager\n");
8218                 goto ERROR;
8219         }
8220
8221         if (MMPLAYER_IS_HTTP_PD(player)) {
8222                 player->pd_downloader = NULL;
8223                 player->pd_file_save_path = NULL;
8224         }
8225
8226         /* create video bo lock and cond */
8227         g_mutex_init(&player->video_bo_mutex);
8228         g_cond_init(&player->video_bo_cond);
8229
8230         /* create media stream callback mutex */
8231         g_mutex_init(&player->media_stream_cb_lock);
8232
8233         /* create subtitle info lock and cond */
8234         g_mutex_init(&player->subtitle_info_mutex);
8235         g_cond_init(&player->subtitle_info_cond);
8236
8237         player->streaming_type = STREAMING_SERVICE_NONE;
8238
8239         /* give default value of audio effect setting */
8240         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8241         player->sound.rg_enable = false;
8242         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8243
8244         player->play_subtitle = FALSE;
8245         player->use_deinterleave = FALSE;
8246         player->max_audio_channels = 0;
8247         player->video_share_api_delta = 0;
8248         player->video_share_clock_delta = 0;
8249         player->has_closed_caption = FALSE;
8250         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8251         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8252         player->pending_resume = FALSE;
8253         if (player->ini.dump_element_keyword[0][0] == '\0')
8254                 player->ini.set_dump_element_flag = FALSE;
8255         else
8256                 player->ini.set_dump_element_flag = TRUE;
8257
8258         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8259         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8260         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8261
8262         /* Set video360 settings to their defaults for just-created player.
8263          * */
8264
8265         player->is_360_feature_enabled = FALSE;
8266         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8267                 LOGI("spherical feature info: %d", enabled);
8268                 if (enabled)
8269                         player->is_360_feature_enabled = TRUE;
8270         } else {
8271                 LOGE("failed to get spherical feature info");
8272         }
8273
8274         player->is_content_spherical = FALSE;
8275         player->is_video360_enabled = TRUE;
8276         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8277         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8278         player->video360_yaw_radians = 4;
8279         player->video360_pitch_radians = 4;
8280         player->video360_zoom = 1.0f;
8281         player->video360_horizontal_fov = 0;
8282         player->video360_vertical_fov = 0;
8283
8284         /* set player state to null */
8285         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8286         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8287
8288         return MM_ERROR_NONE;
8289
8290 ERROR:
8291         /* free lock */
8292         g_mutex_clear(&player->fsink_lock);
8293
8294         /* free update tag lock */
8295         g_mutex_clear(&player->update_tag_lock);
8296
8297         /* free next play thread */
8298         if (player->next_play_thread) {
8299                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8300                 player->next_play_thread_exit = TRUE;
8301                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8302                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8303
8304                 g_thread_join(player->next_play_thread);
8305                 player->next_play_thread = NULL;
8306
8307                 g_mutex_clear(&player->next_play_thread_mutex);
8308                 g_cond_clear(&player->next_play_thread_cond);
8309         }
8310
8311         /* release attributes */
8312         _mmplayer_deconstruct_attribute(handle);
8313
8314         MMPLAYER_FLEAVE();
8315
8316         return ret;
8317 }
8318
8319 static gboolean
8320 __mmplayer_init_gstreamer(mm_player_t* player)
8321 {
8322         static gboolean initialized = FALSE;
8323         static const int max_argc = 50;
8324         gint* argc = NULL;
8325         gchar** argv = NULL;
8326         gchar** argv2 = NULL;
8327         GError *err = NULL;
8328         int i = 0;
8329         int arg_count = 0;
8330
8331         if (initialized) {
8332                 LOGD("gstreamer already initialized.\n");
8333                 return TRUE;
8334         }
8335
8336         /* alloc */
8337         argc = malloc(sizeof(int));
8338         argv = malloc(sizeof(gchar*) * max_argc);
8339         argv2 = malloc(sizeof(gchar*) * max_argc);
8340
8341         if (!argc || !argv || !argv2)
8342                 goto ERROR;
8343
8344         memset(argv, 0, sizeof(gchar*) * max_argc);
8345         memset(argv2, 0, sizeof(gchar*) * max_argc);
8346
8347         /* add initial */
8348         *argc = 1;
8349         argv[0] = g_strdup("mmplayer");
8350
8351         /* add gst_param */
8352         for (i = 0; i < 5; i++) {
8353                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8354                 if (strlen(player->ini.gst_param[i]) > 0) {
8355                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8356                         (*argc)++;
8357                 }
8358         }
8359
8360         /* we would not do fork for scanning plugins */
8361         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8362         (*argc)++;
8363
8364         /* check disable registry scan */
8365         if (player->ini.skip_rescan) {
8366                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8367                 (*argc)++;
8368         }
8369
8370         /* check disable segtrap */
8371         if (player->ini.disable_segtrap) {
8372                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8373                 (*argc)++;
8374         }
8375
8376         LOGD("initializing gstreamer with following parameter\n");
8377         LOGD("argc : %d\n", *argc);
8378         arg_count = *argc;
8379
8380         for (i = 0; i < arg_count; i++) {
8381                 argv2[i] = argv[i];
8382                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8383         }
8384
8385         /* initializing gstreamer */
8386         if (!gst_init_check(argc, &argv, &err)) {
8387                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8388                 if (err)
8389                         g_error_free(err);
8390
8391                 goto ERROR;
8392         }
8393         /* release */
8394         for (i = 0; i < arg_count; i++) {
8395                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8396                 MMPLAYER_FREEIF(argv2[i]);
8397         }
8398
8399         MMPLAYER_FREEIF(argv);
8400         MMPLAYER_FREEIF(argv2);
8401         MMPLAYER_FREEIF(argc);
8402
8403         /* done */
8404         initialized = TRUE;
8405
8406         return TRUE;
8407
8408 ERROR:
8409
8410         /* release */
8411         for (i = 0; i < arg_count; i++) {
8412                 LOGD("free[%d] : %s\n", i, argv2[i]);
8413                 MMPLAYER_FREEIF(argv2[i]);
8414         }
8415
8416         MMPLAYER_FREEIF(argv);
8417         MMPLAYER_FREEIF(argv2);
8418         MMPLAYER_FREEIF(argc);
8419
8420         return FALSE;
8421 }
8422
8423 int
8424 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8425 {
8426         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8427
8428         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8429                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8430                 MMPLAYER_FREEIF(player->pd_file_save_path);
8431         }
8432
8433         return MM_ERROR_NONE;
8434 }
8435
8436 static void
8437 __mmplayer_check_async_state_transition(mm_player_t* player)
8438 {
8439         GstState element_state = GST_STATE_VOID_PENDING;
8440         GstState element_pending_state = GST_STATE_VOID_PENDING;
8441         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8442         GstElement * element = NULL;
8443         gboolean async = FALSE;
8444
8445         /* check player handle */
8446         MMPLAYER_RETURN_IF_FAIL(player &&
8447                                                 player->pipeline &&
8448                                                 player->pipeline->mainbin &&
8449                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8450
8451         if (player->attrs)
8452                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8453
8454         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8455                 LOGD("don't need to check the pipeline state");
8456                 return;
8457         }
8458
8459         MMPLAYER_PRINT_STATE(player);
8460
8461         /* wait for state transition */
8462         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8463         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8464
8465         if (ret == GST_STATE_CHANGE_FAILURE) {
8466                 LOGE(" [%s] state : %s   pending : %s \n",
8467                         GST_ELEMENT_NAME(element),
8468                         gst_element_state_get_name(element_state),
8469                         gst_element_state_get_name(element_pending_state));
8470
8471                 /* dump state of all element */
8472                 __mmplayer_dump_pipeline_state(player);
8473
8474                 return;
8475         }
8476
8477         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8478         return;
8479 }
8480
8481 int
8482 _mmplayer_destroy(MMHandleType handle)
8483 {
8484         mm_player_t* player = MM_PLAYER_CAST(handle);
8485
8486         MMPLAYER_FENTER();
8487
8488         /* check player handle */
8489         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8490
8491         /* destroy can called at anytime */
8492         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8493
8494         /* check async state transition */
8495         __mmplayer_check_async_state_transition(player);
8496
8497         __mmplayer_destroy_streaming_ext(player);
8498
8499         /* release next play thread */
8500         if (player->next_play_thread) {
8501                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8502                 player->next_play_thread_exit = TRUE;
8503                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8504                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8505
8506                 LOGD("waitting for next play thread exit\n");
8507                 g_thread_join(player->next_play_thread);
8508                 g_mutex_clear(&player->next_play_thread_mutex);
8509                 g_cond_clear(&player->next_play_thread_cond);
8510                 LOGD("next play thread released\n");
8511         }
8512
8513         _mmplayer_release_video_capture(player);
8514
8515         /* de-initialize resource manager */
8516         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8517                         player->resource_manager))
8518                 LOGE("failed to deinitialize resource manager\n");
8519
8520         /* release pipeline */
8521         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8522                 LOGE("failed to destory pipeline\n");
8523                 return MM_ERROR_PLAYER_INTERNAL;
8524         }
8525
8526         /* release subtitle info lock and cond */
8527         g_mutex_clear(&player->subtitle_info_mutex);
8528         g_cond_clear(&player->subtitle_info_cond);
8529
8530         __mmplayer_release_dump_list(player->dump_list);
8531
8532         /* release miscellaneous information */
8533         __mmplayer_release_misc(player);
8534
8535         /* release miscellaneous information.
8536            these info needs to be released after pipeline is destroyed. */
8537         __mmplayer_release_misc_post(player);
8538
8539         /* release attributes */
8540         _mmplayer_deconstruct_attribute(handle);
8541
8542         /* release lock */
8543         g_mutex_clear(&player->fsink_lock);
8544
8545         /* release lock */
8546         g_mutex_clear(&player->update_tag_lock);
8547
8548         /* release video bo lock and cond */
8549         g_mutex_clear(&player->video_bo_mutex);
8550         g_cond_clear(&player->video_bo_cond);
8551
8552         /* release media stream callback lock */
8553         g_mutex_clear(&player->media_stream_cb_lock);
8554
8555         MMPLAYER_FLEAVE();
8556
8557         return MM_ERROR_NONE;
8558 }
8559
8560 int
8561 __mmplayer_realize_streaming_ext(mm_player_t* player)
8562 {
8563         int ret = MM_ERROR_NONE;
8564
8565         MMPLAYER_FENTER();
8566         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8567
8568         if (MMPLAYER_IS_HTTP_PD(player)) {
8569                 gboolean bret = FALSE;
8570
8571                 player->pd_downloader = _mmplayer_create_pd_downloader();
8572                 if (!player->pd_downloader) {
8573                         LOGE("Unable to create PD Downloader...");
8574                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8575                 }
8576
8577                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8578
8579                 if (FALSE == bret) {
8580                         LOGE("Unable to create PD Downloader...");
8581                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8582                 }
8583         }
8584
8585         MMPLAYER_FLEAVE();
8586         return ret;
8587 }
8588
8589 int
8590 _mmplayer_realize(MMHandleType hplayer)
8591 {
8592         mm_player_t* player = (mm_player_t*)hplayer;
8593         char *uri = NULL;
8594         void *param = NULL;
8595         MMHandleType attrs = 0;
8596         int ret = MM_ERROR_NONE;
8597
8598         MMPLAYER_FENTER();
8599
8600         /* check player handle */
8601         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8602
8603         /* check current state */
8604         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8605
8606         attrs = MMPLAYER_GET_ATTRS(player);
8607         if (!attrs) {
8608                 LOGE("fail to get attributes.\n");
8609                 return MM_ERROR_PLAYER_INTERNAL;
8610         }
8611         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8612         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8613
8614         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8615                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8616
8617                 if (ret != MM_ERROR_NONE) {
8618                         LOGE("failed to parse profile\n");
8619                         return ret;
8620                 }
8621         }
8622
8623         if (uri && (strstr(uri, "es_buff://"))) {
8624                 if (strstr(uri, "es_buff://push_mode"))
8625                         player->es_player_push_mode = TRUE;
8626                 else
8627                         player->es_player_push_mode = FALSE;
8628         }
8629
8630         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8631                 LOGW("mms protocol is not supported format.\n");
8632                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8633         }
8634
8635         if (MMPLAYER_IS_STREAMING(player))
8636                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8637         else
8638                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8639
8640         player->smooth_streaming = FALSE;
8641         player->videodec_linked  = 0;
8642         player->videosink_linked = 0;
8643         player->audiodec_linked  = 0;
8644         player->audiosink_linked = 0;
8645         player->textsink_linked = 0;
8646         player->is_external_subtitle_present = FALSE;
8647         player->is_external_subtitle_added_now = FALSE;
8648         /* set the subtitle ON default */
8649         player->is_subtitle_off = FALSE;
8650
8651         /* realize pipeline */
8652         ret = __gst_realize(player);
8653         if (ret != MM_ERROR_NONE)
8654                 LOGE("fail to realize the player.\n");
8655         else
8656                 ret = __mmplayer_realize_streaming_ext(player);
8657
8658         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8659         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8660
8661         MMPLAYER_FLEAVE();
8662
8663         return ret;
8664 }
8665
8666 int
8667 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8668 {
8669         MMPLAYER_FENTER();
8670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8671
8672         /* destroy can called at anytime */
8673         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8674                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8675
8676         MMPLAYER_FLEAVE();
8677         return MM_ERROR_NONE;
8678 }
8679
8680 int
8681 _mmplayer_unrealize(MMHandleType hplayer)
8682 {
8683         mm_player_t* player = (mm_player_t*)hplayer;
8684         int ret = MM_ERROR_NONE;
8685
8686         MMPLAYER_FENTER();
8687
8688         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8689
8690         MMPLAYER_CMD_UNLOCK(player);
8691         /* destroy the gst bus msg thread which is created during realize.
8692            this funct have to be called before getting cmd lock. */
8693         _mmplayer_bus_msg_thread_destroy(player);
8694         MMPLAYER_CMD_LOCK(player);
8695
8696         /* check current state */
8697         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8698
8699         /* check async state transition */
8700         __mmplayer_check_async_state_transition(player);
8701
8702         __mmplayer_unrealize_streaming_ext(player);
8703
8704         /* unrealize pipeline */
8705         ret = __gst_unrealize(player);
8706
8707         /* set asm stop if success */
8708         if (MM_ERROR_NONE == ret) {
8709                 if (!player->interrupted_by_resource) {
8710                         if (player->video_decoder_resource != NULL) {
8711                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8712                                                 player->video_decoder_resource);
8713                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8714                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8715                                 else
8716                                         player->video_decoder_resource = NULL;
8717                         }
8718
8719                         if (player->video_overlay_resource != NULL) {
8720                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8721                                                 player->video_overlay_resource);
8722                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8723                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8724                                 else
8725                                         player->video_overlay_resource = NULL;
8726                         }
8727
8728                         ret = mm_resource_manager_commit(player->resource_manager);
8729                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8730                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8731                 }
8732         } else
8733                 LOGE("failed and don't change asm state to stop");
8734
8735         MMPLAYER_FLEAVE();
8736
8737         return ret;
8738 }
8739
8740 int
8741 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8742 {
8743         mm_player_t* player = (mm_player_t*)hplayer;
8744
8745         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8746
8747         return __gst_set_message_callback(player, callback, user_param);
8748 }
8749
8750 int
8751 _mmplayer_get_state(MMHandleType hplayer, int* state)
8752 {
8753         mm_player_t *player = (mm_player_t*)hplayer;
8754
8755         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8756
8757         *state = MMPLAYER_CURRENT_STATE(player);
8758
8759         return MM_ERROR_NONE;
8760 }
8761
8762
8763 int
8764 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8765 {
8766         mm_player_t* player = (mm_player_t*) hplayer;
8767         GstElement* vol_element = NULL;
8768         int i = 0;
8769
8770         MMPLAYER_FENTER();
8771
8772         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8773
8774         LOGD("volume [L]=%f:[R]=%f\n",
8775                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8776
8777         /* invalid factor range or not */
8778         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8779                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8780                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8781                         return MM_ERROR_INVALID_ARGUMENT;
8782                 }
8783         }
8784
8785         /* not support to set other value into each channel */
8786         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8787                 return MM_ERROR_INVALID_ARGUMENT;
8788
8789         /* Save volume to handle. Currently the first array element will be saved. */
8790         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8791
8792         /* check pipeline handle */
8793         if (!player->pipeline || !player->pipeline->audiobin) {
8794                 LOGD("audiobin is not created yet\n");
8795                 LOGD("but, current stored volume will be set when it's created.\n");
8796
8797                 /* NOTE : stored volume will be used in create_audiobin
8798                  * returning MM_ERROR_NONE here makes application to able to
8799                  * set volume at anytime.
8800                  */
8801                 return MM_ERROR_NONE;
8802         }
8803
8804         /* setting volume to volume element */
8805         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8806
8807         if (vol_element) {
8808                 LOGD("volume is set [%f]\n", player->sound.volume);
8809                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8810         }
8811
8812         MMPLAYER_FLEAVE();
8813
8814         return MM_ERROR_NONE;
8815 }
8816
8817
8818 int
8819 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8820 {
8821         mm_player_t* player = (mm_player_t*) hplayer;
8822         int i = 0;
8823
8824         MMPLAYER_FENTER();
8825
8826         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8827         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8828
8829         /* returning stored volume */
8830         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8831                 volume->level[i] = player->sound.volume;
8832
8833         MMPLAYER_FLEAVE();
8834
8835         return MM_ERROR_NONE;
8836 }
8837
8838 int
8839 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8840 {
8841         mm_player_t* player = (mm_player_t*) hplayer;
8842         GstElement* vol_element = NULL;
8843
8844         MMPLAYER_FENTER();
8845
8846         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8847
8848         /* mute value shoud 0 or 1 */
8849         if (mute != 0 && mute != 1) {
8850                 LOGE("bad mute value\n");
8851
8852                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8853                 return MM_ERROR_INVALID_ARGUMENT;
8854         }
8855
8856         player->sound.mute = mute;
8857
8858         /* just hold mute value if pipeline is not ready */
8859         if (!player->pipeline || !player->pipeline->audiobin) {
8860                 LOGD("pipeline is not ready. holding mute value\n");
8861                 return MM_ERROR_NONE;
8862         }
8863
8864         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8865
8866         /* NOTE : volume will only created when the bt is enabled */
8867         if (vol_element) {
8868                 LOGD("mute : %d\n", mute);
8869                 g_object_set(vol_element, "mute", mute, NULL);
8870         } else
8871                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8872
8873         MMPLAYER_FLEAVE();
8874
8875         return MM_ERROR_NONE;
8876 }
8877
8878 int
8879 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8880 {
8881         mm_player_t* player = (mm_player_t*) hplayer;
8882
8883         MMPLAYER_FENTER();
8884
8885         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8886         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8887
8888         /* just hold mute value if pipeline is not ready */
8889         if (!player->pipeline || !player->pipeline->audiobin) {
8890                 LOGD("pipeline is not ready. returning stored value\n");
8891                 *pmute = player->sound.mute;
8892                 return MM_ERROR_NONE;
8893         }
8894
8895         *pmute = player->sound.mute;
8896
8897         MMPLAYER_FLEAVE();
8898
8899         return MM_ERROR_NONE;
8900 }
8901
8902 int
8903 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8904 {
8905         mm_player_t* player = (mm_player_t*) hplayer;
8906
8907         MMPLAYER_FENTER();
8908
8909         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8910
8911         player->video_stream_changed_cb = callback;
8912         player->video_stream_changed_cb_user_param = user_param;
8913         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8914
8915         MMPLAYER_FLEAVE();
8916
8917         return MM_ERROR_NONE;
8918 }
8919
8920 int
8921 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8922 {
8923         mm_player_t* player = (mm_player_t*) hplayer;
8924
8925         MMPLAYER_FENTER();
8926
8927         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8928
8929         player->audio_stream_changed_cb = callback;
8930         player->audio_stream_changed_cb_user_param = user_param;
8931         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8932
8933         MMPLAYER_FLEAVE();
8934
8935         return MM_ERROR_NONE;
8936 }
8937
8938 int
8939 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8940 {
8941         mm_player_t* player = (mm_player_t*) hplayer;
8942
8943         MMPLAYER_FENTER();
8944
8945         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8946
8947         player->audio_stream_render_cb_ex = callback;
8948         player->audio_stream_cb_user_param = user_param;
8949         player->audio_stream_sink_sync = sync;
8950         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);
8951
8952         MMPLAYER_FLEAVE();
8953
8954         return MM_ERROR_NONE;
8955 }
8956
8957 int
8958 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8959 {
8960         mm_player_t* player = (mm_player_t*) hplayer;
8961
8962         MMPLAYER_FENTER();
8963
8964         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8965
8966         if (callback && !player->bufmgr)
8967                 player->bufmgr = tbm_bufmgr_init(-1);
8968
8969         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8970         player->video_stream_cb = callback;
8971         player->video_stream_cb_user_param = user_param;
8972
8973         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8974
8975         MMPLAYER_FLEAVE();
8976
8977         return MM_ERROR_NONE;
8978 }
8979
8980 int
8981 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8982 {
8983         mm_player_t* player = (mm_player_t*) hplayer;
8984
8985         MMPLAYER_FENTER();
8986
8987         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8988
8989         player->audio_stream_cb = callback;
8990         player->audio_stream_cb_user_param = user_param;
8991         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8992
8993         MMPLAYER_FLEAVE();
8994
8995         return MM_ERROR_NONE;
8996 }
8997
8998 static int
8999 __mmplayer_start_streaming_ext(mm_player_t *player)
9000 {
9001         gint ret = MM_ERROR_NONE;
9002
9003         MMPLAYER_FENTER();
9004         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9005
9006         if (MMPLAYER_IS_HTTP_PD(player)) {
9007                 if (!player->pd_downloader) {
9008                         ret = __mmplayer_realize_streaming_ext(player);
9009
9010                         if (ret != MM_ERROR_NONE) {
9011                                 LOGE("failed to realize streaming ext\n");
9012                                 return ret;
9013                         }
9014                 }
9015
9016                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9017                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9018                         if (!ret) {
9019                                 LOGE("ERROR while starting PD...\n");
9020                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9021                         }
9022                         ret = MM_ERROR_NONE;
9023                 }
9024         }
9025
9026         MMPLAYER_FLEAVE();
9027         return ret;
9028 }
9029
9030 int
9031 _mmplayer_start(MMHandleType hplayer)
9032 {
9033         mm_player_t* player = (mm_player_t*) hplayer;
9034         gint ret = MM_ERROR_NONE;
9035
9036         MMPLAYER_FENTER();
9037
9038         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9039
9040         /* check current state */
9041         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9042
9043         /* NOTE : we should check and create pipeline again if not created as we destroy
9044          * whole pipeline when stopping in streamming playback
9045          */
9046         if (!player->pipeline) {
9047                 ret = __gst_realize(player);
9048                 if (MM_ERROR_NONE != ret) {
9049                         LOGE("failed to realize before starting. only in streamming\n");
9050                         /* unlock */
9051                         return ret;
9052                 }
9053         }
9054
9055         ret = __mmplayer_start_streaming_ext(player);
9056         if (ret != MM_ERROR_NONE) {
9057                 LOGE("failed to start streaming ext 0x%X", ret);
9058                 return ret;
9059         }
9060
9061         /* start pipeline */
9062         ret = __gst_start(player);
9063         if (ret != MM_ERROR_NONE)
9064                 LOGE("failed to start player.\n");
9065
9066         MMPLAYER_FLEAVE();
9067
9068         return ret;
9069 }
9070
9071 /* NOTE: post "not supported codec message" to application
9072  * when one codec is not found during AUTOPLUGGING in MSL.
9073  * So, it's separated with error of __mmplayer_gst_callback().
9074  * And, if any codec is not found, don't send message here.
9075  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9076  */
9077 int
9078 __mmplayer_handle_missed_plugin(mm_player_t* player)
9079 {
9080         MMMessageParamType msg_param;
9081         memset(&msg_param, 0, sizeof(MMMessageParamType));
9082         gboolean post_msg_direct = FALSE;
9083
9084         MMPLAYER_FENTER();
9085
9086         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9087
9088         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9089                         player->not_supported_codec, player->can_support_codec);
9090
9091         if (player->not_found_demuxer) {
9092                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9093                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9094
9095                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9096                 MMPLAYER_FREEIF(msg_param.data);
9097
9098                 return MM_ERROR_NONE;
9099         }
9100
9101         if (player->not_supported_codec) {
9102                 if (player->can_support_codec) {
9103                         // There is one codec to play
9104                         post_msg_direct = TRUE;
9105                 } else {
9106                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9107                                 post_msg_direct = TRUE;
9108                 }
9109
9110                 if (post_msg_direct) {
9111                         MMMessageParamType msg_param;
9112                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9113
9114                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9115                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9116
9117                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9118                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9119                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9120                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9121
9122                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9123                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9124                         }
9125
9126                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9127
9128                         MMPLAYER_FREEIF(msg_param.data);
9129
9130                         return MM_ERROR_NONE;
9131                 } else {
9132                         // no any supported codec case
9133                         LOGW("not found any codec, posting error code to application.\n");
9134
9135                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9136                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9137                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9138                         } else {
9139                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9140                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9141                         }
9142
9143                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9144
9145                         MMPLAYER_FREEIF(msg_param.data);
9146                 }
9147         }
9148
9149         MMPLAYER_FLEAVE();
9150
9151         return MM_ERROR_NONE;
9152 }
9153
9154 static void __mmplayer_check_pipeline(mm_player_t* player)
9155 {
9156         GstState element_state = GST_STATE_VOID_PENDING;
9157         GstState element_pending_state = GST_STATE_VOID_PENDING;
9158         gint timeout = 0;
9159         int ret = MM_ERROR_NONE;
9160
9161         if (player->gapless.reconfigure) {
9162                 LOGW("pipeline is under construction.\n");
9163
9164                 MMPLAYER_PLAYBACK_LOCK(player);
9165                 MMPLAYER_PLAYBACK_UNLOCK(player);
9166
9167                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9168
9169                 /* wait for state transition */
9170                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9171
9172                 if (ret == GST_STATE_CHANGE_FAILURE)
9173                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9174         }
9175 }
9176
9177 /* NOTE : it should be able to call 'stop' anytime*/
9178 int
9179 _mmplayer_stop(MMHandleType hplayer)
9180 {
9181         mm_player_t* player = (mm_player_t*)hplayer;
9182         int ret = MM_ERROR_NONE;
9183
9184         MMPLAYER_FENTER();
9185
9186         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9187
9188         /* check current state */
9189         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9190
9191         /* check pipline building state */
9192         __mmplayer_check_pipeline(player);
9193         __mmplayer_reset_gapless_state(player);
9194
9195         /* NOTE : application should not wait for EOS after calling STOP */
9196         __mmplayer_cancel_eos_timer(player);
9197
9198         __mmplayer_unrealize_streaming_ext(player);
9199
9200         /* reset */
9201         player->doing_seek = FALSE;
9202
9203         /* stop pipeline */
9204         ret = __gst_stop(player);
9205
9206         if (ret != MM_ERROR_NONE)
9207                 LOGE("failed to stop player.\n");
9208
9209         MMPLAYER_FLEAVE();
9210
9211         return ret;
9212 }
9213
9214 int
9215 _mmplayer_pause(MMHandleType hplayer)
9216 {
9217         mm_player_t* player = (mm_player_t*)hplayer;
9218         gint64 pos_msec = 0;
9219         gboolean async = FALSE;
9220         gint ret = MM_ERROR_NONE;
9221
9222         MMPLAYER_FENTER();
9223
9224         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9225
9226         /* check current state */
9227         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9228
9229         /* check pipline building state */
9230         __mmplayer_check_pipeline(player);
9231
9232         switch (MMPLAYER_CURRENT_STATE(player)) {
9233         case MM_PLAYER_STATE_READY:
9234                 {
9235                         /* check prepare async or not.
9236                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9237                          */
9238                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9239                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9240
9241                         /* Changing back sync of rtspsrc to async */
9242                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9243                                 LOGD("async prepare working mode for rtsp");
9244                                 async = TRUE;
9245                         }
9246                 }
9247                 break;
9248
9249         case MM_PLAYER_STATE_PLAYING:
9250                 {
9251                         /* NOTE : store current point to overcome some bad operation
9252                         *(returning zero when getting current position in paused state) of some
9253                         * elements
9254                         */
9255                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9256                                 LOGW("getting current position failed in paused\n");
9257
9258                         player->last_position = pos_msec;
9259
9260                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9261                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9262                            This causes problem is position calculation during normal pause resume scenarios also.
9263                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9264                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9265                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9266                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9267                         }
9268                 }
9269                 break;
9270         }
9271
9272         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9273                 LOGD("doing async pause in case of ms buff src");
9274                 async = TRUE;
9275         }
9276
9277         /* pause pipeline */
9278         ret = __gst_pause(player, async);
9279
9280         if (ret != MM_ERROR_NONE)
9281                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9282
9283         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9284                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9285                         LOGE("failed to update display_rotation");
9286         }
9287
9288         MMPLAYER_FLEAVE();
9289
9290         return ret;
9291 }
9292
9293 int
9294 _mmplayer_resume(MMHandleType hplayer)
9295 {
9296         mm_player_t* player = (mm_player_t*)hplayer;
9297         int ret = MM_ERROR_NONE;
9298         gboolean async = FALSE;
9299
9300         MMPLAYER_FENTER();
9301
9302         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9303
9304         /* Changing back sync mode rtspsrc to async */
9305         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9306                 LOGD("async resume for rtsp case");
9307                 async = TRUE;
9308         }
9309
9310         /* check current state */
9311         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9312
9313         ret = __gst_resume(player, async);
9314
9315         if (ret != MM_ERROR_NONE)
9316                 LOGE("failed to resume player.\n");
9317
9318         MMPLAYER_FLEAVE();
9319
9320         return ret;
9321 }
9322
9323 static int
9324 __mmplayer_set_pcm_extraction(mm_player_t* player)
9325 {
9326         gint64 start_nsec = 0;
9327         gint64 end_nsec = 0;
9328         gint64 dur_nsec = 0;
9329         gint64 dur_msec = 0;
9330         int required_start = 0;
9331         int required_end = 0;
9332         int ret = 0;
9333
9334         MMPLAYER_FENTER();
9335
9336         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9337
9338         mm_attrs_multiple_get(player->attrs,
9339                 NULL,
9340                 "pcm_extraction_start_msec", &required_start,
9341                 "pcm_extraction_end_msec", &required_end,
9342                 NULL);
9343
9344         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9345
9346         if (required_start == 0 && required_end == 0) {
9347                 LOGD("extracting entire stream");
9348                 return MM_ERROR_NONE;
9349         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9350                 LOGD("invalid range for pcm extraction");
9351                 return MM_ERROR_INVALID_ARGUMENT;
9352         }
9353
9354         /* get duration */
9355         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9356         if (!ret) {
9357                 LOGE("failed to get duration");
9358                 return MM_ERROR_PLAYER_INTERNAL;
9359         }
9360         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9361
9362         if (dur_msec < required_end) {
9363                 // FIXME
9364                 LOGD("invalid end pos for pcm extraction");
9365                 return MM_ERROR_INVALID_ARGUMENT;
9366         }
9367
9368         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9369         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9370
9371         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9372                                         1.0,
9373                                         GST_FORMAT_TIME,
9374                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9375                                         GST_SEEK_TYPE_SET, start_nsec,
9376                                         GST_SEEK_TYPE_SET, end_nsec))) {
9377                 LOGE("failed to seek for pcm extraction\n");
9378
9379                 return MM_ERROR_PLAYER_SEEK;
9380         }
9381
9382         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9383
9384         MMPLAYER_FLEAVE();
9385
9386         return MM_ERROR_NONE;
9387 }
9388
9389 int
9390 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9391 {
9392         mm_player_t* player = (mm_player_t*)hplayer;
9393         gint64 pos_msec = 0;
9394         int ret = MM_ERROR_NONE;
9395         int mute = FALSE;
9396         signed long long start = 0, stop = 0;
9397         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9398         MMPLAYER_FENTER();
9399
9400         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9401         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9402
9403         /* The sound of video is not supported under 0.0 and over 2.0. */
9404         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9405                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9406                         mute = TRUE;
9407         }
9408         _mmplayer_set_mute(hplayer, mute);
9409
9410         if (player->playback_rate == rate)
9411                 return MM_ERROR_NONE;
9412
9413         /* If the position is reached at start potion during fast backward, EOS is posted.
9414          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9415          * */
9416         player->playback_rate = rate;
9417
9418         current_state = MMPLAYER_CURRENT_STATE(player);
9419
9420         if (current_state != MM_PLAYER_STATE_PAUSED)
9421                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9422
9423         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9424
9425         if ((current_state == MM_PLAYER_STATE_PAUSED)
9426                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9427                 LOGW("returning last point : %lld\n", player->last_position);
9428                 pos_msec = player->last_position;
9429         }
9430
9431         if (rate >= 0) {
9432                 start = pos_msec;
9433                 stop = GST_CLOCK_TIME_NONE;
9434         } else {
9435                 start = GST_CLOCK_TIME_NONE;
9436                 stop = pos_msec;
9437         }
9438
9439         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9440                                 player->playback_rate,
9441                                 GST_FORMAT_TIME,
9442                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9443                                 GST_SEEK_TYPE_SET, start,
9444                                 GST_SEEK_TYPE_SET, stop)) {
9445                 LOGE("failed to set speed playback\n");
9446                 return MM_ERROR_PLAYER_SEEK;
9447         }
9448
9449         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9450
9451         MMPLAYER_FLEAVE();
9452
9453         return MM_ERROR_NONE;;
9454 }
9455
9456 int
9457 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9458 {
9459         mm_player_t* player = (mm_player_t*)hplayer;
9460         int ret = MM_ERROR_NONE;
9461
9462         MMPLAYER_FENTER();
9463
9464         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9465
9466         /* check pipline building state */
9467         __mmplayer_check_pipeline(player);
9468
9469         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9470
9471         MMPLAYER_FLEAVE();
9472
9473         return ret;
9474 }
9475
9476 int
9477 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9478 {
9479         mm_player_t* player = (mm_player_t*)hplayer;
9480         int ret = MM_ERROR_NONE;
9481
9482         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9483
9484         ret = __gst_get_position(player, format, position);
9485
9486         return ret;
9487 }
9488
9489 int
9490 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9491 {
9492         mm_player_t* player = (mm_player_t*)hplayer;
9493         int ret = MM_ERROR_NONE;
9494
9495         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9496
9497         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9498
9499         return ret;
9500 }
9501
9502 int
9503 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9504 {
9505         mm_player_t* player = (mm_player_t*)hplayer;
9506         int ret = MM_ERROR_NONE;
9507
9508         MMPLAYER_FENTER();
9509
9510         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9511
9512         ret = __gst_adjust_subtitle_position(player, format, position);
9513
9514         MMPLAYER_FLEAVE();
9515
9516         return ret;
9517 }
9518 int
9519 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9520 {
9521         mm_player_t* player = (mm_player_t*)hplayer;
9522         int ret = MM_ERROR_NONE;
9523
9524         MMPLAYER_FENTER();
9525
9526         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9527
9528         ret = __gst_adjust_video_position(player, offset);
9529
9530         MMPLAYER_FLEAVE();
9531
9532         return ret;
9533 }
9534
9535 static gboolean
9536 __mmplayer_is_midi_type(gchar* str_caps)
9537 {
9538         if ((g_strrstr(str_caps, "audio/midi")) ||
9539                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9540                 (g_strrstr(str_caps, "application/x-smaf")) ||
9541                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9542                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9543                 (g_strrstr(str_caps, "audio/xmf")) ||
9544                 (g_strrstr(str_caps, "audio/mxmf"))) {
9545                 LOGD("midi\n");
9546                 return TRUE;
9547         }
9548
9549         return FALSE;
9550 }
9551
9552 static gboolean
9553 __mmplayer_is_only_mp3_type(gchar *str_caps)
9554 {
9555         if (g_strrstr(str_caps, "application/x-id3") ||
9556                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9557                 return TRUE;
9558         return FALSE;
9559 }
9560
9561 static void
9562 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9563 {
9564         GstStructure* caps_structure = NULL;
9565         gint samplerate = 0;
9566         gint channels = 0;
9567
9568         MMPLAYER_FENTER();
9569         MMPLAYER_RETURN_IF_FAIL(player && caps);
9570
9571         caps_structure = gst_caps_get_structure(caps, 0);
9572
9573         /* set stream information */
9574         gst_structure_get_int(caps_structure, "rate", &samplerate);
9575         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9576
9577         gst_structure_get_int(caps_structure, "channels", &channels);
9578         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9579
9580         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9581 }
9582
9583 static void
9584 __mmplayer_update_content_type_info(mm_player_t* player)
9585 {
9586         MMPLAYER_FENTER();
9587         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9588
9589         if (__mmplayer_is_midi_type(player->type)) {
9590                 player->bypass_audio_effect = TRUE;
9591         } else if (g_strrstr(player->type, "application/x-hls")) {
9592                 /* If it can't know exact type when it parses uri because of redirection case,
9593                  * it will be fixed by typefinder or when doing autoplugging.
9594                  */
9595                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9596                 if (player->streamer) {
9597                         player->streamer->is_adaptive_streaming = TRUE;
9598                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9599                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9600                 }
9601         } else if (g_strrstr(player->type, "application/dash+xml")) {
9602                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9603         }
9604
9605         MMPLAYER_FLEAVE();
9606 }
9607
9608 static void
9609 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9610 GstCaps *caps, gpointer data)
9611 {
9612         mm_player_t* player = (mm_player_t*)data;
9613         GstPad* pad = NULL;
9614
9615         MMPLAYER_FENTER();
9616
9617         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9618
9619         /* store type string */
9620         MMPLAYER_FREEIF(player->type);
9621         player->type = gst_caps_to_string(caps);
9622         if (player->type) {
9623                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9624                                 player, player->type, probability, gst_caps_get_size(caps));
9625         }
9626
9627         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9628                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9629                 LOGE("not support media format\n");
9630
9631                 if (player->msg_posted == FALSE) {
9632                         MMMessageParamType msg_param;
9633                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9634
9635                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9636                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9637
9638                         /* don't post more if one was sent already */
9639                         player->msg_posted = TRUE;
9640                 }
9641                 return;
9642         }
9643
9644         __mmplayer_update_content_type_info(player);
9645
9646         pad = gst_element_get_static_pad(tf, "src");
9647         if (!pad) {
9648                 LOGE("fail to get typefind src pad.\n");
9649                 return;
9650         }
9651
9652         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9653                 gboolean async = FALSE;
9654                 LOGE("failed to autoplug %s\n", player->type);
9655
9656                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9657
9658                 if (async && player->msg_posted == FALSE)
9659                         __mmplayer_handle_missed_plugin(player);
9660
9661                 goto DONE;
9662         }
9663
9664 DONE:
9665         gst_object_unref(GST_OBJECT(pad));
9666
9667         MMPLAYER_FLEAVE();
9668
9669         return;
9670 }
9671
9672 static GstElement *
9673 __mmplayer_create_decodebin(mm_player_t* player)
9674 {
9675         GstElement *decodebin = NULL;
9676
9677         MMPLAYER_FENTER();
9678
9679         /* create decodebin */
9680         decodebin = gst_element_factory_make("decodebin", NULL);
9681
9682         if (!decodebin) {
9683                 LOGE("fail to create decodebin\n");
9684                 goto ERROR;
9685         }
9686
9687         /* raw pad handling signal */
9688         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9689                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9690
9691         /* no-more-pad pad handling signal */
9692         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9693                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9694
9695         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9696                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9697
9698         /* This signal is emitted when a pad for which there is no further possible
9699            decoding is added to the decodebin.*/
9700         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9701                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9702
9703         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9704            before looking for any elements that can handle that stream.*/
9705         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9706                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9707
9708         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9709            before looking for any elements that can handle that stream.*/
9710         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9711                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9712
9713         /* This signal is emitted once decodebin has finished decoding all the data.*/
9714         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9715                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9716
9717         /* This signal is emitted when a element is added to the bin.*/
9718         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9719                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9720
9721 ERROR:
9722         return decodebin;
9723 }
9724
9725 static gboolean
9726 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9727 {
9728         MMPlayerGstElement* mainbin = NULL;
9729         GstElement* decodebin = NULL;
9730         GstElement* queue2 = NULL;
9731         GstPad* sinkpad = NULL;
9732         GstPad* qsrcpad = NULL;
9733         gint64 dur_bytes = 0L;
9734
9735         guint max_buffer_size_bytes = 0;
9736         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9737
9738         MMPLAYER_FENTER();
9739         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9740
9741         mainbin = player->pipeline->mainbin;
9742
9743         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9744                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9745                 LOGD("creating http streaming buffering queue(queue2)\n");
9746
9747                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9748                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9749                 } else {
9750                         queue2 = gst_element_factory_make("queue2", "queue2");
9751                         if (!queue2) {
9752                                 LOGE("failed to create buffering queue element\n");
9753                                 goto ERROR;
9754                         }
9755
9756                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9757                                 LOGE("failed to add buffering queue\n");
9758                                 goto ERROR;
9759                         }
9760
9761                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9762                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9763
9764                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9765                                 LOGE("failed to link buffering queue\n");
9766                                 goto ERROR;
9767                         }
9768
9769                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9770                                 LOGE("fail to get duration.\n");
9771
9772                         LOGD("dur_bytes = %lld\n", dur_bytes);
9773
9774                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9775
9776                         if (dur_bytes > 0) {
9777                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9778                                         type = MUXED_BUFFER_TYPE_FILE;
9779                                 } else {
9780                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9781                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9782                                 }
9783                         } else {
9784                                 dur_bytes = 0;
9785                         }
9786
9787                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9788                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9789                         if (!g_strrstr(player->type, "video/mpegts")) {
9790                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9791                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9792
9793                                 // FIXME : pass ini setting directly. is this ok?
9794                                 __mm_player_streaming_set_queue2(player->streamer,
9795                                                                                                 queue2,
9796                                                                                                 FALSE,
9797                                                                                                 max_buffer_size_bytes,
9798                                                                                                 player->ini.http_buffering_time,
9799                                                                                                 1.0,                                                            // no meaning
9800                                                                                                 player->ini.http_buffering_limit,       // no meaning
9801                                                                                                 type,
9802                                                                                                 player->http_file_buffering_path,
9803                                                                                                 (guint64)dur_bytes);
9804                         }
9805
9806                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9807                                 LOGE("failed to sync queue2 state with parent\n");
9808                                 goto ERROR;
9809                         }
9810
9811                         srcpad = qsrcpad;
9812
9813                         gst_object_unref(GST_OBJECT(sinkpad));
9814
9815                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9816                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9817                 }
9818         }
9819
9820         /* create decodebin */
9821         decodebin = __mmplayer_create_decodebin(player);
9822
9823         if (!decodebin) {
9824                 LOGE("can not create autoplug element\n");
9825                 goto ERROR;
9826         }
9827
9828         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9829                 LOGE("failed to add decodebin\n");
9830                 goto ERROR;
9831         }
9832
9833         /* to force caps on the decodebin element and avoid reparsing stuff by
9834         * typefind. It also avoids a deadlock in the way typefind activates pads in
9835         * the state change */
9836         g_object_set(decodebin, "sink-caps", caps, NULL);
9837
9838         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9839
9840         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9841                 LOGE("failed to link decodebin\n");
9842                 goto ERROR;
9843         }
9844
9845         gst_object_unref(GST_OBJECT(sinkpad));
9846
9847         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9848         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9849
9850         /* set decodebin property about buffer in streaming playback. *
9851          * in case of HLS/DASH, it does not need to have big buffer        *
9852          * because it is kind of adaptive streaming.                  */
9853         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9854                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9855                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9856                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9857
9858                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9859                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9860                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9861                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9862                 }
9863
9864                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9865                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9866                                                                                         "low-percent", 1,   // 1%
9867                                                                                         "max-size-bytes", max_size_bytes,
9868                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9869                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9870         }
9871
9872         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9873                 LOGE("failed to sync decodebin state with parent\n");
9874                 goto ERROR;
9875         }
9876
9877         MMPLAYER_FLEAVE();
9878
9879         return TRUE;
9880
9881 ERROR:
9882
9883         if (sinkpad)
9884                 gst_object_unref(GST_OBJECT(sinkpad));
9885
9886         if (queue2) {
9887                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9888                  * You need to explicitly set elements to the NULL state before
9889                  * dropping the final reference, to allow them to clean up.
9890                  */
9891                 gst_element_set_state(queue2, GST_STATE_NULL);
9892
9893                 /* And, it still has a parent "player".
9894                  * You need to let the parent manage the object instead of unreffing the object directly.
9895                  */
9896                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9897                 gst_object_unref(queue2);
9898                 queue2 = NULL;
9899         }
9900
9901         if (decodebin) {
9902                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9903                  * You need to explicitly set elements to the NULL state before
9904                  * dropping the final reference, to allow them to clean up.
9905                  */
9906                 gst_element_set_state(decodebin, GST_STATE_NULL);
9907
9908                 /* And, it still has a parent "player".
9909                  * You need to let the parent manage the object instead of unreffing the object directly.
9910                  */
9911
9912                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9913                 gst_object_unref(decodebin);
9914                 decodebin = NULL;
9915         }
9916
9917         return FALSE;
9918 }
9919
9920 static int
9921 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9922 {
9923         MMPLAYER_FENTER();
9924
9925         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9926         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9927
9928         LOGD("class : %s, mime : %s \n", factory_class, mime);
9929
9930         /* add missing plugin */
9931         /* NOTE : msl should check missing plugin for image mime type.
9932          * Some motion jpeg clips can have playable audio track.
9933          * So, msl have to play audio after displaying popup written video format not supported.
9934          */
9935         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9936                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9937                         LOGD("not found demuxer\n");
9938                         player->not_found_demuxer = TRUE;
9939                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9940
9941                         goto DONE;
9942                 }
9943         }
9944
9945         if (!g_strrstr(factory_class, "Demuxer")) {
9946                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9947                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9948                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9949
9950                         /* check that clip have multi tracks or not */
9951                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9952                                 LOGD("video plugin is already linked\n");
9953                         } else {
9954                                 LOGW("add VIDEO to missing plugin\n");
9955                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9956                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9957                         }
9958                 } else if (g_str_has_prefix(mime, "audio")) {
9959                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9960                                 LOGD("audio plugin is already linked\n");
9961                         } else {
9962                                 LOGW("add AUDIO to missing plugin\n");
9963                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9964                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9965                         }
9966                 }
9967         }
9968
9969 DONE:
9970         MMPLAYER_FLEAVE();
9971
9972         return MM_ERROR_NONE;
9973 }
9974
9975
9976 static void
9977 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
9978 {
9979         mm_player_t* player = (mm_player_t*)data;
9980
9981         MMPLAYER_FENTER();
9982
9983         MMPLAYER_RETURN_IF_FAIL(player);
9984
9985         /* remove fakesink. */
9986         if (!__mmplayer_gst_remove_fakesink(player,
9987                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9988                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9989                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9990                  * source element are not same. To overcome this situation, this function will called
9991                  * several places and several times. Therefore, this is not an error case.
9992                  */
9993                 return;
9994         }
9995
9996         LOGD("[handle: %p] pipeline has completely constructed", player);
9997
9998         if ((player->ini.async_start) &&
9999                 (player->msg_posted == FALSE) &&
10000                 (player->cmd >= MMPLAYER_COMMAND_START))
10001                 __mmplayer_handle_missed_plugin(player);
10002
10003         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10004 }
10005
10006 static gboolean
10007 __mmplayer_verify_next_play_path(mm_player_t *player)
10008 {
10009         MMHandleType attrs = 0;
10010         MMPlayerParseProfile profile;
10011         gint uri_idx = 0, check_cnt = 0;
10012         char *uri = NULL;
10013         gint mode = MM_PLAYER_PD_MODE_NONE;
10014         gint video = 0;
10015         gint count = 0;
10016         gint gapless = 0;
10017         guint num_of_list = 0;
10018         static int profile_tv = -1;
10019
10020         MMPLAYER_FENTER();
10021
10022         LOGD("checking for gapless play");
10023
10024         if (player->pipeline->textbin) {
10025                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10026                 goto ERROR;
10027         }
10028
10029         attrs = MMPLAYER_GET_ATTRS(player);
10030         if (!attrs) {
10031                 LOGE("fail to get attributes.\n");
10032                 goto ERROR;
10033         }
10034
10035         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10036
10037         if (__builtin_expect(profile_tv == -1, 0)) {
10038                 char *profileName;
10039                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10040                 switch (*profileName) {
10041                 case 't':
10042                 case 'T':
10043                         profile_tv = 1;
10044                         break;
10045                 default:
10046                         profile_tv = 0;
10047                 }
10048                 free(profileName);
10049         }
10050         /* gapless playback is not supported in case of video at TV profile. */
10051         if (profile_tv && video) {
10052                 LOGW("not support video gapless playback");
10053                 goto ERROR;
10054         }
10055
10056         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10057                 if (mode == TRUE) {
10058                         LOGW("pd mode\n");
10059                         goto ERROR;
10060                 }
10061         }
10062
10063         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10064                 LOGE("can not get play count\n");
10065
10066         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10067                 LOGE("can not get gapless mode\n");
10068
10069         if (video && !gapless) {
10070                 LOGW("not enabled video gapless playback");
10071                 goto ERROR;
10072         }
10073
10074         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10075                 gapless = 1;
10076
10077         if (!gapless) {
10078                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10079                 goto ERROR;
10080         }
10081
10082         num_of_list = g_list_length(player->uri_info.uri_list);
10083
10084         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10085
10086         if (num_of_list == 0) {
10087                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10088                         LOGE("can not get profile_uri\n");
10089                         goto ERROR;
10090                 }
10091
10092                 if (!uri) {
10093                         LOGE("uri list is empty.\n");
10094                         goto ERROR;
10095                 }
10096
10097                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10098                 LOGD("add original path : %s ", uri);
10099
10100                 num_of_list = 1;
10101                 uri = NULL;
10102         }
10103
10104         uri_idx = player->uri_info.uri_idx;
10105
10106         while (TRUE) {
10107                 check_cnt++;
10108
10109                 if (check_cnt > num_of_list) {
10110                         LOGE("there is no valid uri.");
10111                         goto ERROR;
10112                 }
10113
10114                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10115
10116                 if (uri_idx < num_of_list-1) {
10117                         uri_idx++;
10118                 } else {
10119                         if ((count <= 1) && (count != -1)) {
10120                                 LOGD("no repeat.");
10121                                 goto ERROR;
10122                         } else if (count > 1) {
10123                                 /* decrease play count */
10124                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10125                                 count--;
10126
10127                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10128
10129                                 /* commit attribute */
10130                                 if (mmf_attrs_commit(attrs))
10131                                         LOGE("failed to commit attribute\n");
10132                         }
10133
10134                         /* count < 0 : repeat continually */
10135                         uri_idx = 0;
10136                 }
10137
10138                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10139                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10140
10141                 if (uri == NULL) {
10142                         LOGW("next uri does not exist\n");
10143                         continue;
10144                 }
10145
10146                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10147                         LOGE("failed to parse profile\n");
10148                         continue;
10149                 }
10150
10151                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10152                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10153                         LOGW("uri type is not supported(%d).", profile.uri_type);
10154                         continue;
10155                 }
10156
10157                 break;
10158         }
10159
10160         player->uri_info.uri_idx = uri_idx;
10161         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10162
10163         if (mmf_attrs_commit(player->attrs)) {
10164                 LOGE("failed to commit.\n");
10165                 goto ERROR;
10166         }
10167
10168         LOGD("next uri %s(%d)\n", uri, uri_idx);
10169
10170         return TRUE;
10171
10172 ERROR:
10173
10174         LOGE("unable to play next path. EOS will be posted soon.\n");
10175         return FALSE;
10176 }
10177
10178 static void
10179 __mmplayer_initialize_next_play(mm_player_t *player)
10180 {
10181         int i;
10182
10183         MMPLAYER_FENTER();
10184
10185         player->smooth_streaming = FALSE;
10186         player->videodec_linked = 0;
10187         player->audiodec_linked = 0;
10188         player->videosink_linked = 0;
10189         player->audiosink_linked = 0;
10190         player->textsink_linked = 0;
10191         player->is_external_subtitle_present = FALSE;
10192         player->is_external_subtitle_added_now = FALSE;
10193         player->not_supported_codec = MISSING_PLUGIN_NONE;
10194         player->can_support_codec = FOUND_PLUGIN_NONE;
10195         player->pending_seek.is_pending = FALSE;
10196         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10197         player->pending_seek.pos = 0;
10198         player->msg_posted = FALSE;
10199         player->has_many_types = FALSE;
10200         player->no_more_pad = FALSE;
10201         player->not_found_demuxer = 0;
10202         player->doing_seek = FALSE;
10203         player->max_audio_channels = 0;
10204         player->is_subtitle_force_drop = FALSE;
10205         player->play_subtitle = FALSE;
10206         player->adjust_subtitle_pos = 0;
10207
10208         player->total_bitrate = 0;
10209         player->total_maximum_bitrate = 0;
10210
10211         _mmplayer_track_initialize(player);
10212         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10213
10214         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10215                 player->bitrate[i] = 0;
10216                 player->maximum_bitrate[i] = 0;
10217         }
10218
10219         if (player->v_stream_caps) {
10220                 gst_caps_unref(player->v_stream_caps);
10221                 player->v_stream_caps = NULL;
10222         }
10223
10224         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10225
10226         /* clean found parsers */
10227         if (player->parsers) {
10228                 GList *parsers = player->parsers;
10229                 for (; parsers; parsers = g_list_next(parsers)) {
10230                         gchar *name = parsers->data;
10231                         MMPLAYER_FREEIF(name);
10232                 }
10233                 g_list_free(player->parsers);
10234                 player->parsers = NULL;
10235         }
10236
10237         /* clean found audio decoders */
10238         if (player->audio_decoders) {
10239                 GList *a_dec = player->audio_decoders;
10240                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10241                         gchar *name = a_dec->data;
10242                         MMPLAYER_FREEIF(name);
10243                 }
10244                 g_list_free(player->audio_decoders);
10245                 player->audio_decoders = NULL;
10246         }
10247
10248         MMPLAYER_FLEAVE();
10249 }
10250
10251 static void
10252 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10253 {
10254         MMPlayerGstElement *mainbin = NULL;
10255         MMMessageParamType msg_param = {0,};
10256         GstElement *element = NULL;
10257         MMHandleType attrs = 0;
10258         char *uri = NULL;
10259         enum MainElementID elemId = MMPLAYER_M_NUM;
10260
10261         MMPLAYER_FENTER();
10262
10263         if ((player == NULL) ||
10264                 (player->pipeline == NULL) ||
10265                 (player->pipeline->mainbin == NULL)) {
10266                 LOGE("player is null.\n");
10267                 goto ERROR;
10268         }
10269
10270         mainbin = player->pipeline->mainbin;
10271         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10272
10273         attrs = MMPLAYER_GET_ATTRS(player);
10274         if (!attrs) {
10275                 LOGE("fail to get attributes.\n");
10276                 goto ERROR;
10277         }
10278
10279         /* Initialize Player values */
10280         __mmplayer_initialize_next_play(player);
10281
10282         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10283
10284         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10285                 LOGE("failed to parse profile\n");
10286                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10287                 goto ERROR;
10288         }
10289
10290         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10291                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10292                 LOGE("it's dash or hls. not support.");
10293                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10294                 goto ERROR;
10295         }
10296
10297         /* setup source */
10298         switch (player->profile.uri_type) {
10299         /* file source */
10300         case MM_PLAYER_URI_TYPE_FILE:
10301         {
10302                 LOGD("using filesrc for 'file://' handler.\n");
10303                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10304                         LOGE("failed to get storage info");
10305                         break;
10306                 }
10307
10308                 element = gst_element_factory_make("filesrc", "source");
10309
10310                 if (!element) {
10311                         LOGE("failed to create filesrc\n");
10312                         break;
10313                 }
10314
10315                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10316                 break;
10317         }
10318         case MM_PLAYER_URI_TYPE_URL_HTTP:
10319         {
10320                 gchar *user_agent, *cookies, **cookie_list;
10321                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10322                 user_agent = cookies = NULL;
10323                 cookie_list = NULL;
10324
10325                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10326                 if (!element) {
10327                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10328                         break;
10329                 }
10330                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10331
10332                 /* get attribute */
10333                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10334                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10335
10336                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10337                         LOGD("get timeout from ini\n");
10338                         http_timeout = player->ini.http_timeout;
10339                 }
10340
10341                 /* get attribute */
10342                 SECURE_LOGD("location : %s\n", player->profile.uri);
10343                 SECURE_LOGD("cookies : %s\n", cookies);
10344                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10345                 LOGD("timeout : %d\n", http_timeout);
10346
10347                 /* setting property to streaming source */
10348                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10349                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10350                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10351
10352                 /* parsing cookies */
10353                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10354                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10355                 if (user_agent)
10356                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10357                 break;
10358         }
10359         default:
10360                 LOGE("not support uri type %d\n", player->profile.uri_type);
10361                 break;
10362         }
10363
10364         if (!element) {
10365                 LOGE("no source element was created.\n");
10366                 goto ERROR;
10367         }
10368
10369         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10370                 LOGE("failed to add source element to pipeline\n");
10371                 gst_object_unref(GST_OBJECT(element));
10372                 element = NULL;
10373                 goto ERROR;
10374         }
10375
10376         /* take source element */
10377         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10378         mainbin[MMPLAYER_M_SRC].gst = element;
10379
10380         element = NULL;
10381
10382         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10383                 if (player->streamer == NULL) {
10384                         player->streamer = __mm_player_streaming_create();
10385                         __mm_player_streaming_initialize(player->streamer);
10386                 }
10387
10388                 elemId = MMPLAYER_M_TYPEFIND;
10389                 element = gst_element_factory_make("typefind", "typefinder");
10390                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10391                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10392         } else {
10393                 elemId = MMPLAYER_M_AUTOPLUG;
10394                 element = __mmplayer_create_decodebin(player);
10395         }
10396
10397         /* check autoplug element is OK */
10398         if (!element) {
10399                 LOGE("can not create element(%d)\n", elemId);
10400                 goto ERROR;
10401         }
10402
10403         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10404                 LOGE("failed to add sinkbin to pipeline\n");
10405                 gst_object_unref(GST_OBJECT(element));
10406                 element = NULL;
10407                 goto ERROR;
10408         }
10409
10410         mainbin[elemId].id = elemId;
10411         mainbin[elemId].gst = element;
10412
10413         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10414                 LOGE("Failed to link src - autoplug(or typefind)\n");
10415                 goto ERROR;
10416         }
10417
10418         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10419                 LOGE("Failed to change state of src element\n");
10420                 goto ERROR;
10421         }
10422
10423         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10424                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10425                         LOGE("Failed to change state of decodebin\n");
10426                         goto ERROR;
10427                 }
10428         } else {
10429                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10430                         LOGE("Failed to change state of src element\n");
10431                         goto ERROR;
10432                 }
10433         }
10434
10435         player->gapless.stream_changed = TRUE;
10436         player->gapless.running = TRUE;
10437         MMPLAYER_FLEAVE();
10438         return;
10439
10440 ERROR:
10441         if (player) {
10442                 MMPLAYER_PLAYBACK_UNLOCK(player);
10443
10444                 if (!player->msg_posted) {
10445                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10446                         player->msg_posted = TRUE;
10447                 }
10448         }
10449         return;
10450 }
10451
10452 static gboolean
10453 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10454 {
10455         mm_player_selector_t *selector = &player->selector[type];
10456         MMPlayerGstElement *sinkbin = NULL;
10457         enum MainElementID selectorId = MMPLAYER_M_NUM;
10458         enum MainElementID sinkId = MMPLAYER_M_NUM;
10459         GstPad *srcpad = NULL;
10460         GstPad *sinkpad = NULL;
10461         gboolean send_notice = FALSE;
10462
10463         MMPLAYER_FENTER();
10464         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10465
10466         LOGD("type %d", type);
10467
10468         switch (type) {
10469         case MM_PLAYER_TRACK_TYPE_AUDIO:
10470                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10471                 sinkId = MMPLAYER_A_BIN;
10472                 sinkbin = player->pipeline->audiobin;
10473                 break;
10474         case MM_PLAYER_TRACK_TYPE_VIDEO:
10475                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10476                 sinkId = MMPLAYER_V_BIN;
10477                 sinkbin = player->pipeline->videobin;
10478                 send_notice = TRUE;
10479                 break;
10480         case MM_PLAYER_TRACK_TYPE_TEXT:
10481                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10482                 sinkId = MMPLAYER_T_BIN;
10483                 sinkbin = player->pipeline->textbin;
10484                 break;
10485         default:
10486                 LOGE("requested type is not supportable");
10487                 return FALSE;
10488                 break;
10489         }
10490
10491         if (player->pipeline->mainbin[selectorId].gst) {
10492                 gint n;
10493
10494                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10495
10496                 if (selector->event_probe_id != 0)
10497                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10498                 selector->event_probe_id = 0;
10499
10500                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10501                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10502
10503                         if (srcpad && sinkpad) {
10504                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10505                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10506                                 gst_pad_unlink(srcpad, sinkpad);
10507
10508                                 /* send custom event to sink pad to handle it at video sink */
10509                                 if (send_notice) {
10510                                         LOGD("send custom event to sinkpad");
10511                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10512                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10513                                         gst_pad_send_event(sinkpad, event);
10514                                 }
10515                         }
10516
10517                         gst_object_unref(sinkpad);
10518                         sinkpad = NULL;
10519                 }
10520                 gst_object_unref(srcpad);
10521                 srcpad = NULL;
10522
10523                 LOGD("selector release");
10524
10525                 /* release and unref requests pad from the selector */
10526                 for (n = 0; n < selector->channels->len; n++) {
10527                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10528                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10529                 }
10530                 g_ptr_array_set_size(selector->channels, 0);
10531
10532                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10533                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10534
10535                 player->pipeline->mainbin[selectorId].gst = NULL;
10536                 selector = NULL;
10537         }
10538
10539         return TRUE;
10540 }
10541
10542 static void
10543 __mmplayer_deactivate_old_path(mm_player_t *player)
10544 {
10545         MMPLAYER_FENTER();
10546         MMPLAYER_RETURN_IF_FAIL(player);
10547
10548         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10549                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10550                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10551                 LOGE("deactivate selector error");
10552                 goto ERROR;
10553         }
10554
10555         _mmplayer_track_destroy(player);
10556         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10557
10558         if (player->streamer) {
10559                 __mm_player_streaming_deinitialize(player->streamer);
10560                 __mm_player_streaming_destroy(player->streamer);
10561                 player->streamer = NULL;
10562         }
10563
10564         MMPLAYER_PLAYBACK_LOCK(player);
10565         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10566
10567         MMPLAYER_FLEAVE();
10568         return;
10569
10570 ERROR:
10571
10572         if (!player->msg_posted) {
10573                 MMMessageParamType msg = {0,};
10574
10575                 /*post error*/
10576                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10577                 LOGE("next_uri_play> deactivate error");
10578
10579                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10580                 player->msg_posted = TRUE;
10581         }
10582         return;
10583 }
10584
10585 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10586 {
10587         int result = MM_ERROR_NONE;
10588         mm_player_t* player = (mm_player_t*) hplayer;
10589         MMPLAYER_FENTER();
10590
10591         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10592
10593         if (file_path) {
10594                 player->http_file_buffering_path = (gchar*)file_path;
10595                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10596         }
10597         MMPLAYER_FLEAVE();
10598         return result;
10599 }
10600
10601 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10602 {
10603         int result = MM_ERROR_NONE;
10604         mm_player_t* player = (mm_player_t*) hplayer;
10605         MMPLAYER_FENTER();
10606
10607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10608
10609         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10610         if (mmf_attrs_commit(player->attrs)) {
10611                 LOGE("failed to commit the original uri.\n");
10612                 result = MM_ERROR_PLAYER_INTERNAL;
10613         } else {
10614                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10615                         LOGE("failed to add the original uri in the uri list.\n");
10616         }
10617
10618         MMPLAYER_FLEAVE();
10619         return result;
10620 }
10621
10622 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10623 {
10624         mm_player_t* player = (mm_player_t*) hplayer;
10625         guint num_of_list = 0;
10626
10627         MMPLAYER_FENTER();
10628
10629         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10630         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10631
10632         if (player->pipeline && player->pipeline->textbin) {
10633                 LOGE("subtitle path is enabled.\n");
10634                 return MM_ERROR_PLAYER_INVALID_STATE;
10635         }
10636
10637         num_of_list = g_list_length(player->uri_info.uri_list);
10638
10639         if (is_first_path == TRUE) {
10640                 if (num_of_list == 0) {
10641                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10642                         LOGD("add original path : %s", uri);
10643                 } else {
10644                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10645                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10646
10647                         LOGD("change original path : %s", uri);
10648                 }
10649         } else {
10650                 MMHandleType attrs = 0;
10651                 attrs = MMPLAYER_GET_ATTRS(player);
10652
10653                 if (num_of_list == 0) {
10654                         char *original_uri = NULL;
10655
10656                         if (attrs) {
10657                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10658
10659                                 if (!original_uri) {
10660                                         LOGE("there is no original uri.");
10661                                         return MM_ERROR_PLAYER_INVALID_STATE;
10662                                 }
10663
10664                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10665                                 player->uri_info.uri_idx = 0;
10666
10667                                 LOGD("add original path at first : %s(%d)", original_uri);
10668                         }
10669                 }
10670
10671                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10672                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10673         }
10674
10675         MMPLAYER_FLEAVE();
10676         return MM_ERROR_NONE;
10677 }
10678
10679 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10680 {
10681         mm_player_t* player = (mm_player_t*) hplayer;
10682         char *next_uri = NULL;
10683         guint num_of_list = 0;
10684
10685         MMPLAYER_FENTER();
10686         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10687
10688         num_of_list = g_list_length(player->uri_info.uri_list);
10689
10690         if (num_of_list > 0) {
10691                 gint uri_idx = player->uri_info.uri_idx;
10692
10693                 if (uri_idx < num_of_list-1)
10694                         uri_idx++;
10695                 else
10696                         uri_idx = 0;
10697
10698                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10699                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10700
10701                 *uri = g_strdup(next_uri);
10702         }
10703
10704         MMPLAYER_FLEAVE();
10705         return MM_ERROR_NONE;
10706 }
10707
10708 static void
10709 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10710 GstCaps *caps, gpointer data)
10711 {
10712         mm_player_t* player = (mm_player_t*)data;
10713         const gchar* klass = NULL;
10714         const gchar* mime = NULL;
10715         gchar* caps_str = NULL;
10716
10717         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10718         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10719         caps_str = gst_caps_to_string(caps);
10720
10721         LOGW("unknown type of caps : %s from %s",
10722                                         caps_str, GST_ELEMENT_NAME(elem));
10723
10724         MMPLAYER_FREEIF(caps_str);
10725
10726         /* There is no available codec. */
10727         __mmplayer_check_not_supported_codec(player, klass, mime);
10728 }
10729
10730 static gboolean
10731 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10732 GstCaps * caps,  gpointer data)
10733 {
10734         mm_player_t* player = (mm_player_t*)data;
10735         const char* mime = NULL;
10736         gboolean ret = TRUE;
10737
10738         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10739         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10740
10741         if (g_str_has_prefix(mime, "audio")) {
10742                 GstStructure* caps_structure = NULL;
10743                 gint samplerate = 0;
10744                 gint channels = 0;
10745                 gchar *caps_str = NULL;
10746
10747                 caps_structure = gst_caps_get_structure(caps, 0);
10748                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10749                 gst_structure_get_int(caps_structure, "channels", &channels);
10750
10751                 if ((channels > 0 && samplerate == 0)) {
10752                         LOGD("exclude audio...");
10753                         ret = FALSE;
10754                 }
10755
10756                 caps_str = gst_caps_to_string(caps);
10757                 /* set it directly because not sent by TAG */
10758                 if (g_strrstr(caps_str, "mobile-xmf"))
10759                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10760                 MMPLAYER_FREEIF(caps_str);
10761         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10762                 MMMessageParamType msg_param;
10763                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10764                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10765                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10766                 LOGD("video file is not supported on this device");
10767                 ret = FALSE;
10768         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10769                 LOGD("already video linked");
10770                 ret = FALSE;
10771         } else {
10772                 LOGD("found new stream");
10773         }
10774
10775         return ret;
10776 }
10777
10778 static int
10779 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10780 {
10781         int ret = MM_ERROR_NONE;
10782         int idx = 0;
10783         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10784
10785         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10786                 GstStructure* str = NULL;
10787                 gint channels = 0;
10788                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10789
10790                 LOGD("audio codec type: %d", codec_type);
10791                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10792                         /* sw codec will be skipped */
10793                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10794                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10795                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10796                                         ret = MM_ERROR_PLAYER_INTERNAL;
10797                                         goto DONE;
10798                                 }
10799                         }
10800                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10801                         /* hw codec will be skipped */
10802                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10803                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10804                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10805                                 ret = MM_ERROR_PLAYER_INTERNAL;
10806                                 goto DONE;
10807                         }
10808                 }
10809
10810                 str = gst_caps_get_structure(caps, 0);
10811                 if (str) {
10812                         gst_structure_get_int(str, "channels", &channels);
10813
10814                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10815                         if (player->max_audio_channels < channels)
10816                                 player->max_audio_channels = channels;
10817                 }
10818                 /* set stream information */
10819                 if (!player->audiodec_linked)
10820                         __mmplayer_set_audio_attrs(player, caps);
10821
10822                 /* update codec info */
10823                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10824                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10825                 player->audiodec_linked = 1;
10826
10827         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10828
10829                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10830
10831                 LOGD("video codec type: %d", codec_type);
10832                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10833                         /* sw codec is skipped */
10834                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10835                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10836                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10837                                         ret = MM_ERROR_PLAYER_INTERNAL;
10838                                         goto DONE;
10839                                 }
10840                         }
10841                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10842                         /* hw codec is skipped */
10843                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10844                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10845                                 ret = MM_ERROR_PLAYER_INTERNAL;
10846                                 goto DONE;
10847                         }
10848                 }
10849
10850                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10851                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10852
10853                         /* mark video decoder for acquire */
10854                         if (player->video_decoder_resource == NULL) {
10855                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10856                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10857                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10858                                                 &player->video_decoder_resource)
10859                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10860                                         LOGE("could not mark video_decoder resource for acquire");
10861                                         ret = MM_ERROR_PLAYER_INTERNAL;
10862                                         goto DONE;
10863                                 }
10864                         } else {
10865                                 LOGW("video decoder resource is already acquired, skip it.");
10866                                 ret = MM_ERROR_PLAYER_INTERNAL;
10867                                 goto DONE;
10868                         }
10869
10870                         player->interrupted_by_resource = FALSE;
10871                         /* acquire resources for video playing */
10872                         if (mm_resource_manager_commit(player->resource_manager)
10873                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10874                                 LOGE("could not acquire resources for video decoding\n");
10875                                 ret = MM_ERROR_PLAYER_INTERNAL;
10876                                 goto DONE;
10877                         }
10878                 }
10879
10880                 /* update codec info */
10881                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10882                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10883                 player->videodec_linked = 1;
10884         }
10885
10886 DONE:
10887         return ret;
10888 }
10889
10890 static gint
10891 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10892 GstCaps* caps, GstElementFactory* factory, gpointer data)
10893 {
10894         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10895          We are defining our own and will be removed when it actually exposed */
10896         typedef enum {
10897                 GST_AUTOPLUG_SELECT_TRY,
10898                 GST_AUTOPLUG_SELECT_EXPOSE,
10899                 GST_AUTOPLUG_SELECT_SKIP
10900         } GstAutoplugSelectResult;
10901
10902         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10903         mm_player_t* player = (mm_player_t*)data;
10904
10905         gchar* factory_name = NULL;
10906         gchar* caps_str = NULL;
10907         const gchar* klass = NULL;
10908         gint idx = 0;
10909
10910         factory_name = GST_OBJECT_NAME(factory);
10911         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10912         caps_str = gst_caps_to_string(caps);
10913
10914         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10915
10916         /* store type string */
10917         if (player->type == NULL) {
10918                 player->type = gst_caps_to_string(caps);
10919                 __mmplayer_update_content_type_info(player);
10920         }
10921
10922         /* filtering exclude keyword */
10923         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10924                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10925                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10926                                         factory_name, player->ini.exclude_element_keyword[idx]);
10927
10928                         result = GST_AUTOPLUG_SELECT_SKIP;
10929                         goto DONE;
10930                 }
10931         }
10932
10933         /* exclude webm format */
10934         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10935          * because webm format is not supportable.
10936          * If webm is disabled in "autoplug-continue", there is no state change
10937          * failure or error because the decodebin will expose the pad directly.
10938          * It make MSL invoke _prepare_async_callback.
10939          * So, we need to disable webm format in "autoplug-select" */
10940         if (caps_str && strstr(caps_str, "webm")) {
10941                 LOGW("webm is not supported");
10942                 result = GST_AUTOPLUG_SELECT_SKIP;
10943                 goto DONE;
10944         }
10945
10946         /* check factory class for filtering */
10947         /* NOTE : msl don't need to use image plugins.
10948          * So, those plugins should be skipped for error handling.
10949          */
10950         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10951                 LOGD("skipping [%s] by not required\n", factory_name);
10952                 result = GST_AUTOPLUG_SELECT_SKIP;
10953                 goto DONE;
10954         }
10955
10956         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10957                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10958                 // TO CHECK : subtitle if needed, add subparse exception.
10959                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10960                 result = GST_AUTOPLUG_SELECT_SKIP;
10961                 goto DONE;
10962         }
10963
10964         if (g_strrstr(factory_name, "mpegpsdemux")) {
10965                 LOGD("skipping PS container - not support\n");
10966                 result = GST_AUTOPLUG_SELECT_SKIP;
10967                 goto DONE;
10968         }
10969
10970         if (g_strrstr(factory_name, "mssdemux"))
10971                 player->smooth_streaming = TRUE;
10972
10973         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10974                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10975                 gint stype = 0;
10976                 gint width = 0;
10977                 GstStructure *str = NULL;
10978                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10979
10980                 /* don't make video because of not required */
10981                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10982                         (player->set_mode.media_packet_video_stream == FALSE)) {
10983                         LOGD("no video because it's not required. -> return expose");
10984                         result = GST_AUTOPLUG_SELECT_EXPOSE;
10985                         goto DONE;
10986                 }
10987
10988                 /* get w/h for omx state-tune */
10989                 /* FIXME: deprecated? */
10990                 str = gst_caps_get_structure(caps, 0);
10991                 gst_structure_get_int(str, "width", &width);
10992
10993                 if (width != 0) {
10994                         if (player->v_stream_caps) {
10995                                 gst_caps_unref(player->v_stream_caps);
10996                                 player->v_stream_caps = NULL;
10997                         }
10998
10999                         player->v_stream_caps = gst_caps_copy(caps);
11000                         LOGD("take caps for video state tune");
11001                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11002                 }
11003         }
11004
11005         if (g_strrstr(klass, "Codec/Decoder")) {
11006                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11007                         LOGD("skipping %s codec", factory_name);
11008                         result = GST_AUTOPLUG_SELECT_SKIP;
11009                         goto DONE;
11010                 }
11011         }
11012
11013 DONE:
11014         MMPLAYER_FREEIF(caps_str);
11015
11016         return result;
11017 }
11018
11019 static void
11020 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11021 gpointer data)
11022 {
11023         //mm_player_t* player = (mm_player_t*)data;
11024         GstCaps* caps = NULL;
11025
11026         LOGD("[Decodebin2] pad-removed signal\n");
11027
11028         caps = gst_pad_query_caps(new_pad, NULL);
11029         if (caps) {
11030                 gchar* caps_str = NULL;
11031                 caps_str = gst_caps_to_string(caps);
11032
11033                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11034
11035                 MMPLAYER_FREEIF(caps_str);
11036                 gst_caps_unref(caps);
11037         }
11038 }
11039
11040 static void
11041 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11042 {
11043         mm_player_t* player = (mm_player_t*)data;
11044         GstIterator *iter = NULL;
11045         GValue item = { 0, };
11046         GstPad *pad = NULL;
11047         gboolean done = FALSE;
11048         gboolean is_all_drained = TRUE;
11049
11050         MMPLAYER_FENTER();
11051         MMPLAYER_RETURN_IF_FAIL(player);
11052
11053         LOGD("__mmplayer_gst_decode_drained");
11054
11055         if (player->use_deinterleave == TRUE) {
11056                 LOGD("group playing mode.");
11057                 return;
11058         }
11059
11060         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11061                 LOGW("Fail to get cmd lock");
11062                 return;
11063         }
11064
11065         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11066                 !__mmplayer_verify_next_play_path(player)) {
11067                 LOGD("decoding is finished.");
11068                 __mmplayer_reset_gapless_state(player);
11069                 MMPLAYER_CMD_UNLOCK(player);
11070                 return;
11071         }
11072
11073         player->gapless.reconfigure = TRUE;
11074
11075         /* check decodebin src pads whether they received EOS or not */
11076         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11077
11078         while (!done) {
11079                 switch (gst_iterator_next(iter, &item)) {
11080                 case GST_ITERATOR_OK:
11081                         pad = g_value_get_object(&item);
11082                         if (pad && !GST_PAD_IS_EOS(pad)) {
11083                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11084                                 is_all_drained = FALSE;
11085                                 break;
11086                         }
11087                         g_value_reset(&item);
11088                         break;
11089                 case GST_ITERATOR_RESYNC:
11090                         gst_iterator_resync(iter);
11091                         break;
11092                 case GST_ITERATOR_ERROR:
11093                 case GST_ITERATOR_DONE:
11094                         done = TRUE;
11095                         break;
11096                 }
11097         }
11098         g_value_unset(&item);
11099         gst_iterator_free(iter);
11100
11101         if (!is_all_drained) {
11102                 LOGD("Wait util the all pads get EOS.");
11103                 MMPLAYER_CMD_UNLOCK(player);
11104                 MMPLAYER_FLEAVE();
11105                 return;
11106         }
11107
11108         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11109         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11110
11111         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11112         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11113         __mmplayer_deactivate_old_path(player);
11114         MMPLAYER_CMD_UNLOCK(player);
11115
11116         MMPLAYER_FLEAVE();
11117 }
11118
11119 static void
11120 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11121 {
11122         mm_player_t* player = (mm_player_t*)data;
11123         const gchar* klass = NULL;
11124         gchar* factory_name = NULL;
11125
11126         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11127         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11128
11129         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11130
11131         if (__mmplayer_add_dump_buffer_probe(player, element))
11132                 LOGD("add buffer probe");
11133
11134         //<-
11135         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11136                 gchar* selected = NULL;
11137                 selected = g_strdup(GST_ELEMENT_NAME(element));
11138                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11139         }
11140         //-> temp code
11141
11142         if (g_strrstr(klass, "Parser")) {
11143                 gchar* selected = NULL;
11144
11145                 selected = g_strdup(factory_name);
11146                 player->parsers = g_list_append(player->parsers, selected);
11147         }
11148
11149         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11150                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11151                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11152
11153                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11154                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11155
11156                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11157                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11158                                                 "max-video-width", player->adaptive_info.limit.width,
11159                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11160
11161         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11162                 /* FIXIT : first value will be overwritten if there's more
11163                  * than 1 demuxer/parser
11164                  */
11165
11166                 //LOGD("plugged element is demuxer. take it\n");
11167                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11168                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11169
11170                 /*Added for multi audio support */ // Q. del?
11171                 if (g_strrstr(klass, "Demux")) {
11172                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11173                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11174                 }
11175         }
11176
11177         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11178                 int surface_type = 0;
11179
11180                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11181         }
11182
11183         // to support trust-zone only
11184         if (g_strrstr(factory_name, "asfdemux")) {
11185                 LOGD("set file-location %s\n", player->profile.uri);
11186                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11187
11188                 if (player->video_hub_download_mode == TRUE)
11189                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11190         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11191                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11192                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11193         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11194                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11195                         (__mmplayer_is_only_mp3_type(player->type))) {
11196                         LOGD("[mpegaudioparse] set streaming pull mode.");
11197                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11198                 }
11199         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11200                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11201         }
11202
11203         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11204                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11205                 LOGD("plugged element is multiqueue. take it\n");
11206
11207                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11208                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11209
11210                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11211                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11212                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11213                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11214                         __mm_player_streaming_set_multiqueue(player->streamer,
11215                                 element,
11216                                 TRUE,
11217                                 player->ini.http_buffering_time,
11218                                 1.0,
11219                                 player->ini.http_buffering_limit);
11220
11221                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11222                 }
11223         }
11224
11225         return;
11226 }
11227
11228 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11229 {
11230         MMPLAYER_FENTER();
11231         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11232
11233         if (MMPLAYER_IS_STREAMING(player))
11234                 return FALSE;
11235
11236         /* This callback can be set to music player only. */
11237         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11238                 LOGW("audio callback is not supported for video");
11239                 return FALSE;
11240         }
11241
11242         if (player->audio_stream_cb) {
11243                 GstPad *pad = NULL;
11244
11245                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11246
11247                 if (!pad) {
11248                         LOGE("failed to get sink pad from audiosink to probe data\n");
11249                         return FALSE;
11250                 }
11251                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11252                         __mmplayer_audio_stream_probe, player, NULL);
11253
11254                 gst_object_unref(pad);
11255
11256                 pad = NULL;
11257         } else {
11258                 LOGE("There is no audio callback to configure.\n");
11259                 return FALSE;
11260         }
11261
11262         MMPLAYER_FLEAVE();
11263
11264         return TRUE;
11265 }
11266
11267 static void
11268 __mmplayer_release_misc(mm_player_t* player)
11269 {
11270         int i;
11271         bool cur_mode = player->set_mode.rich_audio;
11272         MMPLAYER_FENTER();
11273
11274         MMPLAYER_RETURN_IF_FAIL(player);
11275
11276         player->video_stream_cb = NULL;
11277         player->video_stream_cb_user_param = NULL;
11278         player->video_stream_prerolled = FALSE;
11279
11280         player->audio_stream_cb = NULL;
11281         player->audio_stream_render_cb_ex = NULL;
11282         player->audio_stream_cb_user_param = NULL;
11283         player->audio_stream_sink_sync = false;
11284
11285         player->video_stream_changed_cb = NULL;
11286         player->video_stream_changed_cb_user_param = NULL;
11287
11288         player->audio_stream_changed_cb = NULL;
11289         player->audio_stream_changed_cb_user_param = NULL;
11290
11291         player->sent_bos = FALSE;
11292         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11293
11294         player->doing_seek = FALSE;
11295
11296         player->total_bitrate = 0;
11297         player->total_maximum_bitrate = 0;
11298
11299         player->not_found_demuxer = 0;
11300
11301         player->last_position = 0;
11302         player->duration = 0;
11303         player->http_content_size = 0;
11304         player->not_supported_codec = MISSING_PLUGIN_NONE;
11305         player->can_support_codec = FOUND_PLUGIN_NONE;
11306         player->pending_seek.is_pending = FALSE;
11307         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11308         player->pending_seek.pos = 0;
11309         player->msg_posted = FALSE;
11310         player->has_many_types = FALSE;
11311         player->max_audio_channels = 0;
11312         player->video_share_api_delta = 0;
11313         player->video_share_clock_delta = 0;
11314         player->is_subtitle_force_drop = FALSE;
11315         player->play_subtitle = FALSE;
11316         player->adjust_subtitle_pos = 0;
11317         player->last_multiwin_status = FALSE;
11318         player->has_closed_caption = FALSE;
11319         player->set_mode.media_packet_video_stream = FALSE;
11320         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11321         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11322         /* recover mode */
11323         player->set_mode.rich_audio = cur_mode;
11324
11325         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11326                 player->bitrate[i] = 0;
11327                 player->maximum_bitrate[i] = 0;
11328         }
11329
11330         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11331
11332         /* remove media stream cb(appsrc cb) */
11333         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11334                 player->media_stream_buffer_status_cb[i] = NULL;
11335                 player->media_stream_seek_data_cb[i] = NULL;
11336                 player->buffer_cb_user_param[i] = NULL;
11337                 player->seek_cb_user_param[i] = NULL;
11338         }
11339         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11340
11341         /* free memory related to audio effect */
11342         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11343
11344         if (player->adaptive_info.var_list) {
11345                 g_list_free_full(player->adaptive_info.var_list, g_free);
11346                 player->adaptive_info.var_list = NULL;
11347         }
11348
11349         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11350         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11351         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11352
11353         /* Reset video360 settings to their defaults in case if the pipeline is to be
11354          * re-created.
11355          * */
11356         player->video360_metadata.is_spherical = -1;
11357         player->is_openal_plugin_used = FALSE;
11358
11359         player->is_content_spherical = FALSE;
11360         player->is_video360_enabled = TRUE;
11361         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11362         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11363         player->video360_yaw_radians = 4;
11364         player->video360_pitch_radians = 4;
11365         player->video360_zoom = 1.0f;
11366         player->video360_horizontal_fov = 0;
11367         player->video360_vertical_fov = 0;
11368
11369         player->sound.rg_enable = false;
11370
11371         MMPLAYER_FLEAVE();
11372 }
11373
11374 static void
11375 __mmplayer_release_misc_post(mm_player_t* player)
11376 {
11377         char *original_uri = NULL;
11378         MMPLAYER_FENTER();
11379
11380         /* player->pipeline is already released before. */
11381
11382         MMPLAYER_RETURN_IF_FAIL(player);
11383
11384         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11385
11386         /* clean found parsers */
11387         if (player->parsers) {
11388                 GList *parsers = player->parsers;
11389                 for (; parsers; parsers = g_list_next(parsers)) {
11390                         gchar *name = parsers->data;
11391                         MMPLAYER_FREEIF(name);
11392                 }
11393                 g_list_free(player->parsers);
11394                 player->parsers = NULL;
11395         }
11396
11397         /* clean found audio decoders */
11398         if (player->audio_decoders) {
11399                 GList *a_dec = player->audio_decoders;
11400                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11401                         gchar *name = a_dec->data;
11402                         MMPLAYER_FREEIF(name);
11403                 }
11404                 g_list_free(player->audio_decoders);
11405                 player->audio_decoders = NULL;
11406         }
11407
11408         /* clean the uri list except original uri */
11409         if (player->uri_info.uri_list) {
11410                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11411
11412                 if (player->attrs) {
11413                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11414                         LOGD("restore original uri = %s\n", original_uri);
11415
11416                         if (mmf_attrs_commit(player->attrs))
11417                                 LOGE("failed to commit the original uri.\n");
11418                 }
11419
11420                 GList *uri_list = player->uri_info.uri_list;
11421                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11422                         gchar *uri = uri_list->data;
11423                         MMPLAYER_FREEIF(uri);
11424                 }
11425                 g_list_free(player->uri_info.uri_list);
11426                 player->uri_info.uri_list = NULL;
11427         }
11428
11429         /* clear the audio stream buffer list */
11430         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11431
11432         /* clear the video stream bo list */
11433         __mmplayer_video_stream_destroy_bo_list(player);
11434         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11435
11436         if (player->profile.input_mem.buf) {
11437                 free(player->profile.input_mem.buf);
11438                 player->profile.input_mem.buf = NULL;
11439         }
11440         player->profile.input_mem.len = 0;
11441         player->profile.input_mem.offset = 0;
11442
11443         player->uri_info.uri_idx = 0;
11444         MMPLAYER_FLEAVE();
11445 }
11446
11447 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11448 {
11449         GstElement *element = NULL;
11450         GstPad *sinkpad;
11451
11452         LOGD("creating %s to plug\n", name);
11453
11454         element = gst_element_factory_make(name, NULL);
11455         if (!element) {
11456                 LOGE("failed to create queue\n");
11457                 return NULL;
11458         }
11459
11460         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11461                 LOGE("failed to set state READY to %s\n", name);
11462                 gst_object_unref(element);
11463                 return NULL;
11464         }
11465
11466         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11467                 LOGE("failed to add %s\n", name);
11468                 gst_object_unref(element);
11469                 return NULL;
11470         }
11471
11472         sinkpad = gst_element_get_static_pad(element, "sink");
11473
11474         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11475                 LOGE("failed to link %s\n", name);
11476                 gst_object_unref(sinkpad);
11477                 gst_object_unref(element);
11478                 return NULL;
11479         }
11480
11481         LOGD("linked %s to pipeline successfully\n", name);
11482
11483         gst_object_unref(sinkpad);
11484
11485         return element;
11486 }
11487
11488 gboolean
11489 __mmplayer_check_subtitle(mm_player_t* player)
11490 {
11491         MMHandleType attrs = 0;
11492         char *subtitle_uri = NULL;
11493
11494         MMPLAYER_FENTER();
11495
11496         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11497
11498         /* get subtitle attribute */
11499         attrs = MMPLAYER_GET_ATTRS(player);
11500         if (!attrs)
11501                 return FALSE;
11502
11503         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11504         if (!subtitle_uri || !strlen(subtitle_uri))
11505                 return FALSE;
11506
11507         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11508         player->is_external_subtitle_present = TRUE;
11509
11510         MMPLAYER_FLEAVE();
11511
11512         return TRUE;
11513 }
11514
11515 static gboolean
11516 __mmplayer_can_extract_pcm(mm_player_t* player)
11517 {
11518         MMHandleType attrs = 0;
11519         gboolean sound_extraction = FALSE;
11520
11521         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11522
11523         attrs = MMPLAYER_GET_ATTRS(player);
11524         if (!attrs) {
11525                 LOGE("fail to get attributes.");
11526                 return FALSE;
11527         }
11528
11529         /* get sound_extraction property */
11530         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11531
11532         if (!sound_extraction) {
11533                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11534                 return FALSE;
11535         }
11536
11537         return TRUE;
11538 }
11539
11540 static gboolean
11541 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11542 {
11543         LOGD("\n");
11544         MMMessageParamType msg_param;
11545         gchar *msg_src_element = NULL;
11546         GstStructure *s = NULL;
11547         guint error_id = 0;
11548         gchar *error_string = NULL;
11549
11550         MMPLAYER_FENTER();
11551
11552         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11553         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11554
11555         s = gst_structure_copy(gst_message_get_structure(message));
11556
11557
11558         if (!gst_structure_get_uint(s, "error_id", &error_id))
11559                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11560
11561         switch (error_id) {
11562         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11563                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11564                 break;
11565         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11566                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11567                 break;
11568         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11569                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11570                 break;
11571         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11572                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11573                 break;
11574         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11575                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11576                 break;
11577         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11578                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11579                 break;
11580         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11581                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11582                 break;
11583         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11584                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11585                 break;
11586         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11587                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11588                 break;
11589         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11590                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11591                 break;
11592         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11593                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11594                 break;
11595         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11596                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11597                 break;
11598         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11599                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11600                 break;
11601         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11602                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11603                 break;
11604         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11605                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11606                 break;
11607         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11608                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11609                 break;
11610         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11611                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11612                 break;
11613         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11614                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11615                 break;
11616         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11617                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11618                 break;
11619         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11620                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11621                 break;
11622         case MMPLAYER_STREAMING_ERROR_GONE:
11623                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11624                 break;
11625         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11626                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11627                 break;
11628         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11629                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11630                 break;
11631         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11632                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11633                 break;
11634         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11635                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11636                 break;
11637         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11638                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11639                 break;
11640         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11641                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11642                 break;
11643         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11644                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11645                 break;
11646         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11647                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11648                 break;
11649         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11650                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11651                 break;
11652         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11653                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11654                 break;
11655         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11656                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11657                 break;
11658         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11659                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11660                 break;
11661         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11662                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11663                 break;
11664         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11665                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11666                 break;
11667         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11668                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11669                 break;
11670         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11671                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11672                 break;
11673         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11674                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11675                 break;
11676         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11677                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11678                 break;
11679         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11680                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11681                 break;
11682         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11683                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11684                 break;
11685         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11686                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11687                 break;
11688         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11689                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11690                 break;
11691         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11692                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11693                 break;
11694         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11695                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11696                 break;
11697         default:
11698                 {
11699                         gst_structure_free(s);
11700                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11701                 }
11702         }
11703
11704         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11705         if (error_string)
11706                 msg_param.data = (void *) error_string;
11707
11708         if (message->src) {
11709                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11710
11711                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11712                         msg_src_element, msg_param.code, (char*)msg_param.data);
11713         }
11714
11715         /* post error to application */
11716         if (!player->msg_posted) {
11717                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11718
11719                 /* don't post more if one was sent already */
11720                 player->msg_posted = TRUE;
11721         } else
11722                 LOGD("skip error post because it's sent already.\n");
11723
11724         gst_structure_free(s);
11725         MMPLAYER_FLEAVE();
11726         g_free(error_string);
11727
11728         return TRUE;
11729
11730 }
11731
11732 static void
11733 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11734 {
11735         MMPLAYER_RETURN_IF_FAIL(player);
11736
11737         /* post now if delay is zero */
11738         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11739                 LOGD("eos delay is zero. posting EOS now\n");
11740                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11741
11742                 if (player->set_mode.pcm_extraction)
11743                         __mmplayer_cancel_eos_timer(player);
11744
11745                 return;
11746         }
11747
11748         /* cancel if existing */
11749         __mmplayer_cancel_eos_timer(player);
11750
11751         /* init new timeout */
11752         /* NOTE : consider give high priority to this timer */
11753         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11754
11755         player->eos_timer = g_timeout_add(delay_in_ms,
11756                 __mmplayer_eos_timer_cb, player);
11757
11758         player->global_default = g_main_context_default();
11759         LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11760
11761         /* check timer is valid. if not, send EOS now */
11762         if (player->eos_timer == 0) {
11763                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11764                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11765         }
11766 }
11767
11768 static void
11769 __mmplayer_cancel_eos_timer(mm_player_t* player)
11770 {
11771         MMPLAYER_RETURN_IF_FAIL(player);
11772
11773         if (player->eos_timer) {
11774                 LOGD("cancel eos timer");
11775                 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11776                 player->eos_timer = 0;
11777         }
11778
11779         return;
11780 }
11781
11782 static gboolean
11783 __mmplayer_eos_timer_cb(gpointer u_data)
11784 {
11785         mm_player_t* player = NULL;
11786         MMHandleType attrs = 0;
11787         int count = 0;
11788
11789         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11790
11791         player = (mm_player_t*) u_data;
11792         attrs = MMPLAYER_GET_ATTRS(player);
11793
11794         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11795
11796         if (count == -1) {
11797                 gint ret_value = 0;
11798                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11799                 if (ret_value != MM_ERROR_NONE)
11800                         LOGE("seeking to 0 failed in repeat play");
11801         } else {
11802                 /* posting eos */
11803                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11804         }
11805
11806         /* we are returning FALSE as we need only one posting */
11807         return FALSE;
11808 }
11809
11810 /* sending event to one of sinkelements */
11811 static gboolean
11812 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11813 {
11814         GstEvent * event2 = NULL;
11815         GList *sinks = NULL;
11816         gboolean res = FALSE;
11817         MMPLAYER_FENTER();
11818
11819         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11820         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11821
11822         /* While adding subtitles in live feeds seek is getting called.
11823            Adding defensive check in framework layer.*/
11824         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11825                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11826                         LOGE("Should not send seek event during live playback");
11827                         return TRUE;
11828                 }
11829         }
11830
11831         if (player->play_subtitle)
11832                 event2 = gst_event_copy((const GstEvent *)event);
11833
11834         sinks = player->sink_elements;
11835         while (sinks) {
11836                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11837
11838                 if (GST_IS_ELEMENT(sink)) {
11839                         /* keep ref to the event */
11840                         gst_event_ref(event);
11841
11842                         if ((res = gst_element_send_event(sink, event))) {
11843                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11844                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11845
11846                                 /* rtsp case, asyn_done is not called after seek during pause state */
11847                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11848                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11849                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11850                                                         LOGD("RTSP seek completed, after pause state..\n");
11851                                                         player->doing_seek = FALSE;
11852                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11853                                                 }
11854
11855                                         }
11856                                 }
11857
11858                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11859                                         sinks = g_list_next(sinks);
11860                                         continue;
11861                                 } else {
11862                                         break;
11863                                 }
11864                         }
11865
11866                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11867                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11868                 }
11869
11870                 sinks = g_list_next(sinks);
11871         }
11872
11873         /* Note : Textbin is not linked to the video or audio bin.
11874          * It needs to send the event to the text sink seperatelly.
11875          */
11876          if (player->play_subtitle && player->pipeline) {
11877                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11878
11879                 if (GST_IS_ELEMENT(text_sink)) {
11880                         /* keep ref to the event */
11881                         gst_event_ref(event2);
11882
11883                         if ((res = gst_element_send_event(text_sink, event2)))
11884                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11885                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11886                         else
11887                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11888                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11889
11890                         gst_event_unref(event2);
11891                 }
11892          }
11893
11894         gst_event_unref(event);
11895
11896         MMPLAYER_FLEAVE();
11897
11898         return res;
11899 }
11900
11901 static void
11902 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11903 {
11904         MMPLAYER_FENTER();
11905
11906         MMPLAYER_RETURN_IF_FAIL(player);
11907         MMPLAYER_RETURN_IF_FAIL(sink);
11908
11909         player->sink_elements =
11910                 g_list_append(player->sink_elements, sink);
11911
11912         MMPLAYER_FLEAVE();
11913 }
11914
11915 static void
11916 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11917 {
11918         MMPLAYER_FENTER();
11919
11920         MMPLAYER_RETURN_IF_FAIL(player);
11921         MMPLAYER_RETURN_IF_FAIL(sink);
11922
11923         player->sink_elements =
11924                         g_list_remove(player->sink_elements, sink);
11925
11926         MMPLAYER_FLEAVE();
11927 }
11928
11929 static gboolean
11930 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11931                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11932                         gint64 cur, GstSeekType stop_type, gint64 stop)
11933 {
11934         GstEvent* event = NULL;
11935         gboolean result = FALSE;
11936
11937         MMPLAYER_FENTER();
11938
11939         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11940
11941         if (player->pipeline && player->pipeline->textbin)
11942                 __mmplayer_drop_subtitle(player, FALSE);
11943
11944         event = gst_event_new_seek(rate, format, flags, cur_type,
11945                 cur, stop_type, stop);
11946
11947         result = __gst_send_event_to_sink(player, event);
11948
11949         MMPLAYER_FLEAVE();
11950
11951         return result;
11952 }
11953
11954 /* NOTE : be careful with calling this api. please refer to below glib comment
11955  * glib comment : Note that there is a bug in GObject that makes this function much
11956  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11957  * will no longer be called, but, the signal handler is not currently disconnected.
11958  * If the instance is itself being freed at the same time than this doesn't matter,
11959  * since the signal will automatically be removed, but if instance persists,
11960  * then the signal handler will leak. You should not remove the signal yourself
11961  * because in a future versions of GObject, the handler will automatically be
11962  * disconnected.
11963  *
11964  * It's possible to work around this problem in a way that will continue to work
11965  * with future versions of GObject by checking that the signal handler is still
11966  * connected before disconnected it:
11967  *
11968  *  if (g_signal_handler_is_connected(instance, id))
11969  *    g_signal_handler_disconnect(instance, id);
11970  */
11971 static void
11972 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11973 {
11974         GList* sig_list = NULL;
11975         MMPlayerSignalItem* item = NULL;
11976
11977         MMPLAYER_FENTER();
11978
11979         MMPLAYER_RETURN_IF_FAIL(player);
11980
11981         LOGD("release signals type : %d", type);
11982
11983         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11984                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11985                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11986                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11987                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11988                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11989                 return;
11990         }
11991
11992         sig_list = player->signals[type];
11993
11994         for (; sig_list; sig_list = sig_list->next) {
11995                 item = sig_list->data;
11996
11997                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11998                         if (g_signal_handler_is_connected(item->obj, item->sig))
11999                                 g_signal_handler_disconnect(item->obj, item->sig);
12000                 }
12001
12002                 MMPLAYER_FREEIF(item);
12003         }
12004
12005         g_list_free(player->signals[type]);
12006         player->signals[type] = NULL;
12007
12008         MMPLAYER_FLEAVE();
12009
12010         return;
12011 }
12012
12013 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12014 {
12015         mm_player_t* player = 0;
12016         int prev_display_surface_type = 0;
12017         void *prev_display_overlay = NULL;
12018         const gchar *klass = NULL;
12019         gchar *cur_videosink_name = NULL;
12020         int ret = 0;
12021         int i = 0;
12022         int num_of_dec = 2; /* DEC1, DEC2 */
12023
12024         MMPLAYER_FENTER();
12025
12026         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12027         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12028
12029         player = MM_PLAYER_CAST(handle);
12030
12031         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12032                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12033                 MMPLAYER_FLEAVE();
12034                 return MM_ERROR_INVALID_ARGUMENT;
12035         }
12036
12037         /* load previous attributes */
12038         if (player->attrs) {
12039                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12040                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12041                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12042                 if (prev_display_surface_type == surface_type) {
12043                         LOGD("incoming display surface type is same as previous one, do nothing..");
12044                         MMPLAYER_FLEAVE();
12045                         return MM_ERROR_NONE;
12046                 }
12047         } else {
12048                 LOGE("failed to load attributes");
12049                 MMPLAYER_FLEAVE();
12050                 return MM_ERROR_PLAYER_INTERNAL;
12051         }
12052
12053         /* check videosink element is created */
12054         if (!player->pipeline || !player->pipeline->videobin ||
12055                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12056                 LOGD("videosink element is not yet ready");
12057
12058                 /* videobin is not created yet, so we just set attributes related to display surface */
12059                 LOGD("store display attribute for given surface type(%d)", surface_type);
12060                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12061                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12062                 if (mmf_attrs_commit(player->attrs)) {
12063                         LOGE("failed to commit attribute");
12064                         MMPLAYER_FLEAVE();
12065                         return MM_ERROR_PLAYER_INTERNAL;
12066                 }
12067                 MMPLAYER_FLEAVE();
12068                 return MM_ERROR_NONE;
12069         } else {
12070                 /* get player command status */
12071                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12072                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12073                         MMPLAYER_FLEAVE();
12074                         return MM_ERROR_PLAYER_INVALID_STATE;
12075                 }
12076
12077                 /* surface change */
12078                 for (i = 0 ; i < num_of_dec ; i++) {
12079                         if (player->pipeline->mainbin &&
12080                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12081                                 GstElementFactory *decfactory;
12082                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12083
12084                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12085                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12086                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12087                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12088                                                 if (ret) {
12089                                                         goto ERROR_CASE;
12090                                                 } else {
12091                                                         LOGW("success to changing display surface(%d)", surface_type);
12092                                                         MMPLAYER_FLEAVE();
12093                                                         return MM_ERROR_NONE;
12094                                                 }
12095                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12096                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12097                                                 if (ret) {
12098                                                         goto ERROR_CASE;
12099                                                 } else {
12100                                                         LOGW("success to changing display surface(%d)", surface_type);
12101                                                         MMPLAYER_FLEAVE();
12102                                                         return MM_ERROR_NONE;
12103                                                 }
12104                                         } else {
12105                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12106                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12107                                                 goto ERROR_CASE;
12108                                         }
12109                                 }
12110                         }
12111                 }
12112         }
12113
12114 ERROR_CASE:
12115         /* rollback to previous attributes */
12116         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12117         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12118         if (mmf_attrs_commit(player->attrs)) {
12119                 LOGE("failed to commit attributes to rollback");
12120                 MMPLAYER_FLEAVE();
12121                 return MM_ERROR_PLAYER_INTERNAL;
12122         }
12123         MMPLAYER_FLEAVE();
12124         return ret;
12125 }
12126
12127 /* NOTE : It does not support some use cases, eg using colorspace converter */
12128 int
12129 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12130 {
12131         GstPad *src_pad_dec = NULL;
12132         GstPad *sink_pad_videosink = NULL;
12133         GstPad *sink_pad_videobin = NULL;
12134         GstClock *clock = NULL;
12135         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12136         int ret = MM_ERROR_NONE;
12137         gboolean is_audiobin_created = TRUE;
12138
12139         MMPLAYER_FENTER();
12140
12141         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12142         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12143         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12144
12145         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12146         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12147
12148         /* get information whether if audiobin is created */
12149         if (!player->pipeline->audiobin ||
12150                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12151                 LOGW("audiobin is null, this video content may not have audio data");
12152                 is_audiobin_created = FALSE;
12153         }
12154
12155         /* get current state of player */
12156         previous_state = MMPLAYER_CURRENT_STATE(player);
12157         LOGD("previous state(%d)", previous_state);
12158
12159
12160         /* get src pad of decoder and block it */
12161         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12162         if (!src_pad_dec) {
12163                 LOGE("failed to get src pad from decode in mainbin");
12164                 return MM_ERROR_PLAYER_INTERNAL;
12165         }
12166
12167         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12168                 LOGW("trying to block pad(video)");
12169 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12170                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12171                         NULL, NULL, NULL);
12172                 {
12173                         LOGE("failed to set block pad(video)");
12174                         return MM_ERROR_PLAYER_INTERNAL;
12175                 }
12176                 LOGW("pad is blocked(video)");
12177         } else {
12178                 /* no data flows, so no need to do pad_block */
12179                 if (player->doing_seek)
12180                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12181
12182                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12183         }
12184
12185         /* remove pad */
12186         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12187                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12188                 LOGE("failed to remove previous ghost_pad for videobin");
12189                 return MM_ERROR_PLAYER_INTERNAL;
12190         }
12191
12192         /* change state of videobin to NULL */
12193         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12194         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12195         if (ret != GST_STATE_CHANGE_SUCCESS) {
12196                 LOGE("failed to change state of videobin to NULL");
12197                 return MM_ERROR_PLAYER_INTERNAL;
12198         }
12199
12200         /* unlink between decoder and videobin and remove previous videosink from videobin */
12201         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12202         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12203                 LOGE("failed to remove former videosink from videobin");
12204                 return MM_ERROR_PLAYER_INTERNAL;
12205         }
12206
12207         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12208
12209         /* create a new videosink and add it to videobin */
12210         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12211         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12212                 LOGE("failed to create videosink element\n");
12213                 MMPLAYER_FLEAVE();
12214                 return MM_ERROR_PLAYER_INTERNAL;
12215         }
12216         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12217         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12218         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12219
12220         /* save attributes */
12221         if (player->attrs) {
12222                 /* set a new display surface type */
12223                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12224                 /* set a new diplay overlay */
12225                 switch (surface_type) {
12226                 case MM_DISPLAY_SURFACE_OVERLAY:
12227                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12228                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12229                         break;
12230                 default:
12231                         LOGE("invalid type(%d) for changing display surface", surface_type);
12232                         MMPLAYER_FLEAVE();
12233                         return MM_ERROR_INVALID_ARGUMENT;
12234                 }
12235                 if (mmf_attrs_commit(player->attrs)) {
12236                         LOGE("failed to commit");
12237                         MMPLAYER_FLEAVE();
12238                         return MM_ERROR_PLAYER_INTERNAL;
12239                 }
12240         } else {
12241                 LOGE("player->attrs is null, failed to save attributes");
12242                 MMPLAYER_FLEAVE();
12243                 return MM_ERROR_PLAYER_INTERNAL;
12244         }
12245
12246         /* update video param */
12247         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12248                 LOGE("failed to update video param");
12249                 return MM_ERROR_PLAYER_INTERNAL;
12250         }
12251
12252         /* change state of videobin to READY */
12253         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12254         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12255         if (ret != GST_STATE_CHANGE_SUCCESS) {
12256                 LOGE("failed to change state of videobin to READY");
12257                 return MM_ERROR_PLAYER_INTERNAL;
12258         }
12259
12260         /* change ghostpad */
12261         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12262         if (!sink_pad_videosink) {
12263                 LOGE("failed to get sink pad from videosink element");
12264                 return MM_ERROR_PLAYER_INTERNAL;
12265         }
12266         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12267         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12268                 LOGE("failed to set active to ghost_pad");
12269                 return MM_ERROR_PLAYER_INTERNAL;
12270         }
12271         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12272                 LOGE("failed to change ghostpad for videobin");
12273                 return MM_ERROR_PLAYER_INTERNAL;
12274         }
12275         gst_object_unref(sink_pad_videosink);
12276
12277         /* link decoder with videobin */
12278         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12279         if (!sink_pad_videobin) {
12280                 LOGE("failed to get sink pad from videobin");
12281                 return MM_ERROR_PLAYER_INTERNAL;
12282         }
12283         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12284                 LOGE("failed to link");
12285                 return MM_ERROR_PLAYER_INTERNAL;
12286         }
12287         gst_object_unref(sink_pad_videobin);
12288
12289         /* clock setting for a new videosink plugin */
12290         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12291                         so we set it from audiosink plugin or pipeline(system clock) */
12292         if (!is_audiobin_created) {
12293                 LOGW("audiobin is not created, get clock from pipeline..");
12294                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12295         } else {
12296                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12297         }
12298         if (clock) {
12299                 GstClockTime now;
12300                 GstClockTime base_time;
12301                 LOGD("set the clock to videosink");
12302                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12303                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12304                 if (clock) {
12305                         LOGD("got clock of videosink");
12306                         now = gst_clock_get_time(clock);
12307                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12308                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12309                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12310                 } else {
12311                         LOGE("failed to get clock of videosink after setting clock");
12312                         return MM_ERROR_PLAYER_INTERNAL;
12313                 }
12314         } else
12315                 LOGW("failed to get clock, maybe it is the time before first playing");
12316
12317         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12318                 /* change state of videobin to PAUSED */
12319                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12320                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12321                 if (ret != GST_STATE_CHANGE_FAILURE) {
12322                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12323                 } else {
12324                         LOGE("failed to change state of videobin to PLAYING");
12325                         return MM_ERROR_PLAYER_INTERNAL;
12326                 }
12327
12328                 /* release blocked and unref src pad of video decoder */
12329                 #if 0
12330                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12331                         LOGE("failed to set pad blocked FALSE(video)");
12332                         return MM_ERROR_PLAYER_INTERNAL;
12333                 }
12334                 #endif
12335                 LOGW("pad is unblocked(video)");
12336         } else {
12337                 if (player->doing_seek)
12338                         LOGW("not completed seek(%d)", player->doing_seek);
12339                 /* change state of videobin to PAUSED */
12340                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12341                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12342                 if (ret != GST_STATE_CHANGE_FAILURE) {
12343                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12344                 } else {
12345                         LOGE("failed to change state of videobin to PLAYING");
12346                         return MM_ERROR_PLAYER_INTERNAL;
12347                 }
12348
12349                 /* already skipped pad block */
12350                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12351         }
12352
12353         /* do get/set position for new videosink plugin */
12354         {
12355                 unsigned long position = 0;
12356                 gint64 pos_msec = 0;
12357
12358                 LOGD("do get/set position for new videosink plugin");
12359                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12360                         LOGE("failed to get position");
12361                         return MM_ERROR_PLAYER_INTERNAL;
12362                 }
12363 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12364                 /* accurate seek */
12365                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12366                         LOGE("failed to set position");
12367                         return MM_ERROR_PLAYER_INTERNAL;
12368                 }
12369 #else
12370                 /* key unit seek */
12371                 pos_msec = position * G_GINT64_CONSTANT(1000000);
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, pos_msec,
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 = %lld, rate = %f\n", 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,
12926                                         long long clock,
12927                                         long long clock_delta,
12928                                         long long video_time,
12929                                         long long media_clock,
12930                                         long long audio_time)
12931 {
12932         mm_player_t* player = (mm_player_t*) hplayer;
12933         MMPlayerGstElement* mainbin = NULL;
12934         GstClockTime start_time_audio = 0, start_time_video = 0;
12935         GstClockTimeDiff base_time = 0, new_base_time = 0;
12936         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12937         gint64 api_delta = 0;
12938         gint64 position = 0, position_delta = 0;
12939         gint64 adj_base_time = 0;
12940         GstClock *curr_clock = NULL;
12941         GstClockTime curr_time = 0;
12942         gboolean query_ret = TRUE;
12943         int result = MM_ERROR_NONE;
12944
12945         MMPLAYER_FENTER();
12946
12947         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12948         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12949         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12950
12951         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12952
12953         if ((video_time < 0) || (player->doing_seek)) {
12954                 LOGD("skip setting master clock.  %lld", video_time);
12955                 goto EXIT;
12956         }
12957
12958         mainbin = player->pipeline->mainbin;
12959
12960         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12961         curr_time = gst_clock_get_time(curr_clock);
12962
12963         current_state = MMPLAYER_CURRENT_STATE(player);
12964
12965         if (current_state == MM_PLAYER_STATE_PLAYING)
12966                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12967
12968         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12969                 (!query_ret)) {
12970                 position = player->last_position;
12971                 LOGD("query fail. %lld", position);
12972         }
12973
12974         clock *= GST_USECOND;
12975         clock_delta *= GST_USECOND;
12976
12977         api_delta = clock - curr_time;
12978         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12979                 player->video_share_api_delta = api_delta;
12980         else
12981                 clock_delta += (api_delta - player->video_share_api_delta);
12982
12983         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12984                 player->video_share_clock_delta = (gint64)clock_delta;
12985
12986                 position_delta = (position/GST_USECOND) - video_time;
12987                 position_delta *= GST_USECOND;
12988
12989                 adj_base_time = position_delta;
12990                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12991
12992         } else {
12993                 gint64 new_play_time = 0;
12994                 gint64 network_delay = 0;
12995
12996                 video_time *= GST_USECOND;
12997
12998                 network_delay = clock_delta - player->video_share_clock_delta;
12999                 new_play_time = video_time + network_delay;
13000
13001                 adj_base_time = position - new_play_time;
13002
13003                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13004                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13005         }
13006
13007         /* Adjust Current Stream Time with base_time of sink
13008          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13009          * 2. Set new base time
13010          *    if adj_base_time is positive value, the stream time will be decreased.
13011          * 3. If seek event is occurred, the start time will be reset. */
13012         if ((player->pipeline->audiobin) &&
13013                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13014                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13015
13016                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13017                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13018                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13019                 }
13020
13021                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13022         }
13023
13024         if ((player->pipeline->videobin) &&
13025                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13026                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13027
13028                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13029                         LOGD("video sink : gst_element_set_start_time -> NONE");
13030                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13031                 }
13032
13033                 // if videobin exist, get base_time from videobin.
13034                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13035         }
13036
13037         new_base_time = base_time + adj_base_time;
13038
13039         if ((player->pipeline->audiobin) &&
13040                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13041                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13042
13043         if ((player->pipeline->videobin) &&
13044                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13045                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13046
13047 EXIT:
13048         MMPLAYER_FLEAVE();
13049
13050         return result;
13051 }
13052
13053 int
13054 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13055                                         long long *video_time,
13056                                         long long *media_clock,
13057                                         long long *audio_time)
13058 {
13059         mm_player_t* player = (mm_player_t*) hplayer;
13060         MMPlayerGstElement* mainbin = NULL;
13061         GstClock *curr_clock = NULL;
13062         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13063         gint64 position = 0;
13064         gboolean query_ret = TRUE;
13065
13066         MMPLAYER_FENTER();
13067
13068         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13069         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13070         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13071
13072         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13073         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13074         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13075
13076         mainbin = player->pipeline->mainbin;
13077
13078         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13079
13080         current_state = MMPLAYER_CURRENT_STATE(player);
13081
13082         if (current_state != MM_PLAYER_STATE_PAUSED)
13083                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13084
13085         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13086                 (!query_ret))
13087                 position = player->last_position;
13088
13089         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13090
13091         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13092
13093         if (curr_clock)
13094                 gst_object_unref(curr_clock);
13095
13096         MMPLAYER_FLEAVE();
13097
13098         return MM_ERROR_NONE;
13099 }
13100
13101 static gboolean
13102 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13103 {
13104         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13105         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13106
13107         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13108         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13109
13110         int idx = 0;
13111
13112         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13113                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13114                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13115                         mm_player_dump_t *dump_s;
13116                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13117
13118                         if (dump_s == NULL) {
13119                                 LOGE("malloc fail");
13120                                 return FALSE;
13121                         }
13122
13123                         dump_s->dump_element_file = NULL;
13124                         dump_s->dump_pad = NULL;
13125                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13126
13127                         if (dump_s->dump_pad) {
13128                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13129                                 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]);
13130                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13131                                 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);
13132                                 /* add list for removed buffer probe and close FILE */
13133                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13134                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13135                                 return TRUE;
13136                         } else {
13137                                 g_free(dump_s);
13138                                 dump_s = NULL;
13139                                 LOGE("failed to get %s sink pad added", factory_name);
13140                         }
13141
13142
13143                 }
13144         }
13145         return FALSE;
13146 }
13147
13148 static GstPadProbeReturn
13149 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13150 {
13151         FILE *dump_data = (FILE *) u_data;
13152 //      int written = 0;
13153         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13154         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13155
13156         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13157
13158         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13159
13160 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13161
13162         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13163
13164         return GST_PAD_PROBE_OK;
13165 }
13166
13167 static void
13168 __mmplayer_release_dump_list(GList *dump_list)
13169 {
13170         if (dump_list) {
13171                 GList *d_list = dump_list;
13172                 for (; d_list; d_list = g_list_next(d_list)) {
13173                         mm_player_dump_t *dump_s = d_list->data;
13174                         if (dump_s->dump_pad) {
13175                                 if (dump_s->probe_handle_id)
13176                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13177                         }
13178                         if (dump_s->dump_element_file) {
13179                                 fclose(dump_s->dump_element_file);
13180                                 dump_s->dump_element_file = NULL;
13181                         }
13182                         MMPLAYER_FREEIF(dump_s);
13183                 }
13184                 g_list_free(dump_list);
13185                 dump_list = NULL;
13186         }
13187 }
13188
13189 int
13190 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13191 {
13192         mm_player_t* player = (mm_player_t*) hplayer;
13193
13194         MMPLAYER_FENTER();
13195
13196         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13197         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13198
13199         *exist = player->has_closed_caption;
13200
13201         MMPLAYER_FLEAVE();
13202
13203         return MM_ERROR_NONE;
13204 }
13205
13206 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13207 {
13208         MMPLAYER_FENTER();
13209         if (buffer) {
13210                 // LOGD("unref internal gst buffer %p", buffer);
13211                 gst_buffer_unref((GstBuffer *)buffer);
13212                 buffer = NULL;
13213         }
13214         MMPLAYER_FLEAVE();
13215 }
13216
13217 void
13218 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13219 {
13220         mm_player_t *player  = (mm_player_t*)user_data;
13221         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13222         guint64 current_level_bytes = 0;
13223
13224         MMPLAYER_RETURN_IF_FAIL(player);
13225
13226         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13227
13228         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13229         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13230
13231         if (player->media_stream_buffer_status_cb[type])
13232                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13233         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13234
13235 }
13236
13237 void
13238 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13239 {
13240         mm_player_t *player  = (mm_player_t*)user_data;
13241         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13242         guint64 current_level_bytes = 0;
13243
13244         MMPLAYER_RETURN_IF_FAIL(player);
13245
13246         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13247
13248         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13249
13250         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13251         if (player->media_stream_buffer_status_cb[type])
13252                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13253         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13254 }
13255
13256 void
13257 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13258 {
13259         mm_player_t *player  = (mm_player_t*)user_data;
13260         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13261         guint64 current_level_bytes = 0;
13262
13263         MMPLAYER_RETURN_IF_FAIL(player);
13264
13265         LOGI("app-src: feed subtitle\n");
13266
13267         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13268
13269         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13270         if (player->media_stream_buffer_status_cb[type])
13271                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13272
13273         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13274 }
13275
13276 void
13277 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13278 {
13279         mm_player_t *player  = (mm_player_t*)user_data;
13280         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13281         guint64 current_level_bytes = 0;
13282
13283         MMPLAYER_RETURN_IF_FAIL(player);
13284
13285         LOGI("app-src: audio buffer is full.\n");
13286
13287         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13288
13289         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13290
13291         if (player->media_stream_buffer_status_cb[type])
13292                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13293
13294         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13295 }
13296
13297 void
13298 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13299 {
13300         mm_player_t *player  = (mm_player_t*)user_data;
13301         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13302         guint64 current_level_bytes = 0;
13303
13304         MMPLAYER_RETURN_IF_FAIL(player);
13305
13306         LOGI("app-src: video buffer is full.\n");
13307
13308         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13309
13310         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13311         if (player->media_stream_buffer_status_cb[type])
13312                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13313
13314         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13315 }
13316
13317 gboolean
13318 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13319 {
13320         mm_player_t *player  = (mm_player_t*)user_data;
13321         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13322
13323         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13324
13325         LOGD("app-src: seek audio data %llu\n", position);
13326         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13327
13328         if (player->media_stream_seek_data_cb[type])
13329                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13330         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13331
13332         return TRUE;
13333 }
13334
13335 gboolean
13336 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13337 {
13338         mm_player_t *player  = (mm_player_t*)user_data;
13339         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13340
13341         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13342
13343         LOGD("app-src: seek video data %llu\n", position);
13344         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13345         if (player->media_stream_seek_data_cb[type])
13346                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13347         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13348
13349         return TRUE;
13350 }
13351
13352 gboolean
13353 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13354 {
13355         mm_player_t *player  = (mm_player_t*)user_data;
13356         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13357
13358         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13359
13360         LOGD("app-src: seek subtitle data\n");
13361         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13362
13363         if (player->media_stream_seek_data_cb[type])
13364                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13365         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13366
13367         return TRUE;
13368 }
13369
13370 int
13371 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13372 {
13373         mm_player_t* player = (mm_player_t*) hplayer;
13374
13375         MMPLAYER_FENTER();
13376
13377         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13378
13379         player->pcm_samplerate = samplerate;
13380         player->pcm_channel = channel;
13381
13382         MMPLAYER_FLEAVE();
13383         return MM_ERROR_NONE;
13384 }
13385
13386 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13387 {
13388         mm_player_t* player = (mm_player_t*) hplayer;
13389
13390         MMPLAYER_FENTER();
13391
13392         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13393         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13394
13395         if (MMPLAYER_IS_STREAMING(player))
13396                 *timeout = player->ini.live_state_change_timeout;
13397         else
13398                 *timeout = player->ini.localplayback_state_change_timeout;
13399
13400         LOGD("timeout = %d\n", *timeout);
13401
13402         MMPLAYER_FLEAVE();
13403         return MM_ERROR_NONE;
13404 }
13405
13406 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13407 {
13408         mm_player_t* player = (mm_player_t*) hplayer;
13409
13410         MMPLAYER_FENTER();
13411
13412         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13413         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13414
13415         *num = player->video_num_buffers;
13416         *extra_num = player->video_extra_num_buffers;
13417
13418         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13419
13420         MMPLAYER_FLEAVE();
13421         return MM_ERROR_NONE;
13422 }
13423
13424 static void
13425 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13426 {
13427         int i = 0;
13428         MMPLAYER_FENTER();
13429         MMPLAYER_RETURN_IF_FAIL(player);
13430
13431         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13432
13433                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13434                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13435                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13436                         player->storage_info[i].id = -1;
13437                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13438
13439                         if (path_type != MMPLAYER_PATH_MAX)
13440                                 break;
13441                 }
13442         }
13443
13444         MMPLAYER_FLEAVE();
13445 }
13446
13447 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13448 {
13449         int ret = MM_ERROR_NONE;
13450         mm_player_t* player = (mm_player_t*)hplayer;
13451         MMMessageParamType msg_param = {0, };
13452
13453         MMPLAYER_FENTER();
13454         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13455
13456         LOGW("state changed storage %d:%d", id, state);
13457
13458         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13459                 return MM_ERROR_NONE;
13460
13461         /* FIXME: text path should be handled seperately. */
13462         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13463                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13464                 LOGW("external storage is removed");
13465
13466                 if (player->msg_posted == FALSE) {
13467                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13468                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13469                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13470                         player->msg_posted = TRUE;
13471                 }
13472
13473                 /* unrealize the player */
13474                 ret = _mmplayer_unrealize(hplayer);
13475                 if (ret != MM_ERROR_NONE)
13476                         LOGE("failed to unrealize");
13477         }
13478
13479         MMPLAYER_FLEAVE();
13480         return ret;
13481 }
13482
13483 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13484 {
13485         int ret = MM_ERROR_NONE;
13486         mm_player_t* player = (mm_player_t*) hplayer;
13487         int idx = 0, total = 0;
13488         gchar *result = NULL, *tmp = NULL;
13489
13490         MMPLAYER_FENTER();
13491         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13492         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13493
13494         total = *num = g_list_length(player->adaptive_info.var_list);
13495         if (total <= 0) {
13496                 LOGW("There is no stream variant info.");
13497                 return ret;
13498         }
13499
13500         result = g_strdup("");
13501         for (idx = 0 ; idx < total ; idx++) {
13502                 VariantData *v_data = NULL;
13503                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13504
13505                 if (v_data) {
13506                         gchar data[64] = {0};
13507                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13508
13509                         tmp = g_strconcat(result, data, NULL);
13510                         g_free(result);
13511                         result = tmp;
13512                 } else {
13513                         LOGW("There is no variant data in %d", idx);
13514                         (*num)--;
13515                 }
13516         }
13517
13518         *var_info = (char *)result;
13519
13520         LOGD("variant info %d:%s", *num, *var_info);
13521         MMPLAYER_FLEAVE();
13522         return ret;
13523 }
13524
13525 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13526 {
13527         int ret = MM_ERROR_NONE;
13528         mm_player_t* player = (mm_player_t*) hplayer;
13529
13530         MMPLAYER_FENTER();
13531         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13532
13533         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13534
13535         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13536         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13537         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13538
13539         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13540                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13541                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13542                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13543
13544                 /* FIXME: seek to current position for applying new variant limitation */
13545         }
13546
13547         MMPLAYER_FLEAVE();
13548         return ret;
13549
13550 }
13551
13552 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13553 {
13554         int ret = MM_ERROR_NONE;
13555         mm_player_t* player = (mm_player_t*) hplayer;
13556
13557         MMPLAYER_FENTER();
13558         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13559         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13560
13561         *bandwidth = player->adaptive_info.limit.bandwidth;
13562         *width = player->adaptive_info.limit.width;
13563         *height = player->adaptive_info.limit.height;
13564
13565         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13566
13567         MMPLAYER_FLEAVE();
13568         return ret;
13569 }
13570
13571 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13572 {
13573         int ret = MM_ERROR_NONE;
13574         mm_player_t* player = (mm_player_t*) hplayer;
13575
13576         MMPLAYER_FENTER();
13577         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13578
13579         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13580                 LOGW("buffer_ms will not be applied.");
13581
13582
13583         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13584
13585         if (player->streamer == NULL) {
13586                 player->streamer = __mm_player_streaming_create();
13587                 __mm_player_streaming_initialize(player->streamer);
13588         }
13589
13590         if (buffer_ms >= 0)
13591                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13592
13593         if (rebuffer_ms >= 0)
13594                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13595
13596         MMPLAYER_FLEAVE();
13597         return ret;
13598
13599 }
13600
13601 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13602 {
13603         int ret = MM_ERROR_NONE;
13604         mm_player_t* player = (mm_player_t*) hplayer;
13605
13606         MMPLAYER_FENTER();
13607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13608         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13609
13610         if (player->streamer == NULL) {
13611                 player->streamer = __mm_player_streaming_create();
13612                 __mm_player_streaming_initialize(player->streamer);
13613         }
13614
13615         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13616         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13617
13618         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13619
13620         MMPLAYER_FLEAVE();
13621         return ret;
13622 }
13623
13624 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13625 {
13626 #define IDX_FIRST_SW_CODEC 0
13627         mm_player_t* player = (mm_player_t*) hplayer;
13628         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13629         MMHandleType attrs = 0;
13630
13631         MMPLAYER_FENTER();
13632         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13633
13634         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13635                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13636                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13637
13638         switch (stream_type) {
13639         case MM_PLAYER_STREAM_TYPE_AUDIO:
13640                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13641                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13642                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13643                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13644                         LOGE("There is no a codec for codec_type %d", codec_type);
13645                         return MM_ERROR_PLAYER_NO_OP;
13646                 }
13647         break;
13648         case MM_PLAYER_STREAM_TYPE_VIDEO:
13649                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13650                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13651                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13652                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13653                         LOGE("There is no v codec for codec_type %d", codec_type);
13654                         return MM_ERROR_PLAYER_NO_OP;
13655                 }
13656
13657         break;
13658         default:
13659                 LOGE("Invalid stream type %d", stream_type);
13660                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13661         break;
13662         }
13663
13664         LOGD("update %s codec_type to %d", attr_name, codec_type);
13665
13666         attrs = MMPLAYER_GET_ATTRS(player);
13667         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13668
13669         if (mmf_attrs_commit(player->attrs)) {
13670                 LOGE("failed to commit codec_type attributes");
13671                 return MM_ERROR_PLAYER_INTERNAL;
13672         }
13673
13674         MMPLAYER_FLEAVE();
13675         return MM_ERROR_NONE;
13676 }
13677
13678 int
13679 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13680 {
13681         mm_player_t* player = (mm_player_t*) hplayer;
13682         GstElement* rg_vol_element = NULL;
13683
13684         MMPLAYER_FENTER();
13685
13686         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13687
13688         player->sound.rg_enable = enabled;
13689
13690         /* just hold rgvolume enable value if pipeline is not ready */
13691         if (!player->pipeline || !player->pipeline->audiobin) {
13692                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13693                 return MM_ERROR_NONE;
13694         }
13695
13696         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13697
13698         if (!rg_vol_element) {
13699                 LOGD("rgvolume element is not created");
13700                 return MM_ERROR_PLAYER_INTERNAL;
13701         }
13702
13703         if (enabled)
13704                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13705         else
13706                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13707
13708         MMPLAYER_FLEAVE();
13709
13710         return MM_ERROR_NONE;
13711 }
13712
13713 int
13714 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13715 {
13716         mm_player_t* player = (mm_player_t*) hplayer;
13717         GstElement* rg_vol_element = NULL;
13718         gboolean enable = FALSE;
13719
13720         MMPLAYER_FENTER();
13721
13722         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13723         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13724
13725         /* just hold enable_rg value if pipeline is not ready */
13726         if (!player->pipeline || !player->pipeline->audiobin) {
13727                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13728                 *enabled = player->sound.rg_enable;
13729                 return MM_ERROR_NONE;
13730         }
13731
13732         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13733
13734         if (!rg_vol_element) {
13735                 LOGD("rgvolume element is not created");
13736                 return MM_ERROR_PLAYER_INTERNAL;
13737         }
13738
13739         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13740         *enabled = enable;
13741
13742         MMPLAYER_FLEAVE();
13743
13744         return MM_ERROR_NONE;
13745 }