[0.6.58] add rm and display handling about audio_only
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43 #include <mm_sound.h>
44 #include <mm_sound_focus.h>
45
46 #include "mm_player_priv.h"
47 #include "mm_player_ini.h"
48 #include "mm_player_attrs.h"
49 #include "mm_player_capture.h"
50 #include "mm_player_utils.h"
51 #include "mm_player_tracks.h"
52
53 #include <system_info.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 MM_PLAYER_MPEG_VNAME                    "mpegversion"
89 #define MM_PLAYER_DIVX_VNAME                    "divxversion"
90 #define MM_PLAYER_WMV_VNAME                             "wmvversion"
91 #define MM_PLAYER_WMA_VNAME                             "wmaversion"
92
93 #define DEFAULT_PLAYBACK_RATE                   1.0
94 #define PLAYBACK_RATE_EX_AUDIO_MIN              0.5
95 #define PLAYBACK_RATE_EX_AUDIO_MAX              2.0
96 #define PLAYBACK_RATE_EX_VIDEO_MIN              0.5
97 #define PLAYBACK_RATE_EX_VIDEO_MAX              1.5
98 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
99
100 #define GST_QUEUE_DEFAULT_TIME                  4
101 #define GST_QUEUE_HLS_TIME                              8
102
103 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
104         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
105         (player->ini.http_use_file_buffer) && \
106         (player->http_file_buffering_path) && \
107         (strlen(player->http_file_buffering_path) > 0))
108 #define MM_PLAYER_NAME  "mmplayer"
109
110 #define PLAYER_DISPLAY_MODE_DST_ROI             5
111
112 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
113
114 /*---------------------------------------------------------------------------
115 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
116 ---------------------------------------------------------------------------*/
117
118 /*---------------------------------------------------------------------------
119 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
120 ---------------------------------------------------------------------------*/
121
122 /*---------------------------------------------------------------------------
123 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
124 ---------------------------------------------------------------------------*/
125
126 /*---------------------------------------------------------------------------
127 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
128 ---------------------------------------------------------------------------*/
129
130 /*---------------------------------------------------------------------------
131 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
132 ---------------------------------------------------------------------------*/
133 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
135 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
138 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
140
141 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
142 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
143 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
144 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
145 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
146 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
147 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
148 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
152 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
153 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
154
155 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
157 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
158 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
159 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
160 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
161 //static void   __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
162
163 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
164 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
165 static void             __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
166
167 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
168 //static void    __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
169 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
170 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
171 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172
173
174 static void             __mmplayer_init_factories(mm_player_t* player);
175 static void             __mmplayer_release_factories(mm_player_t* player);
176 static void             __mmplayer_release_misc(mm_player_t* player);
177 static void             __mmplayer_release_misc_post(mm_player_t* player);
178 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
179 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
180 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
181
182 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
183 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
184
185 int             __mmplayer_switch_audio_sink(mm_player_t* player);
186 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
187 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
188 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
189 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
190 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
191 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
192
193 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
194 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
195 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
196 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
197 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
198 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
199 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
200 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
201 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
202 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
203 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
204 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
205 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
206 static gpointer __mmplayer_next_play_thread(gpointer data);
207 static gpointer __mmplayer_repeat_thread(gpointer data);
208 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
209
210
211 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
212 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
213 static void __mmplayer_release_dump_list(GList *dump_list);
214
215 static int              __gst_realize(mm_player_t* player);
216 static int              __gst_unrealize(mm_player_t* player);
217 static int              __gst_start(mm_player_t* player);
218 static int              __gst_stop(mm_player_t* player);
219 static int              __gst_pause(mm_player_t* player, gboolean async);
220 static int              __gst_resume(mm_player_t* player, gboolean async);
221 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
222                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
223                                         gint64 cur, GstSeekType stop_type, gint64 stop);
224 static int __gst_pending_seek(mm_player_t* player);
225
226 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
227 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
228 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
229 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
230 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
231
232 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
233
234 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
235 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
236
237 /*fadeout */
238 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
239 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
240
241 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
242 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
243
244 /* util */
245 static gboolean __is_ms_buff_src(mm_player_t* player);
246 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
247
248 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
249 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
250 static int __mmplayer_start_streaming_ext(mm_player_t *player);
251 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
252 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
253
254 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
255 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
256 static void __mmplayer_check_pipeline(mm_player_t* player);
257 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
258 static void __mmplayer_deactivate_old_path(mm_player_t *player);
259 #if 0 // We'll need this in future.
260 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
261 #endif
262
263 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
264 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
265
266 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
267 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
268 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
269 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
270 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
271 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
272 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
273 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
274 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
275 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
276 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
277 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
278 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
279 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
280
281 /*===========================================================================================
282 |                                                                                                                                                                                       |
283 |  FUNCTION DEFINITIONS                                                                                                                                         |
284 |                                                                                                                                                                                       |
285 ========================================================================================== */
286
287 #if 0 //debug
288 static void
289 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
290 {
291         gint i, count;
292
293         count = gst_tag_list_get_tag_size(list, tag);
294
295         LOGD("count = %d", count);
296
297         for (i = 0; i < count; i++) {
298                 gchar *str;
299
300                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
301                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
302                                 g_assert_not_reached();
303                 } else
304                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
305
306                 if (i == 0)
307                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
308                 else
309                         g_print("                 : %s\n", str);
310
311                 g_free(str);
312         }
313 }
314 #endif
315
316 /* This function should be called after the pipeline goes PAUSED or higher
317 state. */
318 gboolean
319 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
320 {
321         static gboolean has_duration = FALSE;
322         static gboolean has_video_attrs = FALSE;
323         static gboolean has_audio_attrs = FALSE;
324         static gboolean has_bitrate = FALSE;
325         gboolean missing_only = FALSE;
326         gboolean all = FALSE;
327         gint64 dur_nsec = 0;
328         GstStructure* p = NULL;
329         MMHandleType attrs = 0;
330         gchar *path = NULL;
331         gint stream_service_type = STREAMING_SERVICE_NONE;
332         struct stat sb;
333
334         MMPLAYER_FENTER();
335
336         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
337
338         /* check player state here */
339         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
340                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
341                 /* give warning now only */
342                 LOGW("be careful. content attributes may not available in this state ");
343         }
344
345         /* get content attribute first */
346         attrs = MMPLAYER_GET_ATTRS(player);
347         if (!attrs) {
348                 LOGE("cannot get content attribute");
349                 return FALSE;
350         }
351
352         /* get update flag */
353
354         if (flag & ATTR_MISSING_ONLY) {
355                 missing_only = TRUE;
356                 LOGD("updating missed attr only");
357         }
358
359         if (flag & ATTR_ALL) {
360                 all = TRUE;
361                 has_duration = FALSE;
362                 has_video_attrs = FALSE;
363                 has_audio_attrs = FALSE;
364                 has_bitrate = FALSE;
365
366                 LOGD("updating all attrs");
367         }
368
369         if (missing_only && all) {
370                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
371                 missing_only = FALSE;
372         }
373
374         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
375                 LOGD("try to update duration");
376                 has_duration = FALSE;
377
378                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
379                         player->duration = dur_nsec;
380                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
381                 }
382
383                 if (player->duration < 0) {
384                         LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
385                         player->duration = 0;
386                 }
387
388                 /* try to get streaming service type */
389                 stream_service_type = __mmplayer_get_stream_service_type(player);
390                 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
391
392                 /* check duration is OK */
393                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
394                         /* FIXIT : find another way to get duration here. */
395                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
396                 } else {
397                         /*update duration */
398                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
399                         has_duration = TRUE;
400                 }
401         }
402
403         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
404                 /* update audio params
405                 NOTE : We need original audio params and it can be only obtained from src pad of audio
406                 decoder. Below code only valid when we are not using 'resampler' just before
407                 'audioconverter'. */
408
409                 LOGD("try to update audio attrs");
410                 has_audio_attrs = FALSE;
411
412                 if (player->pipeline->audiobin &&
413                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
414                         GstCaps *caps_a = NULL;
415                         GstPad* pad = NULL;
416                         gint samplerate = 0, channels = 0;
417
418                         pad = gst_element_get_static_pad(
419                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
420
421                         if (pad) {
422                                 caps_a = gst_pad_get_current_caps(pad);
423
424                                 if (caps_a) {
425                                         p = gst_caps_get_structure(caps_a, 0);
426
427                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
428
429                                         gst_structure_get_int(p, "rate", &samplerate);
430                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
431
432                                         gst_structure_get_int(p, "channels", &channels);
433                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
434
435                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
436
437                                         gst_caps_unref(caps_a);
438                                         caps_a = NULL;
439
440                                         has_audio_attrs = TRUE;
441                                 } else
442                                         LOGW("not ready to get audio caps");
443
444                                 gst_object_unref(pad);
445                         } else
446                                 LOGW("failed to get pad from audiosink");
447                 }
448         }
449
450         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
451                 LOGD("try to update video attrs");
452                 has_video_attrs = FALSE;
453
454                 if (player->pipeline->videobin &&
455                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
456                         GstCaps *caps_v = NULL;
457                         GstPad* pad = NULL;
458                         gint tmpNu, tmpDe;
459                         gint width, height;
460
461                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
462                         if (pad) {
463                                 caps_v = gst_pad_get_current_caps(pad);
464
465                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
466                                 if (!caps_v && player->v_stream_caps) {
467                                         caps_v = player->v_stream_caps;
468                                         gst_caps_ref(caps_v);
469                                 }
470
471                                 if (caps_v) {
472                                         p = gst_caps_get_structure(caps_v, 0);
473                                         gst_structure_get_int(p, "width", &width);
474                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
475
476                                         gst_structure_get_int(p, "height", &height);
477                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
478
479                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
480
481                                         SECURE_LOGD("width : %d     height : %d", width, height);
482
483                                         gst_caps_unref(caps_v);
484                                         caps_v = NULL;
485
486                                         if (tmpDe > 0) {
487                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
488                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
489                                         }
490
491                                         has_video_attrs = TRUE;
492                                 } else
493                                         LOGD("no negitiated caps from videosink");
494                                 gst_object_unref(pad);
495                                 pad = NULL;
496                         } else
497                                 LOGD("no videosink sink pad");
498                 }
499         }
500
501
502         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
503                 has_bitrate = FALSE;
504
505                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
506                 if (player->duration) {
507                         guint64 data_size = 0;
508
509                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
510                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
511
512                                 if (stat(path, &sb) == 0)
513                                         data_size = (guint64)sb.st_size;
514                         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
515                                 data_size = player->http_content_size;
516                         LOGD("try to update bitrate : data_size = %lld", data_size);
517
518                         if (data_size) {
519                                 guint64 bitrate = 0;
520                                 guint64 msec_dur = 0;
521
522                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
523                                 bitrate = data_size * 8 * 1000 / msec_dur;
524                                 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
525                                 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
526
527                                 has_bitrate = TRUE;
528                         }
529
530                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
531                                 if (player->total_bitrate) {
532                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
533                                         has_bitrate = TRUE;
534                                 }
535                         }
536                 }
537         }
538
539         /* validate all */
540         if (mmf_attrs_commit(attrs)) {
541                 LOGE("failed to update attributes\n");
542                 return FALSE;
543         }
544
545         MMPLAYER_FLEAVE();
546
547         return TRUE;
548 }
549
550 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
551 {
552         gint streaming_type = STREAMING_SERVICE_NONE;
553
554         MMPLAYER_FENTER();
555
556         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
557                         player->pipeline &&
558                         player->pipeline->mainbin &&
559                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
560                         FALSE);
561
562         /* streaming service type if streaming */
563         if (!MMPLAYER_IS_STREAMING(player))
564                 return STREAMING_SERVICE_NONE;
565
566         if (MMPLAYER_IS_HTTP_STREAMING(player))
567                 streaming_type = (player->duration == 0) ?
568                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
569
570         switch (streaming_type) {
571         case STREAMING_SERVICE_LIVE:
572                 LOGD("it's live streaming");
573                 break;
574         case STREAMING_SERVICE_VOD:
575                 LOGD("it's vod streaming");
576                 break;
577         default:
578                 LOGE("should not get here");
579         }
580
581         player->streaming_type = streaming_type;
582         MMPLAYER_FLEAVE();
583
584         return streaming_type;
585 }
586
587
588 /* this function sets the player state and also report
589  * it to applicaton by calling callback function
590  */
591 int
592 __mmplayer_set_state(mm_player_t* player, int state)
593 {
594         MMMessageParamType msg = {0, };
595         int sound_result = MM_ERROR_NONE;
596         gboolean post_bos = FALSE;
597         gboolean interrupted_by_focus = FALSE;
598         gboolean interrupted_by_resource = FALSE;
599
600         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
601
602         if (MMPLAYER_CURRENT_STATE(player) == state) {
603                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
604                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
605                 return MM_ERROR_NONE;
606         }
607
608         /* update player states */
609         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
610         MMPLAYER_CURRENT_STATE(player) = state;
611
612         /* FIXIT : it's better to do like below code
613         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
614                         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
615         and add more code to handling PENDING_STATE.
616         */
617         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
618                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
619
620         /* print state */
621         MMPLAYER_PRINT_STATE(player);
622
623         /* do some FSM stuffs before posting new state to application  */
624         interrupted_by_focus = player->sound_focus.by_asm_cb;
625         interrupted_by_resource = (player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb ||
626                                                            player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb);
627
628         switch (MMPLAYER_CURRENT_STATE(player)) {
629         case MM_PLAYER_STATE_NULL:
630         case MM_PLAYER_STATE_READY:
631                 {
632                         if (player->cmd == MMPLAYER_COMMAND_STOP) {
633                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
634                                 if (sound_result != MM_ERROR_NONE) {
635                                         LOGE("failed to release sound focus\n");
636                                         return MM_ERROR_POLICY_INTERNAL;
637                                 }
638                         }
639                 }
640                 break;
641
642         case MM_PLAYER_STATE_PAUSED:
643                 {
644                          if (!player->sent_bos) {
645                                 int found = 0;
646                                 #define MMPLAYER_MAX_SOUND_PRIORITY     3
647
648                                 /* rtsp case, get content attrs by GstMessage */
649                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
650                                         /* it's first time to update all content attrs. */
651                                         _mmplayer_update_content_attrs( player, ATTR_ALL );
652                                 }
653
654                                 /* set max sound priority to keep own sound and not to mute other's one */
655                                 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
656                                 if (found) {
657                                         mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
658                                         if (found) {
659                                                 LOGD("set max audio priority");
660                                                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
661                                         }
662                                 }
663
664                          }
665
666                         /* add audio callback probe if condition is satisfied */
667                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
668                                 __mmplayer_configure_audio_callback(player);
669                                 /* FIXIT : handle return value */
670
671                         if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
672                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
673                                 if (sound_result != MM_ERROR_NONE) {
674                                         LOGE("failed to release sound focus\n");
675                                         return MM_ERROR_POLICY_INTERNAL;
676                                 }
677                         }
678                 }
679                 break;
680
681         case MM_PLAYER_STATE_PLAYING:
682                 {
683                         /* try to get content metadata */
684                         if (!player->sent_bos) {
685                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
686                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
687                                  * legacy mmfw-player api */
688                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
689                         }
690
691                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
692                                 if (!player->sent_bos)
693                                         __mmplayer_handle_missed_plugin(player);
694                                 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
695                                 if (sound_result != MM_ERROR_NONE) {
696                                         // FIXME : need to check history
697                                         if (player->pipeline->videobin) {
698                                                 MMMessageParamType msg = {0, };
699
700                                                 LOGE("failed to go ahead because of video conflict\n");
701
702                                                 msg.union_type = MM_MSG_UNION_CODE;
703                                                 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
704                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
705
706                                                 _mmplayer_unrealize((MMHandleType)player);
707                                         } else {
708                                                 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
709                                                 _mmplayer_pause((MMHandleType)player);
710                                         }
711
712                                         return MM_ERROR_POLICY_INTERNAL;
713                                 }
714                         }
715
716                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
717                                 /* initialize because auto resume is done well. */
718                                 player->resumed_by_rewind = FALSE;
719                                 player->playback_rate = 1.0;
720                         }
721
722                         if (!player->sent_bos) {
723                                 /* check audio codec field is set or not
724                                  * we can get it from typefinder or codec's caps.
725                                  */
726                                 gchar *audio_codec = NULL;
727                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
728
729                                 /* The codec format can't be sent for audio only case like amr, mid etc.
730                                  * Because, parser don't make related TAG.
731                                  * So, if it's not set yet, fill it with found data.
732                                  */
733                                 if (!audio_codec) {
734                                         if (g_strrstr(player->type, "audio/midi"))
735                                                 audio_codec = g_strdup("MIDI");
736                                         else if (g_strrstr(player->type, "audio/x-amr"))
737                                                 audio_codec = g_strdup("AMR");
738                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
739                                                 audio_codec = g_strdup("AAC");
740                                         else
741                                                 audio_codec = g_strdup("unknown");
742                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
743
744                                         MMPLAYER_FREEIF(audio_codec);
745                                         mmf_attrs_commit(player->attrs);
746                                         LOGD("set audio codec type with caps\n");
747                                 }
748
749                                 post_bos = TRUE;
750                         }
751                 }
752                 break;
753
754         case MM_PLAYER_STATE_NONE:
755         default:
756                 LOGW("invalid target state, there is nothing to do.\n");
757                 break;
758         }
759
760
761         /* post message to application */
762         if (MMPLAYER_TARGET_STATE(player) == state) {
763                 /* fill the message with state of player */
764                 msg.union_type = MM_MSG_UNION_STATE;
765                 msg.state.previous = MMPLAYER_PREV_STATE(player);
766                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
767
768                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
769
770                 /* state changed by focus or resource callback */
771                 if (interrupted_by_focus || interrupted_by_resource) {
772                         if (interrupted_by_focus)
773                                 msg.state.code = player->sound_focus.focus_changed_msg;
774                         else if (interrupted_by_resource)
775                                 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
776                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
777                 } else { /* state changed by usecase */
778                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
779                 }
780         } else {
781                 LOGD("intermediate state, do nothing.\n");
782                 MMPLAYER_PRINT_STATE(player);
783                 return MM_ERROR_NONE;
784         }
785
786         if (post_bos) {
787                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
788                 player->sent_bos = TRUE;
789         }
790
791         return MM_ERROR_NONE;
792 }
793
794 static gpointer __mmplayer_next_play_thread(gpointer data)
795 {
796         mm_player_t* player = (mm_player_t*) data;
797         MMPlayerGstElement *mainbin = NULL;
798
799         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
800
801         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
802         while (!player->next_play_thread_exit) {
803                 LOGD("next play thread started. waiting for signal.\n");
804                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
805
806                 LOGD("reconfigure pipeline for gapless play.\n");
807
808                 if (player->next_play_thread_exit) {
809                         if (player->gapless.reconfigure) {
810                                 player->gapless.reconfigure = false;
811                                 MMPLAYER_PLAYBACK_UNLOCK(player);
812                         }
813                         LOGD("exiting gapless play thread\n");
814                         break;
815                 }
816
817                 mainbin = player->pipeline->mainbin;
818
819                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
820                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
821                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
822                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
823                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
824
825                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
826         }
827         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
828
829         return NULL;
830 }
831
832 static gpointer __mmplayer_repeat_thread(gpointer data)
833 {
834         mm_player_t* player = (mm_player_t*) data;
835         gboolean ret_value = FALSE;
836         MMHandleType attrs = 0;
837         gint count = 0;
838
839         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
840
841         MMPLAYER_REPEAT_THREAD_LOCK(player);
842         while (!player->repeat_thread_exit) {
843                 LOGD("repeat thread started. waiting for signal.\n");
844                 MMPLAYER_REPEAT_THREAD_WAIT(player);
845
846                 if (player->repeat_thread_exit) {
847                         LOGD("exiting repeat thread\n");
848                         break;
849                 }
850
851
852                 /* lock */
853                 MMPLAYER_CMD_LOCK(player);
854
855                 attrs = MMPLAYER_GET_ATTRS(player);
856
857                 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
858                         LOGE("can not get play count\n");
859                         MMPLAYER_CMD_UNLOCK(player);
860                         break;
861                 }
862
863                 if (player->section_repeat) {
864                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
865                 } else {
866                         if (player->playback_rate < 0.0) {
867                                 player->resumed_by_rewind = TRUE;
868                                 _mmplayer_set_mute((MMHandleType)player, 0);
869                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
870                         }
871
872                         ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
873                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
874                                 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
875
876                         /* initialize */
877                         player->sent_bos = FALSE;
878                 }
879
880                 if (!ret_value) {
881                         LOGE("failed to set position to zero for rewind\n");
882                         MMPLAYER_CMD_UNLOCK(player);
883                         continue;
884                 }
885
886                 /* decrease play count */
887                 if (count > 1) {
888                         /* we successeded to rewind. update play count and then wait for next EOS */
889                         count--;
890
891                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
892
893                         /* commit attribute */
894                         if (mmf_attrs_commit(attrs))
895                                 LOGE("failed to commit attribute\n");
896                 }
897
898                 /* unlock */
899                 MMPLAYER_CMD_UNLOCK(player);
900         }
901
902         MMPLAYER_REPEAT_THREAD_UNLOCK(player);
903         return NULL;
904 }
905
906 static void
907 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
908 {
909         MMHandleType attrs = 0;
910         guint64 data_size = 0;
911         gchar* path = NULL;
912         unsigned long pos_msec = 0;
913         struct stat sb;
914
915         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
916
917         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
918
919         attrs = MMPLAYER_GET_ATTRS(player);
920         if (!attrs) {
921                 LOGE("fail to get attributes.\n");
922                 return;
923         }
924
925         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
926                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
927
928                 if (stat(path, &sb) == 0)
929                         data_size = (guint64)sb.st_size;
930         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
931                 data_size = player->http_content_size;
932
933         __mm_player_streaming_buffering(player->streamer,
934                                                                                 buffering_msg,
935                                                                                 data_size,
936                                                                                 player->last_position,
937                                                                                 player->duration);
938
939         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
940
941         return;
942 }
943
944 static int
945 __mmplayer_handle_buffering_message(mm_player_t* player)
946 {
947         int ret = MM_ERROR_NONE;
948         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
949         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
950         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
951         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
952
953         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
954                 LOGW("do nothing for buffering msg\n");
955                 ret = MM_ERROR_PLAYER_INVALID_STATE;
956                 goto exit;
957         }
958
959         prev_state = MMPLAYER_PREV_STATE(player);
960         current_state = MMPLAYER_CURRENT_STATE(player);
961         target_state = MMPLAYER_TARGET_STATE(player);
962         pending_state = MMPLAYER_PENDING_STATE(player);
963
964         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
965                 MMPLAYER_STATE_GET_NAME(prev_state),
966                 MMPLAYER_STATE_GET_NAME(current_state),
967                 MMPLAYER_STATE_GET_NAME(pending_state),
968                 MMPLAYER_STATE_GET_NAME(target_state),
969                 player->streamer->is_buffering);
970
971         if (!player->streamer->is_buffering) {
972                 /* NOTE : if buffering has done, player has to go to target state. */
973                 switch (target_state) {
974                 case MM_PLAYER_STATE_PAUSED:
975                         {
976                                 switch (pending_state) {
977                                 case MM_PLAYER_STATE_PLAYING:
978                                         __gst_pause(player, TRUE);
979                                         break;
980
981                                 case MM_PLAYER_STATE_PAUSED:
982                                         LOGD("player is already going to paused state, there is nothing to do.\n");
983                                         break;
984
985                                 case MM_PLAYER_STATE_NONE:
986                                 case MM_PLAYER_STATE_NULL:
987                                 case MM_PLAYER_STATE_READY:
988                                 default:
989                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
990                                         break;
991                                 }
992                         }
993                         break;
994
995                 case MM_PLAYER_STATE_PLAYING:
996                         {
997                                 switch (pending_state) {
998                                 case MM_PLAYER_STATE_NONE:
999                                         {
1000                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1001                                                         __gst_resume(player, TRUE);
1002                                         }
1003                                         break;
1004
1005                                 case MM_PLAYER_STATE_PAUSED:
1006                                         /* NOTE: It should be worked as asynchronously.
1007                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1008                                          */
1009                                         __gst_resume(player, TRUE);
1010                                         break;
1011
1012                                 case MM_PLAYER_STATE_PLAYING:
1013                                         LOGD("player is already going to playing state, there is nothing to do.\n");
1014                                         break;
1015
1016                                 case MM_PLAYER_STATE_NULL:
1017                                 case MM_PLAYER_STATE_READY:
1018                                 default:
1019                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1020                                         break;
1021                                 }
1022                         }
1023                         break;
1024
1025                 case MM_PLAYER_STATE_NULL:
1026                 case MM_PLAYER_STATE_READY:
1027                 case MM_PLAYER_STATE_NONE:
1028                 default:
1029                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1030                         break;
1031                 }
1032         } else {
1033                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1034                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1035                  */
1036                 switch (pending_state) {
1037                 case MM_PLAYER_STATE_NONE:
1038                         {
1039                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1040                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1041                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1042                                                 LOGD("set pause state during buffering\n");
1043                                                 __gst_pause( player, TRUE );
1044                                         }
1045                                 }
1046                         }
1047                         break;
1048
1049                 case MM_PLAYER_STATE_PLAYING:
1050                         /* rtsp streaming pause makes rtsp server stop sending data. */
1051                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1052                                 __gst_pause ( player, TRUE );
1053                         }
1054                         break;
1055
1056                 case MM_PLAYER_STATE_PAUSED:
1057                         break;
1058
1059                 case MM_PLAYER_STATE_NULL:
1060                 case MM_PLAYER_STATE_READY:
1061                 default:
1062                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1063                         break;
1064                 }
1065         }
1066
1067 exit:
1068         return ret;
1069 }
1070
1071 static void
1072 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1073 {
1074         MMPlayerGstElement *textbin;
1075         MMPLAYER_FENTER();
1076
1077         MMPLAYER_RETURN_IF_FAIL(player &&
1078                                         player->pipeline &&
1079                                         player->pipeline->textbin);
1080
1081         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1082
1083         textbin = player->pipeline->textbin;
1084
1085         if (is_drop) {
1086                 LOGD("Drop subtitle text after getting EOS\n");
1087
1088                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1089                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1090
1091                 player->is_subtitle_force_drop = TRUE;
1092         } else {
1093                 if (player->is_subtitle_force_drop == TRUE) {
1094                         LOGD("Enable subtitle data path without drop\n");
1095
1096                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1097                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1098
1099                         LOGD("non-connected with external display");
1100
1101                         player->is_subtitle_force_drop = FALSE;
1102                 }
1103         }
1104 }
1105
1106 static VariantData *
1107 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1108 {
1109         VariantData *var_info = NULL;
1110         g_return_val_if_fail (self != NULL, NULL);
1111
1112         var_info = g_new0(VariantData, 1);
1113         if (!var_info) return NULL;
1114         var_info->bandwidth = self->bandwidth;
1115         var_info->width = self->width;
1116         var_info->height = self->height;
1117         return var_info;
1118 }
1119
1120 static gboolean
1121 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
1122 {
1123         mm_player_t* player = (mm_player_t*) data;
1124         gboolean ret = TRUE;
1125         static gboolean async_done = FALSE;
1126
1127         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1128         MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1129
1130         switch (GST_MESSAGE_TYPE(msg)) {
1131         case GST_MESSAGE_UNKNOWN:
1132                 LOGD("unknown message received\n");
1133                 break;
1134
1135         case GST_MESSAGE_EOS:
1136                 {
1137                         MMHandleType attrs = 0;
1138                         gint count = 0;
1139
1140                         LOGD("GST_MESSAGE_EOS received\n");
1141
1142                         /* NOTE : EOS event is comming multiple time. watch out it */
1143                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1144                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1145                                 LOGD("EOS received on non-playing state. ignoring it\n");
1146                                 break;
1147                         }
1148
1149                         if (player->pipeline) {
1150                                 if (player->pipeline->textbin)
1151                                         __mmplayer_drop_subtitle(player, TRUE);
1152
1153                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1154                                         GstPad *pad = NULL;
1155
1156                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1157
1158                                         LOGD("release audio callback\n");
1159
1160                                         /* release audio callback */
1161                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1162                                         player->audio_cb_probe_id = 0;
1163                                         /* audio callback should be free because it can be called even though probe remove.*/
1164                                         player->audio_stream_cb = NULL;
1165                                         player->audio_stream_cb_user_param = NULL;
1166
1167                                 }
1168                         }
1169                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1170                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1171
1172                         /* rewind if repeat count is greater then zero */
1173                         /* get play count */
1174                         attrs = MMPLAYER_GET_ATTRS(player);
1175
1176                         if (attrs) {
1177                                 gboolean smooth_repeat = FALSE;
1178
1179                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1180                                 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1181
1182                                 player->play_count = count;
1183
1184                                 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1185
1186                                 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1187                                         if (smooth_repeat) {
1188                                                 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1189
1190                                                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1191
1192                                                 break;
1193                                         } else {
1194                                                 gint ret_value = 0;
1195
1196                                                 if (player->section_repeat) {
1197                                                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1198                                                 } else {
1199                                                         if (player->playback_rate < 0.0) {
1200                                                                 player->resumed_by_rewind = TRUE;
1201                                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1202                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1203                                                         }
1204
1205                                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1206
1207                                                         /* initialize */
1208                                                         player->sent_bos = FALSE;
1209                                                 }
1210
1211                                                 if (MM_ERROR_NONE != ret_value)
1212                                                         LOGE("failed to set position to zero for rewind\n");
1213
1214                                                 /* not posting eos when repeating */
1215                                                 break;
1216                                         }
1217                                 }
1218                         }
1219
1220                         if (player->pipeline)
1221                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1222
1223                         /* post eos message to application */
1224                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1225
1226                         /* reset last position */
1227                         player->last_position = 0;
1228                 }
1229                 break;
1230
1231         case GST_MESSAGE_ERROR:
1232                 {
1233                         GError *error = NULL;
1234                         gchar* debug = NULL;
1235
1236                         /* generating debug info before returning error */
1237                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1238
1239                         /* get error code */
1240                         gst_message_parse_error(msg, &error, &debug);
1241
1242                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1243                                 /* Note : the streaming error from the streaming source is handled
1244                                  *   using __mmplayer_handle_streaming_error.
1245                                  */
1246                                 __mmplayer_handle_streaming_error(player, msg);
1247
1248                                 /* dump state of all element */
1249                                 __mmplayer_dump_pipeline_state(player);
1250                         } else {
1251                                 /* traslate gst error code to msl error code. then post it
1252                                  * to application if needed
1253                                  */
1254                                 __mmplayer_handle_gst_error(player, msg, error);
1255
1256                                 if (debug)
1257                                         LOGE("error debug : %s", debug);
1258                         }
1259
1260                         if (MMPLAYER_IS_HTTP_PD(player))
1261                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1262
1263                         MMPLAYER_FREEIF(debug);
1264                         g_error_free(error);
1265                 }
1266                 break;
1267
1268         case GST_MESSAGE_WARNING:
1269                 {
1270                         char* debug = NULL;
1271                         GError* error = NULL;
1272
1273                         gst_message_parse_warning(msg, &error, &debug);
1274
1275                         LOGD("warning : %s\n", error->message);
1276                         LOGD("debug : %s\n", debug);
1277
1278                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1279
1280                         MMPLAYER_FREEIF(debug);
1281                         g_error_free(error);
1282                 }
1283                 break;
1284
1285         case GST_MESSAGE_TAG:
1286                 {
1287                         LOGD("GST_MESSAGE_TAG\n");
1288                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1289                                 LOGW("failed to extract tags from gstmessage\n");
1290                 }
1291                 break;
1292
1293         case GST_MESSAGE_BUFFERING:
1294                 {
1295                         MMMessageParamType msg_param = {0, };
1296                         int bRet = MM_ERROR_NONE;
1297
1298                         if (!MMPLAYER_IS_STREAMING(player))
1299                                 break;
1300
1301                         /* ignore the prev buffering message */
1302                         if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1303                                 gint buffer_percent = 0;
1304
1305                                 gst_message_parse_buffering(msg, &buffer_percent);
1306
1307                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1308                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1309                                         player->streamer->is_buffering_done = FALSE;
1310                                 }
1311
1312                                 break;
1313                         }
1314
1315                         MMPLAYER_CMD_LOCK(player);
1316                         __mmplayer_update_buffer_setting(player, msg);
1317
1318                         bRet = __mmplayer_handle_buffering_message(player);
1319
1320                         if (bRet == MM_ERROR_NONE) {
1321                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1322                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1323
1324                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1325                                         player->pending_resume &&
1326                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1327
1328                                         player->is_external_subtitle_added_now = FALSE;
1329                                         player->pending_resume = FALSE;
1330                                         _mmplayer_resume((MMHandleType)player);
1331                                 }
1332
1333                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1334                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1335
1336                                         if (player->doing_seek) {
1337                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1338                                                         player->doing_seek = FALSE;
1339                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1340                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1341                                                         async_done = TRUE;
1342                                                 }
1343                                         }
1344                                 }
1345                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1346                                 if (!player->streamer) {
1347                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1348                                         MMPLAYER_CMD_UNLOCK(player);
1349                                         break;
1350                                 }
1351
1352                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1353
1354                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1355                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1356
1357                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1358                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1359                                                 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1360                                         } else {
1361                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1362                                         }
1363                                 } else {
1364                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1365                                         MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1366                                 }
1367                         }
1368                         MMPLAYER_CMD_UNLOCK(player);
1369                 }
1370                 break;
1371
1372         case GST_MESSAGE_STATE_CHANGED:
1373                 {
1374                         MMPlayerGstElement *mainbin;
1375                         const GValue *voldstate, *vnewstate, *vpending;
1376                         GstState oldstate = GST_STATE_NULL;
1377                         GstState newstate = GST_STATE_NULL;
1378                         GstState pending = GST_STATE_NULL;
1379
1380                         if (!(player->pipeline && player->pipeline->mainbin)) {
1381                                 LOGE("player pipeline handle is null");
1382                                 break;
1383                         }
1384
1385                         mainbin = player->pipeline->mainbin;
1386
1387                         /* we only handle messages from pipeline */
1388                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1389                                 break;
1390
1391                         /* get state info from msg */
1392                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1393                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1394                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1395
1396                         if (!voldstate || !vnewstate) {
1397                                 LOGE("received msg has wrong format.");
1398                                 break;
1399                         }
1400
1401                         oldstate = (GstState)voldstate->data[0].v_int;
1402                         newstate = (GstState)vnewstate->data[0].v_int;
1403                         if (vpending)
1404                                 pending = (GstState)vpending->data[0].v_int;
1405
1406                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1407                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1408                                 gst_element_state_get_name((GstState)oldstate),
1409                                 gst_element_state_get_name((GstState)newstate),
1410                                 gst_element_state_get_name((GstState)pending));
1411
1412                         if (newstate == GST_STATE_PLAYING) {
1413                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1414
1415                                         int retVal = MM_ERROR_NONE;
1416                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1417
1418                                         retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1419
1420                                         if (MM_ERROR_NONE != retVal)
1421                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1422
1423                                         player->pending_seek.is_pending = FALSE;
1424                                 }
1425                         }
1426
1427                         if (oldstate == newstate) {
1428                                 LOGD("pipeline reports state transition to old state");
1429                                 break;
1430                         }
1431
1432                         switch (newstate) {
1433                         case GST_STATE_VOID_PENDING:
1434                                 break;
1435
1436                         case GST_STATE_NULL:
1437                                 break;
1438
1439                         case GST_STATE_READY:
1440                                 break;
1441
1442                         case GST_STATE_PAUSED:
1443                                 {
1444                                         gboolean prepare_async = FALSE;
1445
1446                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1447                                                 __mmplayer_configure_audio_callback(player);
1448
1449                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1450                                                 // managed prepare async case
1451                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1452                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1453                                         }
1454
1455                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1456                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1457
1458                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1459                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1460                                                                 player->total_maximum_bitrate, player->total_bitrate);
1461                                         }
1462                                 }
1463                                 break;
1464
1465                         case GST_STATE_PLAYING:
1466                                 {
1467                                         if (MMPLAYER_IS_STREAMING(player)) {
1468                                                 // managed prepare async case when buffering is completed
1469                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1470                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1471                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1472                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1473
1474                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1475
1476                                                         LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1477                                                         if (player->streamer->buffering_percent < 100) {
1478
1479                                                                 MMMessageParamType msg_param = {0, };
1480                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1481
1482                                                                 msg_param.connection.buffering = 100;
1483                                                                 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1484                                                         }
1485                                                 }
1486                                         }
1487
1488                                         if (player->gapless.stream_changed) {
1489                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1490                                                 player->gapless.stream_changed = FALSE;
1491                                         }
1492
1493                                         if (player->doing_seek && async_done) {
1494                                                 player->doing_seek = FALSE;
1495                                                 async_done = FALSE;
1496                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1497                                         }
1498                                 }
1499                                 break;
1500
1501                         default:
1502                                 break;
1503                         }
1504                 }
1505                 break;
1506
1507         case GST_MESSAGE_CLOCK_LOST:
1508                         {
1509                                 GstClock *clock = NULL;
1510                                 gboolean need_new_clock = FALSE;
1511
1512                                 gst_message_parse_clock_lost(msg, &clock);
1513                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1514
1515                                 if (!player->videodec_linked)
1516                                         need_new_clock = TRUE;
1517                                 else if (!player->ini.use_system_clock)
1518                                         need_new_clock = TRUE;
1519
1520                                 if (need_new_clock) {
1521                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1522                                         __gst_pause(player, FALSE);
1523                                         __gst_resume(player, FALSE);
1524                                 }
1525                         }
1526                         break;
1527
1528         case GST_MESSAGE_NEW_CLOCK:
1529                         {
1530                                 GstClock *clock = NULL;
1531                                 gst_message_parse_new_clock(msg, &clock);
1532                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1533                         }
1534                         break;
1535
1536         case GST_MESSAGE_ELEMENT:
1537                         {
1538                                 const gchar *structure_name;
1539                                 gint count = 0, idx = 0;
1540                                 MMHandleType attrs = 0;
1541
1542                                 attrs = MMPLAYER_GET_ATTRS(player);
1543                                 if (!attrs) {
1544                                         LOGE("cannot get content attribute");
1545                                         ret = FALSE;
1546                                         break;
1547                                 }
1548
1549                                 if (gst_message_get_structure(msg) == NULL)
1550                                         break;
1551
1552                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1553                                 if (!structure_name)
1554                                         break;
1555
1556                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1557
1558                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1559                                         const GValue *var_info = NULL;
1560
1561                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1562                                         if (var_info != NULL) {
1563                                                 if (player->adaptive_info.var_list)
1564                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1565
1566                                                 /* share addr or copy the list */
1567                                                 player->adaptive_info.var_list =
1568                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1569
1570                                                 count = g_list_length(player->adaptive_info.var_list);
1571                                                 if (count > 0) {
1572                                                         VariantData *temp = NULL;
1573
1574                                                         /* print out for debug */
1575                                                         LOGD("num of variant_info %d", count);
1576                                                         for (idx = 0; idx < count; idx++) {
1577                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1578                                                                 if (temp)
1579                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1580                                                         }
1581                                                 }
1582                                         }
1583                                 }
1584
1585                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1586                                         gint num_buffers = 0;
1587                                         gint extra_num_buffers = 0;
1588
1589                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1590                                                 player->video_num_buffers = num_buffers;
1591                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1592                                         }
1593
1594                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1595                                                 player->video_extra_num_buffers = extra_num_buffers;
1596                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1597                                         }
1598                                         break;
1599                                 }
1600
1601                                 if (!strcmp(structure_name, "Language_list")) {
1602                                         const GValue *lang_list = NULL;
1603                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1604                                         if (lang_list != NULL) {
1605                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1606                                                 if (count > 1)
1607                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1608                                         }
1609                                 }
1610
1611                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1612                                         const GValue *lang_list = NULL;
1613                                         MMPlayerLangStruct *temp = NULL;
1614
1615                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1616                                         if (lang_list != NULL) {
1617                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1618                                                 if (count) {
1619                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1620                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1621                                                         if (mmf_attrs_commit(attrs))
1622                                                           LOGE("failed to commit.\n");
1623                                                         LOGD("Total subtitle tracks = %d \n", count);
1624                                                 }
1625                                                 while (count) {
1626                                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1627                                                         if (temp)
1628                                                                 LOGD("value of lang_key is %s and lang_code is %s",
1629                                                                                         temp->language_key, temp->language_code);
1630                                                         count--;
1631                                                 }
1632                                         }
1633                                 }
1634
1635                                 /* custom message */
1636                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1637                                         MMMessageParamType msg_param = {0,};
1638                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1639                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1640                                 }
1641
1642                                 /* custom message for RTSP attribute :
1643                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1644                                     sdp which has contents info is received when rtsp connection is opened.
1645                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1646                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1647
1648                                         gchar           *audio_codec = NULL;
1649                                         gchar           *video_codec = NULL;
1650                                         gchar           *video_frame_size = NULL;
1651
1652                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1653                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1654                                         __mmplayer_get_stream_service_type(player);
1655                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1656
1657                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1658                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1659                                         if (audio_codec)
1660                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1661
1662                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1663                                         LOGD("rtsp_video_codec : %s", video_codec);
1664                                         if (video_codec)
1665                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1666
1667                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1668                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1669                                         if (video_frame_size) {
1670
1671                                                 char *seperator = strchr(video_frame_size, '-');
1672                                                 if (seperator) {
1673
1674                                                         char video_width[10]={0,};
1675                                                         int frame_size_len = strlen(video_frame_size);
1676                                                         int separtor_len = strlen(seperator);
1677
1678                                                         strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1679                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1680
1681                                                         seperator++;
1682                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1683                                                 }
1684                                         }
1685
1686                                         if (mmf_attrs_commit(attrs))
1687                                                 LOGE("failed to commit.\n");
1688                                 }
1689                         }
1690                         break;
1691
1692         case GST_MESSAGE_DURATION_CHANGED:
1693                 {
1694                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1695                         ret = __mmplayer_gst_handle_duration(player, msg);
1696                         if (!ret)
1697                                 LOGW("failed to update duration");
1698                 }
1699
1700                 break;
1701
1702         case GST_MESSAGE_ASYNC_START:
1703                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1704                 break;
1705
1706         case GST_MESSAGE_ASYNC_DONE:
1707                 {
1708                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1709
1710                         /* we only handle messages from pipeline */
1711                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1712                                 break;
1713
1714                         if (player->doing_seek) {
1715                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1716                                         player->doing_seek = FALSE;
1717                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1718                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1719                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1720                                                 (player->streamer) &&
1721                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1722                                                 (player->streamer->is_buffering == FALSE)) {
1723                                                 GstQuery *query = NULL;
1724                                                 gboolean busy = FALSE;
1725                                                 gint percent = 0;
1726
1727                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1728                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1729                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1730                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1731                                                         gst_query_unref(query);
1732
1733                                                         LOGD("buffered percent(%s): %d\n",
1734                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1735                                                 }
1736
1737                                                 if (percent >= 100) {
1738                                                         player->streamer->is_buffering = FALSE;
1739                                                         __mmplayer_handle_buffering_message(player);
1740                                                 }
1741                                         }
1742
1743                                         async_done = TRUE;
1744                                 }
1745                         }
1746                 }
1747                 break;
1748
1749         #if 0 /* delete unnecessary logs */
1750         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1751         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1752         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1753         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1754         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1755         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1756         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1757         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1758         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1759         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1760         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1761         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1762         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1763         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1764         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1765         #endif
1766
1767         default:
1768                 break;
1769         }
1770
1771         /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1772          * gst_element_post_message api takes ownership of the message.
1773          */
1774         //gst_message_unref(msg);
1775
1776         return ret;
1777 }
1778
1779 static gboolean
1780 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1781 {
1782         gint64 bytes = 0;
1783
1784         MMPLAYER_FENTER();
1785
1786         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1787         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1788
1789         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1790                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1791                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1792
1793                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1794                         LOGD("data total size of http content: %lld", bytes);
1795                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1796                 }
1797         } else
1798                 /* handling audio clip which has vbr. means duration is keep changing */
1799                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1800
1801         MMPLAYER_FLEAVE();
1802
1803         return TRUE;
1804 }
1805
1806
1807 static gboolean
1808 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1809 {
1810
1811 /* macro for better code readability */
1812 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1813 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1814         if (string != NULL) {\
1815                 SECURE_LOGD("update tag string : %s\n", string); \
1816                 mm_attrs_set_string_by_name(attribute, playertag, string); \
1817                 g_free(string);\
1818                 string = NULL;\
1819         } \
1820 }
1821
1822 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1823 do {    \
1824         GstSample *sample = NULL;\
1825         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1826                 GstMapInfo info = GST_MAP_INFO_INIT;\
1827                 buffer = gst_sample_get_buffer(sample);\
1828                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1829                         LOGD("failed to get image data from tag");\
1830                         return FALSE;\
1831                 } \
1832                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1833                 MMPLAYER_FREEIF(player->album_art);\
1834                 player->album_art = (gchar *)g_malloc(info.size);\
1835                 if (player->album_art) {\
1836                         memcpy(player->album_art, info.data, info.size);\
1837                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1838                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1839                                 msg_param.data = (void *)player->album_art;\
1840                                 msg_param.size = info.size;\
1841                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1842                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1843                         } \
1844                 } \
1845                 gst_buffer_unmap(buffer, &info);\
1846         }       \
1847 } while (0)
1848
1849 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1850 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1851         if (v_uint) {\
1852                 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1853                         if (player->updated_bitrate_count == 0) \
1854                                 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1855                         if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1856                                 player->bitrate[player->updated_bitrate_count] = v_uint;\
1857                                 player->total_bitrate += player->bitrate[player->updated_bitrate_count]; \
1858                                 player->updated_bitrate_count++; \
1859                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1860                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1861                         } \
1862                 } \
1863                 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1864                         if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1865                                 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1866                                 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1867                                 player->updated_maximum_bitrate_count++; \
1868                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1869                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1870                         } \
1871                 } else\
1872                         mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1873                 v_uint = 0;\
1874         } \
1875 }
1876
1877 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1878 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1879         if (date != NULL) {\
1880                 string = g_strdup_printf("%d", g_date_get_year(date));\
1881                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1882                 SECURE_LOGD("metainfo year : %s\n", string);\
1883                 MMPLAYER_FREEIF(string);\
1884                 g_date_free(date);\
1885         } \
1886 }
1887
1888 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1889 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1890         if (datetime != NULL) {\
1891                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1892                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1893                 SECURE_LOGD("metainfo year : %s\n", string);\
1894                 MMPLAYER_FREEIF(string);\
1895                 gst_date_time_unref(datetime);\
1896         } \
1897 }
1898
1899 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1900 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1901         if (v_uint64) {\
1902                 /* FIXIT : don't know how to store date */\
1903                 g_assert(1);\
1904                 v_uint64 = 0;\
1905         } \
1906 }
1907
1908 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1909 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1910         if (v_double) {\
1911                 /* FIXIT : don't know how to store date */\
1912                 g_assert(1);\
1913                 v_double = 0;\
1914         } \
1915 }
1916
1917         /* function start */
1918         GstTagList* tag_list = NULL;
1919
1920         MMHandleType attrs = 0;
1921
1922         char *string = NULL;
1923         guint v_uint = 0;
1924         GDate *date = NULL;
1925         GstDateTime *datetime = NULL;
1926         /* album cover */
1927         GstBuffer *buffer = NULL;
1928         gint index = 0;
1929         MMMessageParamType msg_param = {0, };
1930
1931         /* currently not used. but those are needed for above macro */
1932         //guint64 v_uint64 = 0;
1933         //gdouble v_double = 0;
1934
1935         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1936
1937         attrs = MMPLAYER_GET_ATTRS(player);
1938
1939         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1940
1941         /* get tag list from gst message */
1942         gst_message_parse_tag(msg, &tag_list);
1943
1944         /* store tags to player attributes */
1945         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1946         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1947         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1948         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1949         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1950         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1951         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1952         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1953         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1954         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1955         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1956         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1957         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1958         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1959         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1960         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1961         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1962         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1963         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1964         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1965         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1966         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1967         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1968         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1969         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1970         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1971         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1972         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1973         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1974         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1975         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1976         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1977         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1978         MMPLAYER_UPDATE_TAG_LOCK(player);
1979         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1980         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1981         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1982         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1983         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1984         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1985         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1986         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1987         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1988         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1989         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1990         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1991         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1992         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1993         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1994
1995         if (mmf_attrs_commit(attrs))
1996                 LOGE("failed to commit.\n");
1997
1998         gst_tag_list_free(tag_list);
1999
2000         return TRUE;
2001 }
2002
2003 static void
2004 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2005 {
2006         mm_player_t* player = (mm_player_t*) data;
2007
2008         MMPLAYER_FENTER();
2009
2010         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2011           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2012           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2013           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2014
2015           * [1] audio and video will be dumped with filesink.
2016           * [2] autoplugging is done by just using pad caps.
2017           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2018           * and the video will be dumped via filesink.
2019           */
2020         if (player->num_dynamic_pad == 0) {
2021                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2022
2023                 if (!__mmplayer_gst_remove_fakesink(player,
2024                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2025                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2026                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2027                          * source element are not same. To overcome this situation, this function will called
2028                          * several places and several times. Therefore, this is not an error case.
2029                          */
2030                         return;
2031         }
2032
2033         /* create dot before error-return. for debugging */
2034         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2035
2036         player->no_more_pad = TRUE;
2037
2038         MMPLAYER_FLEAVE();
2039 }
2040
2041 static gboolean
2042 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2043 {
2044         GstElement* parent = NULL;
2045
2046         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2047
2048         /* if we have no fakesink. this meas we are using decodebin which doesn'
2049         t need to add extra fakesink */
2050         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2051
2052         /* lock */
2053         MMPLAYER_FSINK_LOCK(player);
2054
2055         if (!fakesink->gst)
2056                 goto ERROR;
2057
2058         /* get parent of fakesink */
2059         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2060         if (!parent) {
2061                 LOGD("fakesink already removed\n");
2062                 goto ERROR;
2063         }
2064
2065         gst_element_set_locked_state(fakesink->gst, TRUE);
2066
2067         /* setting the state to NULL never returns async
2068          * so no need to wait for completion of state transiton
2069          */
2070         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2071                 LOGE("fakesink state change failure!\n");
2072                 /* FIXIT : should I return here? or try to proceed to next? */
2073                 /* return FALSE; */
2074
2075         /* remove fakesink from it's parent */
2076         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2077                 LOGE("failed to remove fakesink\n");
2078
2079                 gst_object_unref(parent);
2080
2081                 goto ERROR;
2082         }
2083
2084         gst_object_unref(parent);
2085
2086         LOGD("state-holder removed\n");
2087
2088         gst_element_set_locked_state(fakesink->gst, FALSE);
2089
2090         MMPLAYER_FSINK_UNLOCK(player);
2091         return TRUE;
2092
2093 ERROR:
2094         if (fakesink->gst)
2095                 gst_element_set_locked_state(fakesink->gst, FALSE);
2096
2097         MMPLAYER_FSINK_UNLOCK(player);
2098         return FALSE;
2099 }
2100
2101
2102 static void
2103 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2104 {
2105         GstPad *sinkpad = NULL;
2106         GstCaps* caps = NULL;
2107         GstElement* new_element = NULL;
2108         GstStructure* str = NULL;
2109         const gchar* name = NULL;
2110
2111         mm_player_t* player = (mm_player_t*) data;
2112
2113         MMPLAYER_FENTER();
2114
2115         MMPLAYER_RETURN_IF_FAIL(element && pad);
2116         MMPLAYER_RETURN_IF_FAIL(player &&
2117                                         player->pipeline &&
2118                                         player->pipeline->mainbin);
2119
2120
2121         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2122          * num_dynamic_pad will decreased after creating a sinkbin.
2123          */
2124         player->num_dynamic_pad++;
2125         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2126
2127         caps = gst_pad_query_caps(pad, NULL);
2128
2129         MMPLAYER_CHECK_NULL(caps);
2130
2131         /* clear  previous result*/
2132         player->have_dynamic_pad = FALSE;
2133
2134         str = gst_caps_get_structure(caps, 0);
2135
2136         if (!str) {
2137                 LOGE("cannot get structure from caps.\n");
2138                 goto ERROR;
2139         }
2140
2141         name = gst_structure_get_name(str);
2142         if (!name) {
2143                 LOGE("cannot get mimetype from structure.\n");
2144                 goto ERROR;
2145         }
2146
2147         if (strstr(name, "video")) {
2148                 gint stype = 0;
2149                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2150
2151                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2152                         if (player->v_stream_caps) {
2153                                 gst_caps_unref(player->v_stream_caps);
2154                                 player->v_stream_caps = NULL;
2155                         }
2156
2157                         new_element = gst_element_factory_make("fakesink", NULL);
2158                         player->num_dynamic_pad--;
2159                         goto NEW_ELEMENT;
2160                 }
2161         }
2162
2163         /* clear  previous result*/
2164         player->have_dynamic_pad = FALSE;
2165
2166         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2167                 LOGE("failed to autoplug for caps");
2168                 goto ERROR;
2169         }
2170
2171         /* check if there's dynamic pad*/
2172         if (player->have_dynamic_pad) {
2173                 LOGE("using pad caps assums there's no dynamic pad !\n");
2174                 goto ERROR;
2175         }
2176
2177         gst_caps_unref(caps);
2178         caps = NULL;
2179
2180 NEW_ELEMENT:
2181
2182         /* excute new_element if created*/
2183         if (new_element) {
2184                 LOGD("adding new element to pipeline\n");
2185
2186                 /* set state to READY before add to bin */
2187                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2188
2189                 /* add new element to the pipeline */
2190                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2191                         LOGE("failed to add autoplug element to bin\n");
2192                         goto ERROR;
2193                 }
2194
2195                 /* get pad from element */
2196                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2197                 if (!sinkpad) {
2198                         LOGE("failed to get sinkpad from autoplug element\n");
2199                         goto ERROR;
2200                 }
2201
2202                 /* link it */
2203                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2204                         LOGE("failed to link autoplug element\n");
2205                         goto ERROR;
2206                 }
2207
2208                 gst_object_unref(sinkpad);
2209                 sinkpad = NULL;
2210
2211                 /* run. setting PLAYING here since streamming source is live source */
2212                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2213         }
2214
2215         MMPLAYER_FLEAVE();
2216
2217         return;
2218
2219 STATE_CHANGE_FAILED:
2220 ERROR:
2221         /* FIXIT : take care if new_element has already added to pipeline */
2222         if (new_element)
2223                 gst_object_unref(GST_OBJECT(new_element));
2224
2225         if (sinkpad)
2226                 gst_object_unref(GST_OBJECT(sinkpad));
2227
2228         if (caps)
2229                 gst_object_unref(GST_OBJECT(caps));
2230
2231         /* FIXIT : how to inform this error to MSL ????? */
2232         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2233          * then post an error to application
2234          */
2235 }
2236
2237
2238
2239 /* FIXIT : check indent */
2240 #if 0
2241 static void
2242 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2243 {
2244         GstPad *sinkpad = NULL;
2245         GstCaps* caps = NULL;
2246         GstElement* new_element = NULL;
2247         enum MainElementID element_id = MMPLAYER_M_NUM;
2248
2249         mm_player_t* player = (mm_player_t*) data;
2250
2251         MMPLAYER_FENTER();
2252
2253         MMPLAYER_RETURN_IF_FAIL(element && pad);
2254         MMPLAYER_RETURN_IF_FAIL(player &&
2255                 player->pipeline &&
2256                 player->pipeline->mainbin);
2257
2258         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2259
2260         {
2261                 LOGD("using pad caps to autopluging instead of doing typefind\n");
2262                 caps = gst_pad_query_caps(pad);
2263                 MMPLAYER_CHECK_NULL(caps);
2264                 /* clear  previous result*/
2265                 player->have_dynamic_pad = FALSE;
2266                 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2267                 if (!new_element) {
2268                         LOGE("failed to create wfd rtp depay element\n");
2269                         goto ERROR;
2270                 }
2271                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2272                 /* add new element to the pipeline */
2273                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2274                         LOGD("failed to add autoplug element to bin\n");
2275                         goto ERROR;
2276                 }
2277                 /* get pad from element */
2278                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2279                 if (!sinkpad) {
2280                         LOGD("failed to get sinkpad from autoplug element\n");
2281                         goto ERROR;
2282                 }
2283                 /* link it */
2284                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2285                         LOGD("failed to link autoplug element\n");
2286                         goto ERROR;
2287                 }
2288                 gst_object_unref(sinkpad);
2289                 sinkpad = NULL;
2290                 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2291                 caps = gst_pad_query_caps(pad);
2292                 MMPLAYER_CHECK_NULL(caps);
2293                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2294                 /* create typefind */
2295                 new_element = gst_element_factory_make("typefind", NULL);
2296                 if (!new_element) {
2297                         LOGD("failed to create typefind\n");
2298                         goto ERROR;
2299                 }
2300
2301                 MMPLAYER_SIGNAL_CONNECT(player,
2302                         G_OBJECT(new_element),
2303                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2304                         "have-type",
2305                         G_CALLBACK(__mmplayer_typefind_have_type),
2306                         (gpointer)player);
2307
2308                 player->have_dynamic_pad = FALSE;
2309         }
2310
2311         /* excute new_element if created*/
2312         if (new_element) {
2313                 LOGD("adding new element to pipeline\n");
2314
2315                 /* set state to READY before add to bin */
2316                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2317
2318                 /* add new element to the pipeline */
2319                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2320                         LOGD("failed to add autoplug element to bin\n");
2321                         goto ERROR;
2322                 }
2323
2324                 /* get pad from element */
2325                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2326                 if (!sinkpad) {
2327                         LOGD("failed to get sinkpad from autoplug element\n");
2328                         goto ERROR;
2329                 }
2330
2331                 /* link it */
2332                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2333                         LOGD("failed to link autoplug element\n");
2334                         goto ERROR;
2335                 }
2336
2337                 gst_object_unref(sinkpad);
2338                 sinkpad = NULL;
2339
2340                 /* run. setting PLAYING here since streamming source is live source */
2341                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2342         }
2343
2344         /* store handle to futher manipulation */
2345         player->pipeline->mainbin[element_id].id = element_id;
2346         player->pipeline->mainbin[element_id].gst = new_element;
2347
2348         MMPLAYER_FLEAVE();
2349
2350         return;
2351
2352 STATE_CHANGE_FAILED:
2353 ERROR:
2354         /* FIXIT : take care if new_element has already added to pipeline */
2355         if (new_element)
2356                 gst_object_unref(GST_OBJECT(new_element));
2357
2358         if (sinkpad)
2359                 gst_object_unref(GST_OBJECT(sinkpad));
2360
2361         if (caps)
2362                 gst_object_unref(GST_OBJECT(caps));
2363
2364         /* FIXIT : how to inform this error to MSL ????? */
2365         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2366          * then post an error to application
2367          */
2368 }
2369 #endif
2370
2371 static GstPadProbeReturn
2372 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2373 {
2374         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2375         return GST_PAD_PROBE_OK;
2376 }
2377
2378 static GstPadProbeReturn
2379 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2380 {
2381         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2382         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2383         mm_player_t* player = (mm_player_t*)data;
2384         GstCaps* caps = NULL;
2385         GstStructure* str = NULL;
2386         const gchar* name = NULL;
2387         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2388
2389
2390         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2391                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2392                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2393                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2394                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2395                         return ret;
2396         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2397                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2398                         return ret;
2399         }
2400
2401         caps = gst_pad_query_caps(pad, NULL);
2402         if (!caps) {
2403                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2404                 goto ERROR;
2405         }
2406
2407         str = gst_caps_get_structure(caps, 0);
2408         if (!str) {
2409                 LOGE("failed to get structure from caps");
2410                 goto ERROR;
2411         }
2412
2413         name = gst_structure_get_name(str);
2414         if (!name) {
2415                 LOGE("failed to get name from str");
2416                 goto ERROR;
2417         }
2418
2419         if (strstr(name, "audio")) {
2420                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2421         } else if (strstr(name, "video")) {
2422                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2423         } else {
2424                 /* text track is not supportable */
2425                 LOGE("invalid name %s", name);
2426                 goto ERROR;
2427         }
2428
2429         switch (GST_EVENT_TYPE(event)) {
2430         case GST_EVENT_EOS:
2431                 {
2432                         /* in case of gapless, drop eos event not to send it to sink */
2433                         if (player->gapless.reconfigure && !player->msg_posted) {
2434                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2435                                 ret = GST_PAD_PROBE_DROP;
2436                         }
2437                         break;
2438                 }
2439         case GST_EVENT_STREAM_START:
2440                 {
2441                         gint64 stop_running_time = 0;
2442                         gint64 position_running_time = 0;
2443                         gint64 position = 0;
2444                         gint idx = 0;
2445
2446                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2447                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2448                                         !(player->selector[idx].event_probe_id)) {
2449                                         /* LOGW("[%d] skip", idx); */
2450                                         continue;
2451                                 }
2452
2453                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2454                                         stop_running_time =
2455                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2456                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2457                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2458                                         stop_running_time =
2459                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2460                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2461                                 } else {
2462                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2463                                         stop_running_time =
2464                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2465                                                                 GST_FORMAT_TIME, player->duration);
2466                                 }
2467
2468                                 position_running_time =
2469                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2470                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2471
2472                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2473                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2474                                         idx,
2475                                         GST_TIME_ARGS(stop_running_time),
2476                                         GST_TIME_ARGS(position_running_time),
2477                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2478                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2479
2480                                 position_running_time = MAX(position_running_time, stop_running_time);
2481                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2482                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2483                                 position_running_time = MAX(0, position_running_time);
2484                                 position = MAX(position, position_running_time);
2485                         }
2486
2487                         if (position != 0) {
2488                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2489                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2490                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2491
2492                                 player->gapless.start_time[stream_type] += position;
2493                         }
2494                         break;
2495                 }
2496         case GST_EVENT_FLUSH_STOP:
2497                 {
2498                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2499                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2500                         player->gapless.start_time[stream_type] = 0;
2501                         break;
2502                 }
2503         case GST_EVENT_SEGMENT:
2504                 {
2505                         GstSegment segment;
2506                         GstEvent *tmpev;
2507
2508                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2509                         gst_event_copy_segment(event, &segment);
2510
2511                         if (segment.format == GST_FORMAT_TIME) {
2512                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2513                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2514                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2515                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2516                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2517                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2518
2519                                 /* keep the all the segment ev to cover the seeking */
2520                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2521                                 player->gapless.update_segment[stream_type] = TRUE;
2522
2523                                 if (!player->gapless.running)
2524                                         break;
2525
2526                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2527
2528                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2529
2530                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2531                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2532                                 gst_event_unref(event);
2533                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2534                         }
2535                         break;
2536                 }
2537         case GST_EVENT_QOS:
2538                 {
2539                         gdouble proportion = 0.0;
2540                         GstClockTimeDiff diff = 0;
2541                         GstClockTime timestamp = 0;
2542                         gint64 running_time_diff = -1;
2543                         GstQOSType type = 0;
2544                         GstEvent *tmpev = NULL;
2545
2546                         running_time_diff = player->gapless.segment[stream_type].base;
2547
2548                         if (running_time_diff <= 0) /* don't need to adjust */
2549                                 break;
2550
2551                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2552                         gst_event_unref(event);
2553
2554                         if (timestamp < running_time_diff) {
2555                                 LOGW("QOS event from previous group");
2556                                 ret = GST_PAD_PROBE_DROP;
2557                                 break;
2558                         }
2559
2560                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2561                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2562                                                 stream_type, GST_TIME_ARGS(timestamp),
2563                                                 GST_TIME_ARGS(running_time_diff),
2564                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2565
2566                         timestamp -= running_time_diff;
2567
2568                         /* That case is invalid for QoS events */
2569                         if (diff < 0 && -diff > timestamp) {
2570                                 LOGW("QOS event from previous group");
2571                                 ret = GST_PAD_PROBE_DROP;
2572                                 break;
2573                         }
2574
2575                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2576                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2577
2578                         break;
2579                 }
2580         default:
2581                 break;
2582         }
2583
2584 ERROR:
2585         if (caps)
2586                 gst_caps_unref(caps);
2587         return ret;
2588 }
2589
2590 static void
2591 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2592 {
2593         mm_player_t* player = NULL;
2594         GstElement* pipeline = NULL;
2595         GstElement* selector = NULL;
2596         GstElement* fakesink = NULL;
2597         GstCaps* caps = NULL;
2598         GstStructure* str = NULL;
2599         const gchar* name = NULL;
2600         GstPad* sinkpad = NULL;
2601         GstPad* srcpad = NULL;
2602         gboolean first_track = FALSE;
2603
2604         enum MainElementID elemId = MMPLAYER_M_NUM;
2605         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2606
2607         /* check handles */
2608         player = (mm_player_t*)data;
2609
2610         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2611         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2612
2613         //LOGD("pad-added signal handling\n");
2614
2615         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2616
2617         /* get mimetype from caps */
2618         caps = gst_pad_query_caps(pad, NULL);
2619         if (!caps) {
2620                 LOGE("cannot get caps from pad.\n");
2621                 goto ERROR;
2622         }
2623
2624         str = gst_caps_get_structure(caps, 0);
2625         if (!str) {
2626                 LOGE("cannot get structure from caps.\n");
2627                 goto ERROR;
2628         }
2629
2630         name = gst_structure_get_name(str);
2631         if (!name) {
2632                 LOGE("cannot get mimetype from structure.\n");
2633                 goto ERROR;
2634         }
2635
2636         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2637         //LOGD("detected mimetype : %s\n", name);
2638
2639         if (strstr(name, "video")) {
2640                 gint stype = 0;
2641
2642                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2643                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2644
2645                 /* don't make video because of not required, and not support multiple track */
2646                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2647                         LOGD("no video sink by null surface");
2648
2649                         gchar *caps_str = gst_caps_to_string(caps);
2650                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")))
2651                                 player->set_mode.video_zc = TRUE;
2652
2653                         MMPLAYER_FREEIF(caps_str);
2654
2655                         if (player->v_stream_caps) {
2656                                 gst_caps_unref(player->v_stream_caps);
2657                                 player->v_stream_caps = NULL;
2658                         }
2659
2660                         LOGD("create fakesink instead of videobin");
2661
2662                         /* fake sink */
2663                         fakesink = gst_element_factory_make("fakesink", NULL);
2664                         if (fakesink == NULL) {
2665                                 LOGE("ERROR : fakesink create error\n");
2666                                 goto ERROR;
2667                         }
2668
2669                         if (player->ini.set_dump_element_flag)
2670                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2671
2672                         player->video_fakesink = fakesink;
2673
2674                         /* store it as it's sink element */
2675                         __mmplayer_add_sink(player, player->video_fakesink);
2676
2677                         gst_bin_add(GST_BIN(pipeline), fakesink);
2678
2679                         // link
2680                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2681
2682                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2683                                 LOGW("failed to link fakesink\n");
2684                                 gst_object_unref(GST_OBJECT(fakesink));
2685                                 goto ERROR;
2686                         }
2687
2688                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2689                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2690                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2691                         }
2692
2693                         if (player->set_mode.media_packet_video_stream) {
2694                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2695
2696                                 MMPLAYER_SIGNAL_CONNECT(player,
2697                                                                                 G_OBJECT(fakesink),
2698                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2699                                                                                 "handoff",
2700                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2701                                                                                 (gpointer)player);
2702
2703                                 MMPLAYER_SIGNAL_CONNECT(player,
2704                                                                                 G_OBJECT(fakesink),
2705                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2706                                                                                 "preroll-handoff",
2707                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2708                                                                                 (gpointer)player);
2709                         }
2710
2711                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2712                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2713                         goto DONE;
2714                 }
2715
2716                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2717                         __mmplayer_gst_decode_callback(elem, pad, player);
2718                         return;
2719                 }
2720
2721                 LOGD("video selector \n");
2722                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2723                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2724         } else {
2725                 if (strstr(name, "audio")) {
2726                         gint samplerate = 0;
2727                         gint channels = 0;
2728
2729                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2730                                 __mmplayer_gst_decode_callback(elem, pad, player);
2731                                 return;
2732                         }
2733
2734                         LOGD("audio selector \n");
2735                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2736                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2737
2738                         gst_structure_get_int(str, "rate", &samplerate);
2739                         gst_structure_get_int(str, "channels", &channels);
2740
2741                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2742                                 /* fake sink */
2743                                 fakesink = gst_element_factory_make("fakesink", NULL);
2744                                 if (fakesink == NULL) {
2745                                         LOGE("ERROR : fakesink create error\n");
2746                                         goto ERROR;
2747                                 }
2748
2749                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2750
2751                                 /* link */
2752                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2753
2754                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2755                                         LOGW("failed to link fakesink\n");
2756                                         gst_object_unref(GST_OBJECT(fakesink));
2757                                         goto ERROR;
2758                                 }
2759
2760                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2761                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2762                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2763
2764                                 goto DONE;
2765                         }
2766                 } else if (strstr(name, "text")) {
2767                         LOGD("text selector \n");
2768                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2769                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2770                 } else {
2771                         LOGE("wrong elem id \n");
2772                         goto ERROR;
2773                 }
2774         }
2775
2776         selector = player->pipeline->mainbin[elemId].gst;
2777         if (selector == NULL) {
2778                 selector = gst_element_factory_make("input-selector", NULL);
2779                 LOGD("Creating input-selector\n");
2780                 if (selector == NULL) {
2781                         LOGE("ERROR : input-selector create error\n");
2782                         goto ERROR;
2783                 }
2784                 g_object_set(selector, "sync-streams", TRUE, NULL);
2785
2786                 player->pipeline->mainbin[elemId].id = elemId;
2787                 player->pipeline->mainbin[elemId].gst = selector;
2788
2789                 first_track = TRUE;
2790                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2791
2792                 srcpad = gst_element_get_static_pad(selector, "src");
2793
2794                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2795                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2796                         __mmplayer_gst_selector_blocked, NULL, NULL);
2797                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2798                         __mmplayer_gst_selector_event_probe, player, NULL);
2799
2800                 gst_element_set_state(selector, GST_STATE_PAUSED);
2801                 gst_bin_add(GST_BIN(pipeline), selector);
2802         } else
2803                 LOGD("input-selector is already created.\n");
2804
2805         // link
2806         LOGD("Calling request pad with selector %p \n", selector);
2807         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2808
2809         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2810
2811         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2812                 LOGW("failed to link selector\n");
2813                 gst_object_unref(GST_OBJECT(selector));
2814                 goto ERROR;
2815         }
2816
2817         if (first_track) {
2818                 LOGD("this is first track --> active track \n");
2819                 g_object_set(selector, "active-pad", sinkpad, NULL);
2820         }
2821
2822         _mmplayer_track_update_info(player, stream_type, sinkpad);
2823
2824
2825 DONE:
2826 ERROR:
2827
2828         if (caps)
2829                 gst_caps_unref(caps);
2830
2831         if (sinkpad) {
2832                 gst_object_unref(GST_OBJECT(sinkpad));
2833                 sinkpad = NULL;
2834         }
2835
2836         if (srcpad) {
2837                 gst_object_unref(GST_OBJECT(srcpad));
2838                 srcpad = NULL;
2839         }
2840
2841         return;
2842 }
2843
2844 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2845 {
2846         GstPad* srcpad = NULL;
2847         MMHandleType attrs = 0;
2848         gint active_index = 0;
2849
2850         // [link] input-selector :: textbin
2851         srcpad = gst_element_get_static_pad(text_selector, "src");
2852         if (!srcpad) {
2853                 LOGE("failed to get srcpad from selector\n");
2854                 return;
2855         }
2856
2857         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2858
2859         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2860         if ((active_index != DEFAULT_TRACK) &&
2861                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2862                 LOGW("failed to change text track\n");
2863                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2864         }
2865
2866         player->no_more_pad = TRUE;
2867         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2868
2869         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2870         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2871                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2872                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2873         }
2874
2875         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2876
2877         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2878                 player->has_closed_caption = TRUE;
2879
2880         attrs = MMPLAYER_GET_ATTRS(player);
2881         if (attrs) {
2882                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2883                 if (mmf_attrs_commit(attrs))
2884                         LOGE("failed to commit.\n");
2885         } else
2886                 LOGE("cannot get content attribute");
2887
2888         if (srcpad) {
2889                 gst_object_unref(GST_OBJECT(srcpad));
2890                 srcpad = NULL;
2891         }
2892 }
2893
2894 static void
2895 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2896 {
2897         mm_player_t* player = (mm_player_t*)data;
2898         GstElement* selector = NULL;
2899         GstElement* queue = NULL;
2900
2901         GstPad* srcpad = NULL;
2902         GstPad* sinkpad = NULL;
2903         gchar* caps_str = NULL;
2904
2905         MMPLAYER_FENTER();
2906         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2907
2908         caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2909         LOGD("deinterleave new caps : %s\n", caps_str);
2910         MMPLAYER_FREEIF(caps_str);
2911
2912         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2913                 LOGE("ERROR : queue create error\n");
2914                 goto ERROR;
2915         }
2916
2917         g_object_set(G_OBJECT(queue),
2918                                 "max-size-buffers", 10,
2919                                 "max-size-bytes", 0,
2920                                 "max-size-time", (guint64)0,
2921                                 NULL);
2922
2923         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2924
2925         if (!selector) {
2926                 LOGE("there is no audio channel selector.\n");
2927                 goto ERROR;
2928         }
2929
2930         srcpad = gst_element_get_static_pad(queue, "src");
2931         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2932
2933         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2934
2935         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2936                 LOGW("failed to link deinterleave - selector\n");
2937                 goto ERROR;
2938         }
2939
2940         gst_element_set_state(queue, GST_STATE_PAUSED);
2941         player->audio_mode.total_track_num++;
2942
2943 ERROR:
2944
2945         if (srcpad) {
2946                 gst_object_unref(GST_OBJECT(srcpad));
2947                 srcpad = NULL;
2948         }
2949
2950         if (sinkpad) {
2951                 gst_object_unref(GST_OBJECT(sinkpad));
2952                 sinkpad = NULL;
2953         }
2954
2955         MMPLAYER_FLEAVE();
2956         return;
2957 }
2958
2959 static void
2960 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2961 {
2962         mm_player_t* player = NULL;
2963         GstElement* selector = NULL;
2964         GstPad* sinkpad = NULL;
2965         gint active_index = 0;
2966         gchar* change_pad_name = NULL;
2967         GstCaps* caps = NULL;   // no need to unref
2968         gint default_audio_ch = 0;
2969
2970         MMPLAYER_FENTER();
2971         player = (mm_player_t*) data;
2972
2973         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2974
2975         if (!selector) {
2976                 LOGE("there is no audio channel selector.\n");
2977                 goto ERROR;
2978         }
2979
2980         active_index = player->audio_mode.active_pad_index;
2981
2982         if (active_index != default_audio_ch) {
2983                 gint audio_ch = default_audio_ch;
2984
2985                 /*To get the new pad from the selector*/
2986                 change_pad_name = g_strdup_printf("sink%d", active_index);
2987                 if (change_pad_name != NULL) {
2988                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2989                         if (sinkpad != NULL) {
2990                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2991                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2992
2993                                 audio_ch = active_index;
2994
2995                                 caps = gst_pad_get_current_caps(sinkpad);
2996                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2997
2998                                 __mmplayer_set_audio_attrs(player, caps);
2999                         }
3000                         MMPLAYER_FREEIF(change_pad_name);
3001                 }
3002
3003                 player->audio_mode.active_pad_index = audio_ch;
3004                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3005         }
3006
3007 ERROR:
3008
3009         if (sinkpad)
3010                 gst_object_unref(sinkpad);
3011
3012         MMPLAYER_FLEAVE();
3013         return;
3014 }
3015
3016 static void
3017 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3018 {
3019         mm_player_t* player = NULL;
3020         MMPlayerGstElement *mainbin = NULL;
3021
3022         GstElement* tee = NULL;
3023         GstElement* stereo_queue = NULL;
3024         GstElement* mono_queue = NULL;
3025         GstElement* conv = NULL;
3026         GstElement* filter = NULL;
3027         GstElement* deinterleave = NULL;
3028         GstElement* selector = NULL;
3029
3030         GstPad* srcpad = NULL;
3031         GstPad* selector_srcpad = NULL;
3032         GstPad* sinkpad = NULL;
3033         GstCaps* caps = NULL;
3034         gulong block_id = 0;
3035
3036         MMPLAYER_FENTER();
3037
3038         /* check handles */
3039         player = (mm_player_t*) data;
3040
3041         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3042         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3043
3044         mainbin = player->pipeline->mainbin;
3045
3046         /* tee */
3047         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3048                 LOGE("ERROR : tee create error\n");
3049                 goto ERROR;
3050         }
3051
3052         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3053         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3054
3055         gst_element_set_state(tee, GST_STATE_PAUSED);
3056
3057         /* queue */
3058         srcpad = gst_element_get_request_pad(tee, "src_%u");
3059         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3060                 LOGE("ERROR : stereo queue create error\n");
3061                 goto ERROR;
3062         }
3063
3064         g_object_set(G_OBJECT(stereo_queue),
3065                                 "max-size-buffers", 10,
3066                                 "max-size-bytes", 0,
3067                                 "max-size-time", (guint64)0,
3068                                 NULL);
3069
3070         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3071         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3072
3073         if (srcpad) {
3074                 gst_object_unref(GST_OBJECT(srcpad));
3075                 srcpad = NULL;
3076         }
3077
3078         srcpad = gst_element_get_request_pad(tee, "src_%u");
3079
3080         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3081                 LOGE("ERROR : mono queue create error\n");
3082                 goto ERROR;
3083         }
3084
3085         g_object_set(G_OBJECT(mono_queue),
3086                                 "max-size-buffers", 10,
3087                                 "max-size-bytes", 0,
3088                                 "max-size-time", (guint64)0,
3089                                 NULL);
3090
3091         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3092         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3093
3094         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3095         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3096
3097         /* audioconvert */
3098         srcpad = gst_element_get_static_pad(mono_queue, "src");
3099         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3100                 LOGE("ERROR : audioconvert create error\n");
3101                 goto ERROR;
3102         }
3103
3104         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3105         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3106
3107         /* caps filter */
3108         if (srcpad) {
3109                 gst_object_unref(GST_OBJECT(srcpad));
3110                 srcpad = NULL;
3111         }
3112         srcpad = gst_element_get_static_pad(conv, "src");
3113
3114         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3115                 LOGE("ERROR : capsfilter create error\n");
3116                 goto ERROR;
3117         }
3118
3119         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3120         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3121
3122         caps = gst_caps_from_string("audio/x-raw-int, "
3123                                 "width = (int) 16, "
3124                                 "depth = (int) 16, "
3125                                 "channels = (int) 2");
3126
3127         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3128         gst_caps_unref(caps);
3129
3130         gst_element_set_state(conv, GST_STATE_PAUSED);
3131         gst_element_set_state(filter, GST_STATE_PAUSED);
3132
3133         /* deinterleave */
3134         if (srcpad) {
3135                 gst_object_unref(GST_OBJECT(srcpad));
3136                 srcpad = NULL;
3137         }
3138         srcpad = gst_element_get_static_pad(filter, "src");
3139
3140         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3141                 LOGE("ERROR : deinterleave create error\n");
3142                 goto ERROR;
3143         }
3144
3145         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3146
3147         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3148                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3149
3150         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3151                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3152
3153         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3154         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3155
3156         /* selector */
3157         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3158         if (selector == NULL) {
3159                 LOGE("ERROR : audio-selector create error\n");
3160                 goto ERROR;
3161         }
3162
3163         g_object_set(selector, "sync-streams", TRUE, NULL);
3164         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3165
3166         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3167         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3168
3169         selector_srcpad = gst_element_get_static_pad(selector, "src");
3170
3171         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3172         block_id =
3173                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3174                         __mmplayer_gst_selector_blocked, NULL, NULL);
3175
3176         if (srcpad) {
3177                 gst_object_unref(GST_OBJECT(srcpad));
3178                 srcpad = NULL;
3179         }
3180
3181         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3182         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3183
3184         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3185                 LOGW("failed to link queue_stereo - selector\n");
3186                 goto ERROR;
3187         }
3188
3189         player->audio_mode.total_track_num++;
3190
3191         g_object_set(selector, "active-pad", sinkpad, NULL);
3192         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3193         gst_element_set_state(selector, GST_STATE_PAUSED);
3194
3195         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3196
3197 ERROR:
3198
3199         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3200         if (block_id != 0) {
3201                 gst_pad_remove_probe(selector_srcpad, block_id);
3202                 block_id = 0;
3203         }
3204
3205         if (sinkpad) {
3206                 gst_object_unref(GST_OBJECT(sinkpad));
3207                 sinkpad = NULL;
3208         }
3209
3210         if (srcpad) {
3211                 gst_object_unref(GST_OBJECT(srcpad));
3212                 srcpad = NULL;
3213         }
3214
3215         if (selector_srcpad) {
3216                 gst_object_unref(GST_OBJECT(selector_srcpad));
3217                 selector_srcpad = NULL;
3218         }
3219
3220         MMPLAYER_FLEAVE();
3221         return;
3222 }
3223
3224 static void
3225 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3226 {
3227         mm_player_t* player = NULL;
3228         GstPad* srcpad = NULL;
3229         GstElement* video_selector = NULL;
3230         GstElement* audio_selector = NULL;
3231         GstElement* text_selector = NULL;
3232         MMHandleType attrs = 0;
3233         gint active_index = 0;
3234         gint64 dur_bytes = 0L;
3235
3236         player = (mm_player_t*) data;
3237
3238         LOGD("no-more-pad signal handling\n");
3239
3240         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3241                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3242                 LOGW("no need to go more");
3243
3244                 if (player->gapless.reconfigure) {
3245                         player->gapless.reconfigure = FALSE;
3246                         MMPLAYER_PLAYBACK_UNLOCK(player);
3247                 }
3248
3249                 return;
3250         }
3251
3252         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3253                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3254                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3255                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3256                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3257
3258                 if (NULL == player->streamer) {
3259                         LOGW("invalid state for buffering");
3260                         goto ERROR;
3261                 }
3262
3263                 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3264                 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3265
3266                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3267                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3268
3269                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3270
3271                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3272                         LOGE("fail to get duration.\n");
3273
3274                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3275                 // use file information was already set on Q2 when it was created.
3276                 __mm_player_streaming_set_queue2(player->streamer,
3277                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3278                                                 TRUE,                                                           // use_buffering
3279                                                 buffer_bytes,
3280                                                 init_buffering_time,
3281                                                 1.0,                                                            // low percent
3282                                                 player->ini.http_buffering_limit,       // high percent
3283                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3284                                                 NULL,
3285                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3286         }
3287
3288         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3289         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3290         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3291         if (video_selector) {
3292                 // [link] input-selector :: videobin
3293                 srcpad = gst_element_get_static_pad(video_selector, "src");
3294                 if (!srcpad) {
3295                         LOGE("failed to get srcpad from video selector\n");
3296                         goto ERROR;
3297                 }
3298
3299                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3300                 if (!text_selector && !audio_selector)
3301                         player->no_more_pad = TRUE;
3302
3303                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3304
3305                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3306                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3307                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3308                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3309                 }
3310         }
3311
3312         if (audio_selector) {
3313                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3314                 if ((active_index != DEFAULT_TRACK) &&
3315                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3316                         LOGW("failed to change audio track\n");
3317                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3318                 }
3319
3320                 // [link] input-selector :: audiobin
3321                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3322                 if (!srcpad) {
3323                         LOGE("failed to get srcpad from selector\n");
3324                         goto ERROR;
3325                 }
3326
3327                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3328                 if (!text_selector)
3329                         player->no_more_pad = TRUE;
3330
3331                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3332                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3333                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3334                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3335                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3336                         }
3337
3338                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3339                 } else {
3340                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3341
3342                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3343                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3344                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3345                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3346                         }
3347                 }
3348
3349                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3350
3351                 attrs = MMPLAYER_GET_ATTRS(player);
3352                 if (attrs) {
3353                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3354                         if (mmf_attrs_commit(attrs))
3355                                 LOGE("failed to commit.\n");
3356                 } else
3357                         LOGE("cannot get content attribute");
3358         } else {
3359                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3360                         LOGD("There is no audio track : remove audiobin");
3361
3362                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3363                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3364
3365                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3366                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3367                 }
3368
3369                 if (player->num_dynamic_pad == 0)
3370                         __mmplayer_pipeline_complete(NULL, player);
3371         }
3372
3373         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3374                 if (text_selector)
3375                         __mmplayer_handle_text_decode_path(player, text_selector);
3376         }
3377
3378         MMPLAYER_FLEAVE();
3379
3380 ERROR:
3381         if (srcpad) {
3382                 gst_object_unref(GST_OBJECT(srcpad));
3383                 srcpad = NULL;
3384         }
3385
3386         if (player->gapless.reconfigure) {
3387                 player->gapless.reconfigure = FALSE;
3388                 MMPLAYER_PLAYBACK_UNLOCK(player);
3389         }
3390 }
3391
3392 static void
3393 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3394 {
3395         mm_player_t* player = NULL;
3396         MMHandleType attrs = 0;
3397         GstElement* pipeline = NULL;
3398         GstCaps* caps = NULL;
3399         gchar* caps_str = NULL;
3400         GstStructure* str = NULL;
3401         const gchar* name = NULL;
3402         GstPad* sinkpad = NULL;
3403         GstElement* sinkbin = NULL;
3404         gboolean reusing = FALSE;
3405         GstElement *text_selector = NULL;
3406         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3407
3408         /* check handles */
3409         player = (mm_player_t*) data;
3410
3411         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3412         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3413
3414         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3415
3416         attrs = MMPLAYER_GET_ATTRS(player);
3417         if (!attrs) {
3418                 LOGE("cannot get content attribute\n");
3419                 goto ERROR;
3420         }
3421
3422         /* get mimetype from caps */
3423         caps = gst_pad_query_caps(pad, NULL);
3424         if (!caps) {
3425                 LOGE("cannot get caps from pad.\n");
3426                 goto ERROR;
3427         }
3428         caps_str = gst_caps_to_string(caps);
3429
3430         str = gst_caps_get_structure(caps, 0);
3431         if (!str) {
3432                 LOGE("cannot get structure from caps.\n");
3433                 goto ERROR;
3434         }
3435
3436         name = gst_structure_get_name(str);
3437         if (!name) {
3438                 LOGE("cannot get mimetype from structure.\n");
3439                 goto ERROR;
3440         }
3441
3442         //LOGD("detected mimetype : %s\n", name);
3443
3444         if (strstr(name, "audio")) {
3445                 if (player->pipeline->audiobin == NULL) {
3446                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3447                                 LOGE("failed to create audiobin. continuing without audio\n");
3448                                 goto ERROR;
3449                         }
3450
3451                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3452                         LOGD("creating audiosink bin success\n");
3453                 } else {
3454                         reusing = TRUE;
3455                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3456                         LOGD("reusing audiobin\n");
3457                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3458                 }
3459
3460                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3461                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3462
3463                 player->audiosink_linked  = 1;
3464
3465                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3466                 if (!sinkpad) {
3467                         LOGE("failed to get pad from sinkbin\n");
3468                         goto ERROR;
3469                 }
3470         } else if (strstr(name, "video")) {
3471                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")))
3472                         player->set_mode.video_zc = TRUE;
3473
3474                 if (player->pipeline->videobin == NULL) {
3475                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3476                         /* get video surface type */
3477                         int surface_type = 0;
3478                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3479                         LOGD("display_surface_type(%d)\n", surface_type);
3480
3481                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3482                                 LOGD("not make videobin because it dose not want\n");
3483                                 goto ERROR;
3484                         }
3485
3486                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3487                                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
3488                                         /* prepare resource manager for video overlay */
3489                                         if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3490                                                 if (_mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], RESOURCE_TYPE_VIDEO_OVERLAY)
3491                                                         != MM_ERROR_NONE) {
3492                                                         LOGE("could not prepare for video_overlay resource\n");
3493                                                         goto ERROR;
3494                                                 }
3495                                         }
3496                                 }
3497                         }
3498
3499                         if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
3500                                 /* acquire resources for video overlay */
3501                                 if (resource_state == RESOURCE_STATE_PREPARED) {
3502                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]) != MM_ERROR_NONE) {
3503                                                 LOGE("could not acquire resources for video playing\n");
3504                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
3505                                                 goto ERROR;
3506                                         }
3507                                 }
3508                         }
3509
3510                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3511                                 LOGE("failed to create videobin. continuing without video\n");
3512                                 goto ERROR;
3513                         }
3514
3515                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3516                         LOGD("creating videosink bin success\n");
3517                 } else {
3518                         reusing = TRUE;
3519                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3520                         LOGD("re-using videobin\n");
3521                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3522                 }
3523
3524                 /* FIXIT : track number shouldn't be hardcoded */
3525                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3526                 player->videosink_linked  = 1;
3527
3528                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3529                 if (!sinkpad) {
3530                         LOGE("failed to get pad from sinkbin\n");
3531                         goto ERROR;
3532                 }
3533         } else if (strstr(name, "text")) {
3534                 if (player->pipeline->textbin == NULL) {
3535                         MMPlayerGstElement* mainbin = NULL;
3536
3537                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3538                                 LOGE("failed to create text sink bin. continuing without text\n");
3539                                 goto ERROR;
3540                         }
3541
3542                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3543                         LOGD("creating textsink bin success\n");
3544
3545                         /* FIXIT : track number shouldn't be hardcoded */
3546                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3547
3548                         player->textsink_linked  = 1;
3549                         LOGI("player->textsink_linked set to 1\n");
3550
3551                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3552                         if (!sinkpad) {
3553                                 LOGE("failed to get pad from sinkbin\n");
3554                                 goto ERROR;
3555                         }
3556
3557                         mainbin = player->pipeline->mainbin;
3558
3559                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3560                                 /* input selector */
3561                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3562                                 if (!text_selector) {
3563                                         LOGE("failed to create subtitle input selector element\n");
3564                                         goto ERROR;
3565                                 }
3566                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3567
3568                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3569                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3570
3571                                 /* warm up */
3572                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3573                                         LOGE("failed to set state(READY) to sinkbin\n");
3574                                         goto ERROR;
3575                                 }
3576
3577                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3578                                         LOGW("failed to add subtitle input selector\n");
3579                                         goto ERROR;
3580                                 }
3581
3582                                 LOGD("created element input-selector");
3583
3584                         } else {
3585                                 LOGD("already having subtitle input selector");
3586                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3587                         }
3588                 } else {
3589                         if (!player->textsink_linked) {
3590                                 LOGD("re-using textbin\n");
3591
3592                                 reusing = TRUE;
3593                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3594
3595                                 player->textsink_linked  = 1;
3596                                 LOGI("player->textsink_linked set to 1\n");
3597                         } else
3598                                 LOGD("ignoring internal subtutle since external subtitle is available");
3599                 }
3600         } else {
3601                 LOGW("unknown type of elementary stream!ignoring it...\n");
3602                 goto ERROR;
3603         }
3604
3605         if (sinkbin) {
3606                 if (!reusing) {
3607                         /* warm up */
3608                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3609                                 LOGE("failed to set state(READY) to sinkbin\n");
3610                                 goto ERROR;
3611                         }
3612
3613                         /* Added for multi audio support to avoid adding audio bin again*/
3614                         /* add */
3615                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3616                                 LOGE("failed to add sinkbin to pipeline\n");
3617                                 goto ERROR;
3618                         }
3619                 }
3620
3621                 /* link */
3622                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3623                         LOGE("failed to get pad from sinkbin\n");
3624                         goto ERROR;
3625                 }
3626
3627                 if (!reusing) {
3628                         /* run */
3629                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3630                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3631                                 goto ERROR;
3632                         }
3633
3634                         if (text_selector) {
3635                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3636                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3637                                         goto ERROR;
3638                                 }
3639                         }
3640                 }
3641
3642                 gst_object_unref(sinkpad);
3643                 sinkpad = NULL;
3644         }
3645
3646         LOGD("linking sink bin success\n");
3647
3648         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3649          * streaming task. if the task blocked, then buffer will not flow to the next element
3650          *(autoplugging element). so this is special hack for streaming. please try to remove it
3651          */
3652         /* dec stream count. we can remove fakesink if it's zero */
3653         if (player->num_dynamic_pad)
3654                 player->num_dynamic_pad--;
3655
3656         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3657
3658         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3659                 __mmplayer_pipeline_complete(NULL, player);
3660
3661         /* FIXIT : please leave a note why this code is needed */
3662         if (MMPLAYER_IS_WFD_STREAMING(player))
3663                 player->no_more_pad = TRUE;
3664
3665 ERROR:
3666
3667         MMPLAYER_FREEIF(caps_str);
3668
3669         if (caps)
3670                 gst_caps_unref(caps);
3671
3672         if (sinkpad)
3673                 gst_object_unref(GST_OBJECT(sinkpad));
3674
3675         /* flusing out new attributes */
3676         if (mmf_attrs_commit(attrs))
3677                 LOGE("failed to comit attributes\n");
3678
3679         return;
3680 }
3681
3682 static gboolean
3683 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3684 {
3685         int pro_value = 0; // in the case of expection, default will be returned.
3686         int dest_angle = rotation_angle;
3687         int rotation_type = -1;
3688
3689         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3690         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3691         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3692
3693         if (rotation_angle >= 360)
3694                 dest_angle = rotation_angle - 360;
3695
3696         /* chech if supported or not */
3697         if (dest_angle % 90) {
3698                 LOGD("not supported rotation angle = %d", rotation_angle);
3699                 return FALSE;
3700         }
3701
3702         /*
3703           * waylandsink (A)
3704           * custom_convert - none (B)
3705           * videoflip - none (C)
3706           */
3707         if (player->set_mode.video_zc) {
3708                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3709                         rotation_type = ROTATION_USING_CUSTOM;
3710                 else // A
3711                         rotation_type = ROTATION_USING_SINK;
3712         } else {
3713                 int surface_type = 0;
3714                 rotation_type = ROTATION_USING_FLIP;
3715
3716                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3717                 LOGD("check display surface type attribute: %d", surface_type);
3718
3719                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3720                         rotation_type = ROTATION_USING_SINK;
3721                 else
3722                         rotation_type = ROTATION_USING_FLIP; //C
3723
3724                 LOGD("using %d type for rotation", rotation_type);
3725         }
3726
3727         /* get property value for setting */
3728         switch (rotation_type) {
3729         case ROTATION_USING_SINK: // waylandsink
3730                 {
3731                         switch (dest_angle) {
3732                         case 0:
3733                                 break;
3734                         case 90:
3735                                 pro_value = 3; // clockwise 90
3736                                 break;
3737                         case 180:
3738                                 pro_value = 2;
3739                                 break;
3740                         case 270:
3741                                 pro_value = 1; // counter-clockwise 90
3742                                 break;
3743                         }
3744                 }
3745                 break;
3746         case ROTATION_USING_CUSTOM:
3747                 {
3748                         gchar *ename = NULL;
3749                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3750
3751                         if (g_strrstr(ename, "fimcconvert")) {
3752                                 switch (dest_angle) {
3753                                 case 0:
3754                                         break;
3755                                 case 90:
3756                                         pro_value = 90; // clockwise 90
3757                                         break;
3758                                 case 180:
3759                                         pro_value = 180;
3760                                         break;
3761                                 case 270:
3762                                         pro_value = 270; // counter-clockwise 90
3763                                         break;
3764                                 }
3765                         }
3766                 }
3767                 break;
3768         case ROTATION_USING_FLIP: // videoflip
3769                 {
3770                                 switch (dest_angle) {
3771                                 case 0:
3772                                         break;
3773                                 case 90:
3774                                         pro_value = 1; // clockwise 90
3775                                         break;
3776                                 case 180:
3777                                         pro_value = 2;
3778                                         break;
3779                                 case 270:
3780                                         pro_value = 3; // counter-clockwise 90
3781                                         break;
3782                                 }
3783                 }
3784                 break;
3785         }
3786
3787         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3788
3789         *value = pro_value;
3790
3791         return TRUE;
3792 }
3793
3794 int
3795 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3796 {
3797         /* check video sinkbin is created */
3798         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3799                 player->pipeline &&
3800                 player->pipeline->videobin &&
3801                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3802                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3803                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3804
3805         return MM_ERROR_NONE;
3806 }
3807
3808 void
3809 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3810 {
3811         int rotation_value = 0;
3812         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3813         int user_angle = 0;
3814         MMPLAYER_FENTER();
3815
3816         /* check video sinkbin is created */
3817         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3818                 return;
3819
3820         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3821
3822         /* get rotation value to set */
3823         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3824         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3825         LOGD("set video param : rotate %d", rotation_value);
3826 }
3827
3828 void
3829 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3830 {
3831         MMHandleType attrs = 0;
3832         int visible = 0;
3833         MMPLAYER_FENTER();
3834
3835         /* check video sinkbin is created */
3836         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3837                 return;
3838
3839         attrs = MMPLAYER_GET_ATTRS(player);
3840         MMPLAYER_RETURN_IF_FAIL(attrs);
3841
3842         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3843         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3844         LOGD("set video param : visible %d", visible);
3845 }
3846
3847 void
3848 __mmplayer_video_param_set_display_method(mm_player_t* player)
3849 {
3850         MMHandleType attrs = 0;
3851         int display_method = 0;
3852         MMPLAYER_FENTER();
3853
3854         /* check video sinkbin is created */
3855         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3856                 return;
3857
3858         attrs = MMPLAYER_GET_ATTRS(player);
3859         MMPLAYER_RETURN_IF_FAIL(attrs);
3860
3861         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3862         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3863         LOGD("set video param : method %d", display_method);
3864 }
3865
3866 void
3867 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3868 {
3869         MMHandleType attrs = 0;
3870         int display_method = 0;
3871         void *handle = NULL;
3872         /*set wl_display*/
3873         int wl_window_x = 0;
3874         int wl_window_y = 0;
3875         int wl_window_width = 0;
3876         int wl_window_height = 0;
3877         MMPLAYER_FENTER();
3878
3879         /* check video sinkbin is created */
3880         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3881                 return;
3882
3883         attrs = MMPLAYER_GET_ATTRS(player);
3884         MMPLAYER_RETURN_IF_FAIL(attrs);
3885
3886         /* check roi mode is set */
3887         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3888         if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3889                 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3890                 return;
3891         }
3892         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3893
3894         if (handle) {
3895                 /*It should be set after setting window*/
3896                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3897                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3898                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3899                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3900
3901                 /* After setting window handle, set render      rectangle */
3902                 gst_video_overlay_set_render_rectangle(
3903                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3904                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3905                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3906                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3907
3908         }
3909 }
3910 void
3911 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3912 {
3913         MMHandleType attrs = 0;
3914         void *handle = NULL;
3915
3916         /* check video sinkbin is created */
3917         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3918                 return;
3919
3920         attrs = MMPLAYER_GET_ATTRS(player);
3921         MMPLAYER_RETURN_IF_FAIL(attrs);
3922
3923         /* common case if using overlay surface */
3924         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3925
3926         if (handle) {
3927                 /* default is using wl_surface_id */
3928                 unsigned int wl_surface_id      = 0;
3929                 wl_surface_id = *(int*)handle;
3930                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3931                 gst_video_overlay_set_wl_window_wl_surface_id(
3932                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3933                                 *(int*)handle);
3934         } else
3935                 /* FIXIT : is it error case? */
3936                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3937 }
3938
3939
3940 int
3941 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3942 {
3943         bool update_all_param = FALSE;
3944         MMPLAYER_FENTER();
3945
3946         /* check video sinkbin is created */
3947         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3948                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3949
3950         if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
3951                 LOGE("can not find waylandsink");
3952                 return MM_ERROR_PLAYER_INTERNAL;
3953         }
3954
3955         LOGD("param_name : %s", param_name);
3956         if (!g_strcmp0(param_name, "update_all_param"))
3957                 update_all_param = TRUE;
3958
3959         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3960                 __mmplayer_video_param_set_display_overlay(player);
3961         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3962                 __mmplayer_video_param_set_display_method(player);
3963         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3964                 __mmplayer_video_param_set_render_rectangle(player);
3965         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3966                 __mmplayer_video_param_set_display_visible(player);
3967         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3968                 __mmplayer_video_param_set_display_rotation(player);
3969
3970         return MM_ERROR_NONE;
3971 }
3972
3973 int
3974 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3975 {
3976         MMHandleType attrs = 0;
3977         int surface_type = 0;
3978         int ret = MM_ERROR_NONE;
3979
3980         MMPLAYER_FENTER();
3981
3982         /* check video sinkbin is created */
3983         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3984                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3985
3986         attrs = MMPLAYER_GET_ATTRS(player);
3987         if (!attrs) {
3988                 LOGE("cannot get content attribute");
3989                 return MM_ERROR_PLAYER_INTERNAL;
3990         }
3991         LOGD("param_name : %s", param_name);
3992
3993         /* update display surface */
3994         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3995         LOGD("check display surface type attribute: %d", surface_type);
3996
3997         /* configuring display */
3998         switch (surface_type) {
3999         case MM_DISPLAY_SURFACE_OVERLAY:
4000                 {
4001                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4002                         if (ret != MM_ERROR_NONE)
4003                                 return ret;
4004                 }
4005                 break;
4006         }
4007
4008         MMPLAYER_FLEAVE();
4009
4010         return MM_ERROR_NONE;
4011 }
4012
4013 int
4014 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
4015 {
4016         gboolean disable_overlay = FALSE;
4017         mm_player_t* player = (mm_player_t*) hplayer;
4018         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
4019         int ret = MM_ERROR_NONE;
4020
4021         MMPLAYER_FENTER();
4022         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4023         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4024                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4025                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4026
4027         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4028                 LOGW("Display control is not supported");
4029                 return MM_ERROR_PLAYER_INTERNAL;
4030         }
4031
4032         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4033
4034         if (audio_only == (bool)disable_overlay) {
4035                 LOGE("It's the same with current setting: (%d)", audio_only);
4036                 return MM_ERROR_NONE;
4037         }
4038
4039         if (audio_only) {
4040                 LOGE("disable overlay");
4041                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
4042
4043                 /* release overlay resource */
4044                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4045                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
4046                                 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4047                                 if (ret != MM_ERROR_NONE) {
4048                                         LOGE("failed to release overlay resource, ret(0x%x)\n", ret);
4049                                         goto ERROR;
4050                                 }
4051                         }
4052                 }
4053
4054                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4055                         if (resource_state == RESOURCE_STATE_PREPARED) {
4056                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4057                                 if (ret != MM_ERROR_NONE) {
4058                                         LOGE("failed to unprepare overlay resource, ret(0x%x)\n", ret);
4059                                         goto ERROR;
4060                                 }
4061                         }
4062                 }
4063         } else {
4064                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4065                         /* prepare resource manager for video overlay */
4066                         if (resource_state >= RESOURCE_STATE_INITIALIZED) {
4067                                 ret = _mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], RESOURCE_TYPE_VIDEO_OVERLAY);
4068                                 if (ret != MM_ERROR_NONE) {
4069                                         LOGE("could not prepare for video_overlay resource\n");
4070                                         goto ERROR;
4071                                 }
4072                         }
4073                 }
4074
4075                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
4076                         /* acquire resources for video overlay */
4077                         if (resource_state == RESOURCE_STATE_PREPARED) {
4078                                 ret = _mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4079                                 if (ret != MM_ERROR_NONE) {
4080                                         LOGE("could not acquire resources for video playing\n");
4081                                         _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
4082                                         goto ERROR;
4083                                 }
4084                         }
4085                 }
4086
4087                 LOGD("enable overlay");
4088                 __mmplayer_video_param_set_display_overlay(player);
4089                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4090         }
4091
4092 ERROR:
4093         MMPLAYER_FLEAVE();
4094         return MM_ERROR_NONE;
4095 }
4096
4097 int
4098 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4099 {
4100         mm_player_t* player = (mm_player_t*) hplayer;
4101         gboolean disable_overlay = FALSE;
4102
4103         MMPLAYER_FENTER();
4104
4105         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4106         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4107         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4108                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4109                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4110
4111         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4112                 LOGW("Display control is not supported");
4113                 return MM_ERROR_PLAYER_INTERNAL;
4114         }
4115
4116         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4117
4118         *paudio_only = (bool)(disable_overlay);
4119
4120         LOGD("audio_only : %d", *paudio_only);
4121
4122         MMPLAYER_FLEAVE();
4123
4124         return MM_ERROR_NONE;
4125 }
4126
4127 static int
4128 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4129 {
4130         GList* bucket = element_bucket;
4131         MMPlayerGstElement* element = NULL;
4132         MMPlayerGstElement* prv_element = NULL;
4133         gint successful_link_count = 0;
4134
4135         MMPLAYER_FENTER();
4136
4137         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4138
4139         prv_element = (MMPlayerGstElement*)bucket->data;
4140         bucket = bucket->next;
4141
4142         for (; bucket; bucket = bucket->next) {
4143                 element = (MMPlayerGstElement*)bucket->data;
4144
4145                 if (element && element->gst) {
4146                         /* If next element is audio appsrc then make a separate audio pipeline */
4147                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4148                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4149                                 prv_element = element;
4150                                 continue;
4151                         }
4152
4153                         if (prv_element && prv_element->gst) {
4154                                 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4155                                         LOGD("linking [%s] to [%s] success\n",
4156                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4157                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4158                                         successful_link_count++;
4159                                 } else {
4160                                         LOGD("linking [%s] to [%s] failed\n",
4161                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4162                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4163                                         return -1;
4164                                 }
4165                         }
4166                 }
4167
4168                 prv_element = element;
4169         }
4170
4171         MMPLAYER_FLEAVE();
4172
4173         return successful_link_count;
4174 }
4175
4176 static int
4177 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4178 {
4179         GList* bucket = element_bucket;
4180         MMPlayerGstElement* element = NULL;
4181         int successful_add_count = 0;
4182
4183         MMPLAYER_FENTER();
4184
4185         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4186         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4187
4188         for (; bucket; bucket = bucket->next) {
4189                 element = (MMPlayerGstElement*)bucket->data;
4190
4191                 if (element && element->gst) {
4192                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4193                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4194                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4195                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4196                                 return 0;
4197                         }
4198                         successful_add_count++;
4199                 }
4200         }
4201
4202         MMPLAYER_FLEAVE();
4203
4204         return successful_add_count;
4205 }
4206
4207 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4208 {
4209         mm_player_t* player = (mm_player_t*) data;
4210         GstCaps *caps = NULL;
4211         GstStructure *str = NULL;
4212         const char *name;
4213
4214         MMPLAYER_FENTER();
4215
4216         MMPLAYER_RETURN_IF_FAIL(pad)
4217         MMPLAYER_RETURN_IF_FAIL(unused)
4218         MMPLAYER_RETURN_IF_FAIL(data)
4219
4220         caps = gst_pad_get_current_caps(pad);
4221         if (!caps)
4222                 return;
4223
4224         str = gst_caps_get_structure(caps, 0);
4225         if (!str)
4226                 goto ERROR;
4227
4228         name = gst_structure_get_name(str);
4229         if (!name)
4230                 goto ERROR;
4231
4232         LOGD("name = %s\n", name);
4233
4234         if (strstr(name, "audio")) {
4235                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4236
4237                 if (player->audio_stream_changed_cb) {
4238                         LOGE("call the audio stream changed cb\n");
4239                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4240                 }
4241         } else if (strstr(name, "video")) {
4242                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4243
4244                 if (player->video_stream_changed_cb) {
4245                         LOGE("call the video stream changed cb\n");
4246                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4247                 }
4248         } else
4249                 goto ERROR;
4250
4251 ERROR:
4252
4253         gst_caps_unref(caps);
4254
4255         MMPLAYER_FLEAVE();
4256
4257         return;
4258 }
4259
4260
4261
4262 /**
4263  * This function is to create audio pipeline for playing.
4264  *
4265  * @param       player          [in]    handle of player
4266  *
4267  * @return      This function returns zero on success.
4268  * @remark
4269  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4270  */
4271 /* macro for code readability. just for sinkbin-creation functions */
4272 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4273 do {\
4274         x_bin[x_id].id = x_id;\
4275         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4276         if (!x_bin[x_id].gst) {\
4277                 LOGE("failed to create %s \n", x_factory);\
4278                 goto ERROR;\
4279         } else {\
4280                 if (x_player->ini.set_dump_element_flag)\
4281                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4282         } \
4283         if (x_add_bucket)\
4284                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4285 } while (0);
4286
4287 static void
4288 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4289 {
4290         GList *l = NULL;
4291
4292         MMPLAYER_FENTER();
4293         MMPLAYER_RETURN_IF_FAIL(player);
4294
4295         if (player->audio_stream_buff_list) {
4296                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4297                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4298                         if (tmp) {
4299                                 if (send_all) {
4300                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4301                                         __mmplayer_audio_stream_send_data(player, tmp);
4302                                 }
4303                                 if (tmp->pcm_data)
4304                                         g_free(tmp->pcm_data);
4305                                 g_free(tmp);
4306                         }
4307                 }
4308                 g_list_free(player->audio_stream_buff_list);
4309                 player->audio_stream_buff_list = NULL;
4310         }
4311
4312         MMPLAYER_FLEAVE();
4313 }
4314
4315 static void
4316 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4317 {
4318         MMPlayerAudioStreamDataType audio_stream = { 0, };
4319
4320         MMPLAYER_FENTER();
4321         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4322
4323         audio_stream.bitrate = a_buffer->bitrate;
4324         audio_stream.channel = a_buffer->channel;
4325         audio_stream.depth = a_buffer->depth;
4326         audio_stream.is_little_endian = a_buffer->is_little_endian;
4327         audio_stream.channel_mask = a_buffer->channel_mask;
4328         audio_stream.data_size = a_buffer->data_size;
4329         audio_stream.data = a_buffer->pcm_data;
4330
4331         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4332         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4333
4334         MMPLAYER_FLEAVE();
4335 }
4336
4337 static void
4338 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4339 {
4340         mm_player_t* player = (mm_player_t*) data;
4341
4342         gint channel = 0;
4343         gint rate = 0;
4344         gint depth = 0;
4345         gint endianness = 0;
4346         guint64 channel_mask = 0;
4347         void *a_data = NULL;
4348         gint a_size = 0;
4349         mm_player_audio_stream_buff_t *a_buffer = NULL;
4350         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4351         GList *l = NULL;
4352
4353         MMPLAYER_FENTER();
4354         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4355
4356         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4357         a_data = mapinfo.data;
4358         a_size = mapinfo.size;
4359
4360         GstCaps *caps = gst_pad_get_current_caps(pad);
4361         GstStructure *structure = gst_caps_get_structure(caps, 0);
4362
4363         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4364         gst_structure_get_int(structure, "rate", &rate);
4365         gst_structure_get_int(structure, "channels", &channel);
4366         gst_structure_get_int(structure, "depth", &depth);
4367         gst_structure_get_int(structure, "endianness", &endianness);
4368         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4369         gst_caps_unref(GST_CAPS(caps));
4370
4371         /* In case of the sync is false, use buffer list.              *
4372          * The num of buffer list depends on the num of audio channels */
4373         if (player->audio_stream_buff_list) {
4374                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4375                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4376                         if (tmp) {
4377                                 if (channel_mask == tmp->channel_mask) {
4378                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4379                                         if (tmp->data_size + a_size < tmp->buff_size) {
4380                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4381                                                 tmp->data_size += a_size;
4382                                         } else {
4383                                                 /* send data to client */
4384                                                 __mmplayer_audio_stream_send_data(player, tmp);
4385
4386                                                 if (a_size > tmp->buff_size) {
4387                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4388                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4389                                                         if (tmp->pcm_data == NULL) {
4390                                                                 LOGE("failed to realloc data.");
4391                                                                 goto DONE;
4392                                                         }
4393                                                         tmp->buff_size = a_size;
4394                                                 }
4395                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4396                                                 memcpy(tmp->pcm_data, a_data, a_size);
4397                                                 tmp->data_size = a_size;
4398                                         }
4399                                         goto DONE;
4400                                 }
4401                         } else {
4402                                 LOGE("data is empty in list.");
4403                                 goto DONE;
4404                         }
4405                 }
4406         }
4407
4408         /* create new audio stream data */
4409         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4410         if (a_buffer == NULL) {
4411                 LOGE("failed to alloc data.");
4412                 goto DONE;
4413         }
4414         a_buffer->bitrate = rate;
4415         a_buffer->channel = channel;
4416         a_buffer->depth = depth;
4417         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4418         a_buffer->channel_mask = channel_mask;
4419         a_buffer->data_size = a_size;
4420
4421         if (!player->audio_stream_sink_sync) {
4422                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4423                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4424                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4425                 if (a_buffer->pcm_data == NULL) {
4426                         LOGE("failed to alloc data.");
4427                         g_free(a_buffer);
4428                         goto DONE;
4429                 }
4430                 memcpy(a_buffer->pcm_data, a_data, a_size);
4431                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4432                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4433         } else {
4434                 /* If sync is TRUE, send data directly. */
4435                 a_buffer->pcm_data = a_data;
4436                 __mmplayer_audio_stream_send_data(player, a_buffer);
4437                 g_free(a_buffer);
4438         }
4439
4440 DONE:
4441         gst_buffer_unmap(buffer, &mapinfo);
4442         MMPLAYER_FLEAVE();
4443 }
4444
4445 static void
4446 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4447 {
4448         mm_player_t* player = (mm_player_t*)data;
4449         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4450         GstPad* sinkpad = NULL;
4451         GstElement *queue = NULL, *sink = NULL;
4452
4453         MMPLAYER_FENTER();
4454         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4455
4456         queue = gst_element_factory_make("queue", NULL);
4457         if (queue == NULL) {
4458                 LOGD("fail make queue\n");
4459                 goto ERROR;
4460         }
4461
4462         sink = gst_element_factory_make("fakesink", NULL);
4463         if (sink == NULL) {
4464                 LOGD("fail make fakesink\n");
4465                 goto ERROR;
4466         }
4467
4468         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4469
4470         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4471                 LOGW("failed to link queue & sink\n");
4472                 goto ERROR;
4473         }
4474
4475         sinkpad = gst_element_get_static_pad(queue, "sink");
4476
4477         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4478                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4479                 goto ERROR;
4480         }
4481
4482         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4483
4484         gst_object_unref(sinkpad);
4485         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4486         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4487
4488         gst_element_set_state(sink, GST_STATE_PAUSED);
4489         gst_element_set_state(queue, GST_STATE_PAUSED);
4490
4491         MMPLAYER_SIGNAL_CONNECT(player,
4492                 G_OBJECT(sink),
4493                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4494                 "handoff",
4495                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4496                 (gpointer)player);
4497
4498         MMPLAYER_FLEAVE();
4499         return ;
4500
4501 ERROR:
4502         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4503         if (queue) {
4504                 gst_object_unref(GST_OBJECT(queue));
4505                 queue = NULL;
4506         }
4507         if (sink) {
4508                 gst_object_unref(GST_OBJECT(sink));
4509                 sink = NULL;
4510         }
4511         if (sinkpad) {
4512                 gst_object_unref(GST_OBJECT(sinkpad));
4513                 sinkpad = NULL;
4514         }
4515
4516         return;
4517 }
4518
4519 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4520 {
4521         #define MAX_PROPS_LEN 128
4522         gint latency_mode = 0;
4523         gchar *stream_type = NULL;
4524         gchar *latency = NULL;
4525         gint stream_id = 0;
4526         gchar stream_props[MAX_PROPS_LEN] = {0,};
4527         GstStructure *props = NULL;
4528
4529         /* set volume table
4530          * It should be set after player creation through attribute.
4531          * But, it can not be changed during playing.
4532          */
4533         MMPLAYER_FENTER();
4534         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4535         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4536
4537         if (!stream_type) {
4538                 LOGE("stream_type is null.\n");
4539         } else {
4540                 if (player->sound_focus.focus_id)
4541                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d, mused.client_pid=%d",
4542                                         stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid);
4543                 else
4544                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, mused.client_pid=%d",
4545                                         stream_type, stream_id, player->sound_focus.pid);
4546                 props = gst_structure_from_string(stream_props, NULL);
4547                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4548                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], client_pid[%d], result[%s].\n",
4549                         stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid, stream_props);
4550         }
4551
4552         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4553
4554         switch (latency_mode) {
4555         case AUDIO_LATENCY_MODE_LOW:
4556                 latency = g_strndup("low", 3);
4557                 break;
4558         case AUDIO_LATENCY_MODE_MID:
4559                 latency = g_strndup("mid", 3);
4560                 break;
4561         case AUDIO_LATENCY_MODE_HIGH:
4562                 latency = g_strndup("high", 4);
4563                 break;
4564         };
4565
4566 #if 0 //need to check
4567         if (player->sound_focus.user_route_policy != 0)
4568                 route_path = player->sound_focus.user_route_policy;
4569
4570         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4571                         "latency", latency_mode,
4572                         NULL);
4573
4574         LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4575                 volume_type, route_path, latency_mode);
4576         MMPLAYER_FLEAVE();
4577
4578 #endif
4579
4580         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4581                         "latency", latency,
4582                         NULL);
4583
4584         LOGD("audiosink property - latency=%s \n", latency);
4585
4586         g_free(latency);
4587
4588         MMPLAYER_FLEAVE();
4589 }
4590
4591 static int
4592 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4593 {
4594         MMPlayerGstElement* first_element = NULL;
4595         MMPlayerGstElement* audiobin = NULL;
4596         MMHandleType attrs = 0;
4597         GstPad *pad = NULL;
4598         GstPad *ghostpad = NULL;
4599         GList* element_bucket = NULL;
4600         gboolean link_audio_sink_now = TRUE;
4601         int i = 0;
4602
4603         MMPLAYER_FENTER();
4604
4605         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4606
4607         /* alloc handles */
4608         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4609         if (!audiobin) {
4610                 LOGE("failed to allocate memory for audiobin\n");
4611                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4612         }
4613
4614         attrs = MMPLAYER_GET_ATTRS(player);
4615
4616         /* create bin */
4617         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4618         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4619         if (!audiobin[MMPLAYER_A_BIN].gst) {
4620                 LOGE("failed to create audiobin\n");
4621                 goto ERROR;
4622         }
4623
4624         /* take it */
4625         player->pipeline->audiobin = audiobin;
4626
4627         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4628
4629         /* Adding audiotp plugin for reverse trickplay feature */
4630 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4631
4632         /* converter */
4633         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4634
4635         /* resampler */
4636         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4637
4638         if (player->set_mode.pcm_extraction) {
4639                 // pcm extraction only and no sound output
4640                 if (player->audio_stream_render_cb_ex) {
4641                         char *caps_str = NULL;
4642                         GstCaps* caps = NULL;
4643                         gchar *format = NULL;
4644
4645                         /* capsfilter */
4646                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4647
4648                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4649
4650                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4651
4652                         caps = gst_caps_new_simple("audio/x-raw",
4653                                         "format", G_TYPE_STRING, format,
4654                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4655                                         "channels", G_TYPE_INT, player->pcm_channel,
4656                                         NULL);
4657                         caps_str = gst_caps_to_string(caps);
4658                         LOGD("new caps : %s\n", caps_str);
4659
4660                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4661
4662                         /* clean */
4663                         gst_caps_unref(caps);
4664                         MMPLAYER_FREEIF(caps_str);
4665
4666                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4667
4668                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4669                         /* raw pad handling signal */
4670                         MMPLAYER_SIGNAL_CONNECT(player,
4671                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4672                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4673                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4674                 } else {
4675                         int dst_samplerate = 0;
4676                         int dst_channels = 0;
4677                         int dst_depth = 0;
4678                         char *caps_str = NULL;
4679                         GstCaps* caps = NULL;
4680
4681                         /* get conf. values */
4682                         mm_attrs_multiple_get(player->attrs,
4683                                                 NULL,
4684                                                 "pcm_extraction_samplerate", &dst_samplerate,
4685                                                 "pcm_extraction_channels", &dst_channels,
4686                                                 "pcm_extraction_depth", &dst_depth,
4687                                                 NULL);
4688
4689                         /* capsfilter */
4690                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4691                         caps = gst_caps_new_simple("audio/x-raw",
4692                                         "rate", G_TYPE_INT, dst_samplerate,
4693                                         "channels", G_TYPE_INT, dst_channels,
4694                                         "depth", G_TYPE_INT, dst_depth,
4695                                         NULL);
4696                         caps_str = gst_caps_to_string(caps);
4697                         LOGD("new caps : %s\n", caps_str);
4698
4699                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4700
4701                         /* clean */
4702                         gst_caps_unref(caps);
4703                         MMPLAYER_FREEIF(caps_str);
4704
4705                         /* fake sink */
4706                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4707
4708                         /* set sync */
4709                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4710                 }
4711         } else {
4712                 // normal playback
4713                 //GstCaps* caps = NULL;
4714                 gint channels = 0;
4715
4716                 /* for logical volume control */
4717                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4718                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4719
4720                 if (player->sound.mute) {
4721                         LOGD("mute enabled\n");
4722                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4723                 }
4724
4725 #if 0
4726                 /*capsfilter */
4727                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4728                 caps = gst_caps_from_string("audio/x-raw-int, "
4729                                         "endianness = (int) LITTLE_ENDIAN, "
4730                                         "signed = (boolean) true, "
4731                                         "width = (int) 16, "
4732                                         "depth = (int) 16");
4733                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4734                 gst_caps_unref(caps);
4735 #endif
4736
4737                 /* chech if multi-chennels */
4738                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4739                         GstPad *srcpad = NULL;
4740                         GstCaps *caps = NULL;
4741
4742                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4743                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4744                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4745                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4746                                         if (str)
4747                                                 gst_structure_get_int(str, "channels", &channels);
4748                                         gst_caps_unref(caps);
4749                                 }
4750                                 gst_object_unref(srcpad);
4751                         }
4752                 }
4753
4754                 /* audio effect element. if audio effect is enabled */
4755                 if ((strcmp(player->ini.audioeffect_element, ""))
4756                         && (channels <= 2)
4757                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4758                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4759
4760                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4761
4762                         if ((!player->bypass_audio_effect)
4763                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4764                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4765                                         if (!_mmplayer_audio_effect_custom_apply(player))
4766                                                 LOGI("apply audio effect(custom) setting success\n");
4767                                 }
4768                         }
4769
4770                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4771                                 && (player->set_mode.rich_audio))
4772                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4773                 }
4774
4775                 /* create audio sink */
4776                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4777
4778                 /* qos on */
4779                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4780                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4781
4782
4783                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4784                         (player->videodec_linked && player->ini.use_system_clock)) {
4785                         LOGD("system clock will be used.\n");
4786                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4787                 }
4788
4789                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4790                         __mmplayer_gst_set_audiosink_property(player, attrs);
4791         }
4792
4793         if (audiobin[MMPLAYER_A_SINK].gst) {
4794                 GstPad *sink_pad = NULL;
4795                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4796                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4797                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4798                 gst_object_unref(GST_OBJECT(sink_pad));
4799         }
4800
4801         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4802
4803         /* adding created elements to bin */
4804         LOGD("adding created elements to bin\n");
4805         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4806                 LOGE("failed to add elements\n");
4807                 goto ERROR;
4808         }
4809
4810         /* linking elements in the bucket by added order. */
4811         LOGD("Linking elements in the bucket by added order.\n");
4812         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4813                 LOGE("failed to link elements\n");
4814                 goto ERROR;
4815         }
4816
4817         /* get first element's sinkpad for creating ghostpad */
4818         first_element = (MMPlayerGstElement *)element_bucket->data;
4819         if (!first_element) {
4820                 LOGE("failed to get first elem\n");
4821                 goto ERROR;
4822         }
4823
4824         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4825         if (!pad) {
4826                 LOGE("failed to get pad from first element of audiobin\n");
4827                 goto ERROR;
4828         }
4829
4830         ghostpad = gst_ghost_pad_new("sink", pad);
4831         if (!ghostpad) {
4832                 LOGE("failed to create ghostpad\n");
4833                 goto ERROR;
4834         }
4835
4836         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4837                 LOGE("failed to add ghostpad to audiobin\n");
4838                 goto ERROR;
4839         }
4840
4841         gst_object_unref(pad);
4842
4843         g_list_free(element_bucket);
4844
4845         mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4846
4847         MMPLAYER_FLEAVE();
4848
4849         return MM_ERROR_NONE;
4850
4851 ERROR:
4852
4853         LOGD("ERROR : releasing audiobin\n");
4854
4855         if (pad)
4856                 gst_object_unref(GST_OBJECT(pad));
4857
4858         if (ghostpad)
4859                 gst_object_unref(GST_OBJECT(ghostpad));
4860
4861         if (element_bucket)
4862                 g_list_free(element_bucket);
4863
4864         /* release element which are not added to bin */
4865         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4866                 /* NOTE : skip bin */
4867                 if (audiobin[i].gst) {
4868                         GstObject* parent = NULL;
4869                         parent = gst_element_get_parent(audiobin[i].gst);
4870
4871                         if (!parent) {
4872                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4873                                 audiobin[i].gst = NULL;
4874                         } else
4875                                 gst_object_unref(GST_OBJECT(parent));
4876                 }
4877         }
4878
4879         /* release audiobin with it's childs */
4880         if (audiobin[MMPLAYER_A_BIN].gst)
4881                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4882
4883         MMPLAYER_FREEIF(audiobin);
4884
4885         player->pipeline->audiobin = NULL;
4886
4887         return MM_ERROR_PLAYER_INTERNAL;
4888 }
4889
4890 static GstPadProbeReturn
4891 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4892 {
4893         mm_player_t* player = (mm_player_t*) u_data;
4894         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4895         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4896
4897         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4898
4899         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4900                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4901
4902         return GST_PAD_PROBE_OK;
4903 }
4904
4905 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4906 {
4907         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4908 }
4909
4910 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4911 {
4912         int ret = MM_ERROR_NONE;
4913         GList *l = NULL;
4914         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4915         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4916
4917         MMPLAYER_VIDEO_BO_LOCK(player);
4918
4919         if (player->video_bo_list) {
4920                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4921                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4922                         if (tmp && tmp->bo == bo) {
4923                                 tmp->using = FALSE;
4924                                 LOGD("release bo %p", bo);
4925                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4926                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4927                                 return ret;
4928                         }
4929                 }
4930         } else {
4931                 /* hw codec is running or the list was reset for DRC. */
4932                 LOGW("there is no bo list.");
4933         }
4934         MMPLAYER_VIDEO_BO_UNLOCK(player);
4935
4936         LOGW("failed to find bo %p", bo);
4937         return ret;
4938 }
4939
4940 static void
4941 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4942 {
4943         GList *l = NULL;
4944
4945         MMPLAYER_FENTER();
4946         MMPLAYER_RETURN_IF_FAIL(player);
4947
4948         MMPLAYER_VIDEO_BO_LOCK(player);
4949         if (player->video_bo_list) {
4950                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4951                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4952                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4953                         if (tmp) {
4954                                 if (tmp->bo)
4955                                         tbm_bo_unref(tmp->bo);
4956                                 g_free(tmp);
4957                         }
4958                 }
4959                 g_list_free(player->video_bo_list);
4960                 player->video_bo_list = NULL;
4961         }
4962         player->video_bo_size = 0;
4963         MMPLAYER_VIDEO_BO_UNLOCK(player);
4964
4965         MMPLAYER_FLEAVE();
4966         return;
4967 }
4968
4969 static void*
4970 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4971 {
4972         GList *l = NULL;
4973         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4974         gboolean ret = TRUE;
4975
4976         /* check DRC, if it is, destroy the prev bo list to create again */
4977         if (player->video_bo_size != size) {
4978                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4979                 __mmplayer_video_stream_destroy_bo_list(player);
4980                 player->video_bo_size = size;
4981         }
4982
4983         MMPLAYER_VIDEO_BO_LOCK(player);
4984
4985         if ((!player->video_bo_list) ||
4986                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4987
4988                 /* create bo list */
4989                 int idx = 0;
4990                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4991
4992                 if (player->video_bo_list) {
4993                         /* if bo list did not created all, try it again. */
4994                         idx = g_list_length(player->video_bo_list);
4995                         LOGD("bo list exist(len: %d)", idx);
4996                 }
4997
4998                 for (; idx < player->ini.num_of_video_bo; idx++) {
4999                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5000                         if (!bo_info) {
5001                                 LOGE("Fail to alloc bo_info.");
5002                                 break;
5003                         }
5004                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5005                         if (!bo_info->bo) {
5006                                 LOGE("Fail to tbm_bo_alloc.");
5007                                 g_free(bo_info);
5008                                 break;
5009                         }
5010                         bo_info->using = FALSE;
5011                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5012                 }
5013
5014                 /* update video num buffers */
5015                 player->video_num_buffers = idx;
5016                 if (idx == player->ini.num_of_video_bo)
5017                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5018
5019                 if (idx == 0) {
5020                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5021                         return NULL;
5022                 }
5023
5024                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5025         }
5026
5027         while (TRUE) {
5028                 /* get bo from list*/
5029                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5030                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5031                         if (tmp && (tmp->using == FALSE)) {
5032                                 LOGD("found bo %p to use", tmp->bo);
5033                                 tmp->using = TRUE;
5034                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5035                                 return tmp->bo;
5036                         }
5037                 }
5038                 if (!ret) {
5039                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5040                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5041                         return NULL;
5042                 }
5043
5044                 if (player->ini.video_bo_timeout <= 0) {
5045                         MMPLAYER_VIDEO_BO_WAIT(player);
5046                 } else {
5047                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5048                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5049                 }
5050                 continue;
5051         }
5052 }
5053
5054 static void
5055 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5056 {
5057         mm_player_t* player = (mm_player_t*)data;
5058         MMPLAYER_FENTER();
5059         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5060
5061         /* send prerolled pkt */
5062         player->video_stream_prerolled = FALSE;
5063
5064         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5065
5066         /* not to send prerolled pkt again */
5067         player->video_stream_prerolled = TRUE;
5068 }
5069
5070 static void
5071 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5072 {
5073         mm_player_t* player = (mm_player_t*)data;
5074         GstCaps *caps = NULL;
5075         MMPlayerVideoStreamDataType stream;
5076         MMVideoBuffer *video_buffer = NULL;
5077         GstMemory *dataBlock = NULL;
5078         GstMemory *metaBlock = NULL;
5079         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5080         GstStructure *structure = NULL;
5081         const gchar *string_format = NULL;
5082         unsigned int fourcc = 0;
5083
5084         MMPLAYER_FENTER();
5085         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5086
5087         if (player->video_stream_prerolled) {
5088                 player->video_stream_prerolled = FALSE;
5089                 LOGD("skip the prerolled pkt not to send it again");
5090                 return;
5091         }
5092
5093         caps = gst_pad_get_current_caps(pad);
5094         if (caps == NULL) {
5095                 LOGE("Caps is NULL.");
5096                 return;
5097         }
5098
5099         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5100
5101         /* clear stream data structure */
5102         memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5103
5104         structure = gst_caps_get_structure(caps, 0);
5105         gst_structure_get_int(structure, "width", & (stream.width));
5106         gst_structure_get_int(structure, "height", & (stream.height));
5107         string_format = gst_structure_get_string(structure, "format");
5108         if (string_format)
5109                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5110         stream.format = util_get_pixtype(fourcc);
5111         gst_caps_unref(caps);
5112         caps = NULL;
5113
5114     /*
5115         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5116                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5117     */
5118
5119         if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5120                 LOGE("Wrong condition!!");
5121                 return;
5122         }
5123
5124         /* set size and timestamp */
5125         dataBlock = gst_buffer_peek_memory(buffer, 0);
5126         stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5127         stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5128
5129         /* check zero-copy */
5130         if (player->set_mode.video_zc &&
5131                 player->set_mode.media_packet_video_stream &&
5132                 gst_buffer_n_memory(buffer) > 1) {
5133                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5134                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5135                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5136         }
5137
5138         if (video_buffer) { /* hw codec */
5139                 /* set tbm bo */
5140                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5141                         /* copy pointer of tbm bo, stride, elevation */
5142                         memcpy(stream.bo, video_buffer->handle.bo,
5143                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5144                 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5145                         /* FIXME: need to check this path */
5146                         memcpy(stream.data, video_buffer->data,
5147                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5148                 }
5149                 memcpy(stream.stride, video_buffer->stride_width,
5150                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5151                 memcpy(stream.elevation, video_buffer->stride_height,
5152                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5153                 /* set gst buffer */
5154                 stream.internal_buffer = buffer;
5155         } else { /* sw codec */
5156                 tbm_bo_handle thandle;
5157                 int stride = GST_ROUND_UP_4(stream.width);
5158                 int elevation = stream.height;
5159                 int size = 0;
5160
5161                 gboolean gst_ret;
5162                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5163                 if (!gst_ret) {
5164                         LOGE("fail to gst_memory_map");
5165                         return;
5166                 }
5167
5168                 stream.stride[0] = stride;
5169                 stream.elevation[0] = elevation;
5170                 if (stream.format == MM_PIXEL_FORMAT_I420) {
5171                         stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5172                         stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5173                         size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5174                 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5175                         stream.stride[0] = stream.width * 4;
5176                         size = stream.stride[0] * stream.height;
5177                 } else {
5178                         LOGE("Not support format %d", stream.format);
5179                         gst_memory_unmap(dataBlock, &mapinfo);
5180                         return;
5181                 }
5182                 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5183                 if (!stream.bo[0]) {
5184                         LOGE("Fail to tbm_bo_alloc!!");
5185                         gst_memory_unmap(dataBlock, &mapinfo);
5186                         return;
5187                 }
5188                 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5189                 if (thandle.ptr && mapinfo.data)
5190                         memcpy(thandle.ptr, mapinfo.data, size);
5191                 else
5192                         LOGE("data pointer is wrong. dest : %p, src : %p",
5193                                         thandle.ptr, mapinfo.data);
5194                 tbm_bo_unmap(stream.bo[0]);
5195         }
5196
5197         if (player->video_stream_cb)
5198                 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5199
5200         if (metaBlock)
5201                 gst_memory_unmap(metaBlock, &mapinfo);
5202         else
5203                 gst_memory_unmap(dataBlock, &mapinfo);
5204
5205         return;
5206 }
5207
5208 static int
5209 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5210 {
5211         MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5212         gchar* video_csc = "videoconvert"; // default colorspace converter
5213         GList* element_bucket = *bucket;
5214
5215         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5216
5217         MMPLAYER_FENTER();
5218
5219         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5220
5221         if (player->set_mode.video_zc) {
5222                 video_csc = ""; /* videosinks don't use videoconvert normally */
5223         } else {
5224                 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5225                 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5226                         video_csc = "videoconvert";
5227         }
5228         if (video_csc && (strcmp(video_csc, ""))) {
5229                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5230                 LOGD("using video converter: %s", video_csc);
5231         }
5232
5233         /* set video rotator */
5234         if (!player->set_mode.video_zc)
5235                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5236
5237         *bucket = element_bucket;
5238         MMPLAYER_FLEAVE();
5239         return MM_ERROR_NONE;
5240
5241 ERROR:
5242         *bucket = NULL;
5243         MMPLAYER_FLEAVE();
5244         return MM_ERROR_PLAYER_INTERNAL;
5245 }
5246
5247 /**
5248  * This function is to create video pipeline.
5249  *
5250  * @param       player          [in]    handle of player
5251  *              caps            [in]    src caps of decoder
5252  *              surface_type    [in]    surface type for video rendering
5253  *
5254  * @return      This function returns zero on success.
5255  * @remark
5256  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5257  */
5258 /**
5259   * VIDEO PIPELINE
5260   * - video overlay surface(arm/x86) : waylandsink
5261   */
5262 static int
5263 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5264 {
5265         GstPad *pad = NULL;
5266         MMHandleType attrs;
5267         GList*element_bucket = NULL;
5268         MMPlayerGstElement* first_element = NULL;
5269         MMPlayerGstElement* videobin = NULL;
5270         gchar *videosink_element = NULL;
5271
5272         MMPLAYER_FENTER();
5273
5274         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5275
5276         /* alloc handles */
5277         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5278         if (!videobin)
5279                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5280
5281         player->pipeline->videobin = videobin;
5282
5283         attrs = MMPLAYER_GET_ATTRS(player);
5284         if (!attrs) {
5285                 LOGE("cannot get content attribute");
5286                 return MM_ERROR_PLAYER_INTERNAL;
5287         }
5288
5289         /* create bin */
5290         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5291         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5292         if (!videobin[MMPLAYER_V_BIN].gst) {
5293                 LOGE("failed to create videobin");
5294                 goto ERROR;
5295         }
5296
5297         int enable_video_decoded_cb = 0;
5298         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5299
5300         /* set video sink */
5301         switch (surface_type) {
5302         case MM_DISPLAY_SURFACE_OVERLAY:
5303                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5304                         goto ERROR;
5305                 if (strlen(player->ini.videosink_element_overlay) > 0)
5306                         videosink_element = player->ini.videosink_element_overlay;
5307                 else
5308                         goto ERROR;
5309                 break;
5310         case MM_DISPLAY_SURFACE_NULL:
5311                 if (strlen(player->ini.videosink_element_fake) > 0)
5312                         videosink_element = player->ini.videosink_element_fake;
5313                 else
5314                         goto ERROR;
5315                 break;
5316         case MM_DISPLAY_SURFACE_REMOTE:
5317                 if (strlen(player->ini.videosink_element_fake) > 0)
5318                         videosink_element = player->ini.videosink_element_fake;
5319                 else
5320                         goto ERROR;
5321                 break;
5322         default:
5323                 LOGE("unidentified surface type");
5324                 goto ERROR;
5325         }
5326         LOGD("selected videosink name: %s", videosink_element);
5327
5328         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5329
5330         /* additional setting for sink plug-in */
5331         switch (surface_type) {
5332         case MM_DISPLAY_SURFACE_OVERLAY:
5333         {
5334                 bool use_tbm = player->set_mode.video_zc;
5335                 if (!use_tbm) {
5336                         LOGD("selected videosink name: %s", videosink_element);
5337
5338                         /* support shard memory with S/W codec on HawkP */
5339                         if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5340                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5341                                         "use-tbm", use_tbm, NULL);
5342                         }
5343                 } else {
5344                         if (attrs) {
5345                                 int gapless = 0;
5346
5347                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5348
5349                                 if (gapless > 0) {
5350                                         LOGD("disable last-sample");
5351                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5352                                 }
5353                         }
5354                 }
5355                 if (player->set_mode.media_packet_video_stream) {
5356                         int enable = 0;
5357                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5358                         if (enable)
5359                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5360
5361                         MMPLAYER_SIGNAL_CONNECT(player,
5362                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5363                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5364                                                                         "handoff",
5365                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5366                                                                         (gpointer)player);
5367
5368                         MMPLAYER_SIGNAL_CONNECT(player,
5369                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5370                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5371                                                                         "preroll-handoff",
5372                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5373                                                                         (gpointer)player);
5374                 }
5375                 break;
5376         }
5377         case MM_DISPLAY_SURFACE_REMOTE:
5378         {
5379                 if (player->set_mode.media_packet_video_stream) {
5380                         LOGE("add data probe at videosink");
5381                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5382                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5383
5384                         MMPLAYER_SIGNAL_CONNECT(player,
5385                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5386                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5387                                                                         "handoff",
5388                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5389                                                                         (gpointer)player);
5390
5391                         MMPLAYER_SIGNAL_CONNECT(player,
5392                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5394                                                                         "preroll-handoff",
5395                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5396                                                                         (gpointer)player);
5397                         if (attrs) {
5398                                 int gapless = 0;
5399
5400                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5401
5402                                 if (gapless > 0) {
5403                                         LOGD("disable last-sample");
5404                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5405                                 }
5406                         }
5407                 }
5408                 break;
5409         }
5410         default:
5411                 break;
5412         }
5413
5414         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5415                 goto ERROR;
5416
5417         if (videobin[MMPLAYER_V_SINK].gst) {
5418                 GstPad *sink_pad = NULL;
5419                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5420                 if (sink_pad) {
5421                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5422                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5423                         gst_object_unref(GST_OBJECT(sink_pad));
5424                 } else
5425                         LOGW("failed to get sink pad from videosink\n");
5426         }
5427
5428         /* store it as it's sink element */
5429         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5430
5431         /* adding created elements to bin */
5432         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5433                 LOGE("failed to add elements\n");
5434                 goto ERROR;
5435         }
5436
5437         /* Linking elements in the bucket by added order */
5438         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5439                 LOGE("failed to link elements\n");
5440                 goto ERROR;
5441         }
5442
5443         /* get first element's sinkpad for creating ghostpad */
5444         if (element_bucket)
5445                 first_element = (MMPlayerGstElement *)element_bucket->data;
5446         if (!first_element) {
5447                 LOGE("failed to get first element from bucket\n");
5448                 goto ERROR;
5449         }
5450
5451         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5452         if (!pad) {
5453                 LOGE("failed to get pad from first element\n");
5454                 goto ERROR;
5455         }
5456
5457         /* create ghostpad */
5458         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5459         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5460                 LOGE("failed to add ghostpad to videobin\n");
5461                 goto ERROR;
5462         }
5463         gst_object_unref(pad);
5464
5465         /* done. free allocated variables */
5466         if (element_bucket)
5467                 g_list_free(element_bucket);
5468
5469         MMPLAYER_FLEAVE();
5470
5471         return MM_ERROR_NONE;
5472
5473 ERROR:
5474         LOGE("ERROR : releasing videobin\n");
5475
5476         g_list_free(element_bucket);
5477
5478         if (pad)
5479                 gst_object_unref(GST_OBJECT(pad));
5480
5481         /* release videobin with it's childs */
5482         if (videobin[MMPLAYER_V_BIN].gst)
5483                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5484
5485
5486         MMPLAYER_FREEIF(videobin);
5487
5488         player->pipeline->videobin = NULL;
5489
5490         return MM_ERROR_PLAYER_INTERNAL;
5491 }
5492
5493 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5494 {
5495         GList *element_bucket = NULL;
5496         MMPlayerGstElement *textbin = player->pipeline->textbin;
5497
5498         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5499         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5500         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5501                                                         "signal-handoffs", FALSE,
5502                                                         NULL);
5503
5504         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5505         MMPLAYER_SIGNAL_CONNECT(player,
5506                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5507                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5508                                                         "handoff",
5509                                                         G_CALLBACK(__mmplayer_update_subtitle),
5510                                                         (gpointer)player);
5511
5512         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5513         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5514         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5515
5516         if (!player->play_subtitle) {
5517                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5518                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5519         }
5520
5521         /* adding created elements to bin */
5522         LOGD("adding created elements to bin\n");
5523         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5524                 LOGE("failed to add elements\n");
5525                 goto ERROR;
5526         }
5527
5528         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5529         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5530         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5531
5532         /* linking elements in the bucket by added order. */
5533         LOGD("Linking elements in the bucket by added order.\n");
5534         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5535                 LOGE("failed to link elements\n");
5536                 goto ERROR;
5537         }
5538
5539         /* done. free allocated variables */
5540         g_list_free(element_bucket);
5541
5542         if (textbin[MMPLAYER_T_QUEUE].gst) {
5543                 GstPad *pad = NULL;
5544                 GstPad *ghostpad = NULL;
5545
5546                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5547                 if (!pad) {
5548                         LOGE("failed to get sink pad of text queue");
5549                         goto ERROR;
5550                 }
5551
5552                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5553                 gst_object_unref(pad);
5554
5555                 if (!ghostpad) {
5556                         LOGE("failed to create ghostpad of textbin\n");
5557                         goto ERROR;
5558                 }
5559
5560                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5561                         LOGE("failed to add ghostpad to textbin\n");
5562                         gst_object_unref(ghostpad);
5563                         goto ERROR;
5564                 }
5565         }
5566
5567         return MM_ERROR_NONE;
5568
5569 ERROR:
5570         g_list_free(element_bucket);
5571
5572         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5573                 LOGE("remove textbin sink from sink list");
5574                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5575         }
5576
5577         /* release element at __mmplayer_gst_create_text_sink_bin */
5578         return MM_ERROR_PLAYER_INTERNAL;
5579 }
5580
5581 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5582 {
5583         MMPlayerGstElement *textbin = NULL;
5584         GList *element_bucket = NULL;
5585         int surface_type = 0;
5586         gint i = 0;
5587
5588         MMPLAYER_FENTER();
5589
5590         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5591
5592         /* alloc handles */
5593         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5594         if (!textbin) {
5595                 LOGE("failed to allocate memory for textbin\n");
5596                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5597         }
5598
5599         /* create bin */
5600         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5601         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5602         if (!textbin[MMPLAYER_T_BIN].gst) {
5603                 LOGE("failed to create textbin\n");
5604                 goto ERROR;
5605         }
5606
5607         /* take it */
5608         player->pipeline->textbin = textbin;
5609
5610         /* fakesink */
5611         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5612         LOGD("surface type for subtitle : %d", surface_type);
5613         switch (surface_type) {
5614         case MM_DISPLAY_SURFACE_OVERLAY:
5615         case MM_DISPLAY_SURFACE_NULL:
5616         case MM_DISPLAY_SURFACE_REMOTE:
5617                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5618                         LOGE("failed to make plain text elements\n");
5619                         goto ERROR;
5620                 }
5621                 break;
5622         default:
5623                 goto ERROR;
5624                 break;
5625         }
5626
5627         MMPLAYER_FLEAVE();
5628
5629         return MM_ERROR_NONE;
5630
5631 ERROR:
5632
5633         LOGD("ERROR : releasing textbin\n");
5634
5635         g_list_free(element_bucket);
5636
5637         /* release signal */
5638         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5639
5640         /* release element which are not added to bin */
5641         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5642                 /* NOTE : skip bin */
5643                 if (textbin[i].gst) {
5644                         GstObject* parent = NULL;
5645                         parent = gst_element_get_parent(textbin[i].gst);
5646
5647                         if (!parent) {
5648                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5649                                 textbin[i].gst = NULL;
5650                         } else {
5651                                 gst_object_unref(GST_OBJECT(parent));
5652                         }
5653                 }
5654         }
5655
5656         /* release textbin with it's childs */
5657         if (textbin[MMPLAYER_T_BIN].gst)
5658                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5659
5660         MMPLAYER_FREEIF(player->pipeline->textbin);
5661         player->pipeline->textbin = NULL;
5662
5663         MMPLAYER_FLEAVE();
5664         return MM_ERROR_PLAYER_INTERNAL;
5665 }
5666
5667
5668 static int
5669 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5670 {
5671         MMPlayerGstElement* mainbin = NULL;
5672         MMPlayerGstElement* textbin = NULL;
5673         MMHandleType attrs = 0;
5674         GstElement *subsrc = NULL;
5675         GstElement *subparse = NULL;
5676         gchar *subtitle_uri = NULL;
5677         const gchar *charset = NULL;
5678         GstPad *pad = NULL;
5679
5680         MMPLAYER_FENTER();
5681
5682         /* get mainbin */
5683         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5684                                                                 player->pipeline &&
5685                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5686
5687         mainbin = player->pipeline->mainbin;
5688
5689         attrs = MMPLAYER_GET_ATTRS(player);
5690         if (!attrs) {
5691                 LOGE("cannot get content attribute\n");
5692                 return MM_ERROR_PLAYER_INTERNAL;
5693         }
5694
5695         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5696         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5697                 LOGE("subtitle uri is not proper filepath.\n");
5698                 return MM_ERROR_PLAYER_INVALID_URI;
5699         }
5700
5701         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5702                 LOGE("failed to get storage info of subtitle path");
5703                 return MM_ERROR_PLAYER_INVALID_URI;
5704         }
5705
5706         LOGD("subtitle file path is [%s].\n", subtitle_uri);
5707
5708         /* create the subtitle source */
5709         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5710         if (!subsrc) {
5711                 LOGE("failed to create filesrc element\n");
5712                 goto ERROR;
5713         }
5714         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5715
5716         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5717         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5718
5719         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5720                 LOGW("failed to add queue\n");
5721                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5722                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5723                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5724                 goto ERROR;
5725         }
5726
5727         /* subparse */
5728         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5729         if (!subparse) {
5730                 LOGE("failed to create subparse element\n");
5731                 goto ERROR;
5732         }
5733
5734         charset = util_get_charset(subtitle_uri);
5735         if (charset) {
5736                 LOGD("detected charset is %s\n", charset);
5737                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5738         }
5739
5740         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5741         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5742
5743         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5744                 LOGW("failed to add subparse\n");
5745                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5746                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5747                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5748                 goto ERROR;
5749         }
5750
5751         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5752                 LOGW("failed to link subsrc and subparse\n");
5753                 goto ERROR;
5754         }
5755
5756         player->play_subtitle = TRUE;
5757         player->adjust_subtitle_pos = 0;
5758
5759         LOGD("play subtitle using subtitle file\n");
5760
5761         if (player->pipeline->textbin == NULL) {
5762                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5763                         LOGE("failed to create text sink bin. continuing without text\n");
5764                         goto ERROR;
5765                 }
5766
5767                 textbin = player->pipeline->textbin;
5768
5769                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5770                         LOGW("failed to add textbin\n");
5771
5772                         /* release signal */
5773                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5774
5775                         /* release textbin with it's childs */
5776                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5777                         MMPLAYER_FREEIF(player->pipeline->textbin);
5778                         player->pipeline->textbin = textbin = NULL;
5779                         goto ERROR;
5780                 }
5781
5782                 LOGD("link text input selector and textbin ghost pad");
5783
5784                 player->textsink_linked = 1;
5785                 player->external_text_idx = 0;
5786                 LOGI("player->textsink_linked set to 1\n");
5787         } else {
5788                 textbin = player->pipeline->textbin;
5789                 LOGD("text bin has been created. reuse it.");
5790                 player->external_text_idx = 1;
5791         }
5792
5793         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5794                 LOGW("failed to link subparse and textbin\n");
5795                 goto ERROR;
5796         }
5797
5798         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5799         if (!pad) {
5800                 LOGE("failed to get sink pad from textsink to probe data");
5801                 goto ERROR;
5802         }
5803
5804         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5805                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5806
5807         gst_object_unref(pad);
5808         pad = NULL;
5809
5810         /* create dot. for debugging */
5811         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5812         MMPLAYER_FLEAVE();
5813
5814         return MM_ERROR_NONE;
5815
5816 ERROR:
5817         /* release text pipeline resource */
5818         player->textsink_linked = 0;
5819
5820         /* release signal */
5821         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5822
5823         if (player->pipeline->textbin) {
5824                 LOGE("remove textbin");
5825
5826                 /* release textbin with it's childs */
5827                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5828                 MMPLAYER_FREEIF(player->pipeline->textbin);
5829                 player->pipeline->textbin = NULL;
5830
5831         }
5832
5833         /* release subtitle elem */
5834         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5835         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5836
5837         return MM_ERROR_PLAYER_INTERNAL;
5838 }
5839
5840 gboolean
5841 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5842 {
5843         mm_player_t* player = (mm_player_t*) data;
5844         MMMessageParamType msg = {0, };
5845         GstClockTime duration = 0;
5846         gpointer text = NULL;
5847         guint text_size = 0;
5848         gboolean ret = TRUE;
5849         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5850
5851         MMPLAYER_FENTER();
5852
5853         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5854         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5855
5856         if (player->is_subtitle_force_drop)
5857         {
5858                 LOGW("subtitle is dropped forcedly.");
5859                 return ret;
5860         }
5861
5862         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5863         text = mapinfo.data;
5864         text_size = mapinfo.size;
5865         duration = GST_BUFFER_DURATION(buffer);
5866
5867         if (player->set_mode.subtitle_off) {
5868                 LOGD("subtitle is OFF.\n");
5869                 return TRUE;
5870         }
5871
5872         if (!text || (text_size == 0)) {
5873                 LOGD("There is no subtitle to be displayed.\n");
5874                 return TRUE;
5875         }
5876
5877         msg.data = (void *) text;
5878         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5879
5880         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5881
5882         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5883         gst_buffer_unmap(buffer, &mapinfo);
5884
5885         MMPLAYER_FLEAVE();
5886
5887         return ret;
5888 }
5889
5890 static GstPadProbeReturn
5891 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5892
5893 {
5894         mm_player_t *player = (mm_player_t *) u_data;
5895         GstClockTime cur_timestamp = 0;
5896         gint64 adjusted_timestamp = 0;
5897         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5898
5899         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5900
5901         if (player->set_mode.subtitle_off) {
5902                 LOGD("subtitle is OFF.\n");
5903                 return TRUE;
5904         }
5905
5906         if (player->adjust_subtitle_pos == 0) {
5907                 LOGD("nothing to do");
5908                 return TRUE;
5909         }
5910
5911         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5912         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5913
5914         if (adjusted_timestamp < 0) {
5915                 LOGD("adjusted_timestamp under zero");
5916                 MMPLAYER_FLEAVE();
5917                 return FALSE;
5918         }
5919
5920         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5921         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5922                                 GST_TIME_ARGS(cur_timestamp),
5923                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5924
5925         return GST_PAD_PROBE_OK;
5926 }
5927 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5928 {
5929         MMPLAYER_FENTER();
5930
5931         /* check player and subtitlebin are created */
5932         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5933         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5934
5935         if (position == 0) {
5936                 LOGD("nothing to do\n");
5937                 MMPLAYER_FLEAVE();
5938                 return MM_ERROR_NONE;
5939         }
5940
5941         switch (format) {
5942         case MM_PLAYER_POS_FORMAT_TIME:
5943                 {
5944                         /* check current postion */
5945                         player->adjust_subtitle_pos = position;
5946
5947                         LOGD("save adjust_subtitle_pos in player") ;
5948                 }
5949                 break;
5950
5951         default:
5952                 {
5953                         LOGW("invalid format.\n");
5954                         MMPLAYER_FLEAVE();
5955                         return MM_ERROR_INVALID_ARGUMENT;
5956                 }
5957         }
5958
5959         MMPLAYER_FLEAVE();
5960
5961         return MM_ERROR_NONE;
5962 }
5963 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5964 {
5965         MMPLAYER_FENTER();
5966         LOGD("adjusting video_pos in player") ;
5967         int current_pos = 0;
5968         /* check player and videobin are created */
5969         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5970         if (!player->pipeline->videobin ||
5971                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5972                 LOGD("no video pipeline or sink is there");
5973                 return MM_ERROR_PLAYER_INVALID_STATE ;
5974         }
5975         if (offset == 0) {
5976                 LOGD("nothing to do\n");
5977                 MMPLAYER_FLEAVE();
5978                 return MM_ERROR_NONE;
5979         }
5980         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
5981                 LOGD("failed to get current position");
5982                 return MM_ERROR_PLAYER_INTERNAL;
5983         }
5984         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5985                 LOGD("enter video delay is valid");
5986         } else {
5987                 LOGD("enter video delay is crossing content boundary");
5988                 return MM_ERROR_INVALID_ARGUMENT ;
5989         }
5990         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5991         LOGD("video delay has been done");
5992         MMPLAYER_FLEAVE();
5993
5994         return MM_ERROR_NONE;
5995 }
5996
5997 static void
5998 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
5999 {
6000         GstElement *appsrc = element;
6001         tBuffer *buf = (tBuffer *)user_data;
6002         GstBuffer *buffer = NULL;
6003         GstFlowReturn ret = GST_FLOW_OK;
6004         gint len = size;
6005
6006         MMPLAYER_RETURN_IF_FAIL(element);
6007         MMPLAYER_RETURN_IF_FAIL(buf);
6008
6009         buffer = gst_buffer_new();
6010
6011         if (buf->offset >= buf->len) {
6012                 LOGD("call eos appsrc\n");
6013                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6014                 return;
6015         }
6016
6017         if (buf->len - buf->offset < size)
6018                 len = buf->len - buf->offset;
6019
6020         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6021         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6022         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6023
6024         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6025         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6026
6027         buf->offset += len;
6028 }
6029
6030 static gboolean
6031 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6032 {
6033         tBuffer *buf = (tBuffer *)user_data;
6034
6035         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6036
6037         buf->offset  = (int)size;
6038
6039         return TRUE;
6040 }
6041
6042 static GstBusSyncReply
6043 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6044 {
6045         mm_player_t *player = (mm_player_t *)data;
6046         GstBusSyncReply reply = GST_BUS_DROP;
6047
6048         if (!(player->pipeline && player->pipeline->mainbin)) {
6049                 LOGE("player pipeline handle is null");
6050                 return GST_BUS_PASS;
6051         }
6052
6053         if (!__mmplayer_check_useful_message(player, message)) {
6054                 gst_message_unref(message);
6055                 return GST_BUS_DROP;
6056         }
6057
6058         switch (GST_MESSAGE_TYPE(message)) {
6059         case GST_MESSAGE_STATE_CHANGED:
6060                 /* post directly for fast launch */
6061                 if (player->sync_handler) {
6062                         __mmplayer_gst_callback(NULL, message, player);
6063                         reply = GST_BUS_DROP;
6064                 } else
6065                         reply = GST_BUS_PASS;
6066                 break;
6067         case GST_MESSAGE_TAG:
6068                 __mmplayer_gst_extract_tag_from_msg(player, message);
6069
6070                 #if 0 // debug
6071                 {
6072                         GstTagList *tags = NULL;
6073
6074                         gst_message_parse_tag(message, &tags);
6075                         if (tags) {
6076                                 LOGE("TAGS received from element \"%s\".\n",
6077                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6078
6079                                 gst_tag_list_foreach(tags, print_tag, NULL);
6080                                 gst_tag_list_free(tags);
6081                                 tags = NULL;
6082                         }
6083                         break;
6084                 }
6085                 #endif
6086                 break;
6087
6088         case GST_MESSAGE_DURATION_CHANGED:
6089                 __mmplayer_gst_handle_duration(player, message);
6090                 break;
6091         case GST_MESSAGE_ASYNC_DONE:
6092                 /* NOTE:Don't call gst_callback directly
6093                  * because previous frame can be showed even though this message is received for seek.
6094                  */
6095         default:
6096                 reply = GST_BUS_PASS;
6097                 break;
6098         }
6099
6100         if (reply == GST_BUS_DROP)
6101                 gst_message_unref(message);
6102
6103         return reply;
6104 }
6105
6106 static gboolean
6107 __mmplayer_gst_create_decoder(mm_player_t *player,
6108                                                                 MMPlayerTrackType track,
6109                                                                 GstPad* srcpad,
6110                                                                 enum MainElementID elemId,
6111                                                                 const gchar* name)
6112 {
6113         gboolean ret = TRUE;
6114         GstPad *sinkpad = NULL;
6115
6116         MMPLAYER_FENTER();
6117
6118         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6119                                                 player->pipeline &&
6120                                                 player->pipeline->mainbin, FALSE);
6121         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6122         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6123         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6124
6125         GstElement *decodebin = NULL;
6126         GstCaps *dec_caps = NULL;
6127
6128         /* create decodebin */
6129         decodebin = gst_element_factory_make("decodebin", name);
6130
6131         if (!decodebin) {
6132                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6133                 ret = FALSE;
6134                 goto ERROR;
6135         }
6136
6137         /* raw pad handling signal */
6138         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6139                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6140
6141         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6142         before looking for any elements that can handle that stream.*/
6143         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6144                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6145
6146         /* This signal is emitted when a element is added to the bin.*/
6147         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6148                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6149
6150         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6151                 LOGE("failed to add new decodebin\n");
6152                 ret = FALSE;
6153                 goto ERROR;
6154         }
6155
6156         dec_caps = gst_pad_query_caps(srcpad, NULL);
6157         if (dec_caps) {
6158                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6159                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6160                 gst_caps_unref(dec_caps);
6161         }
6162
6163         player->pipeline->mainbin[elemId].id = elemId;
6164         player->pipeline->mainbin[elemId].gst = decodebin;
6165
6166         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6167
6168         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6169                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6170                 gst_object_unref(GST_OBJECT(decodebin));
6171         }
6172
6173         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6174                 LOGE("failed to sync second level decodebin state with parent\n");
6175
6176         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6177
6178 ERROR:
6179         if (sinkpad) {
6180                 gst_object_unref(GST_OBJECT(sinkpad));
6181                 sinkpad = NULL;
6182         }
6183         MMPLAYER_FLEAVE();
6184
6185         return ret;
6186 }
6187
6188 /**
6189  * This function is to create  audio or video pipeline for playing.
6190  *
6191  * @param       player          [in]    handle of player
6192  *
6193  * @return      This function returns zero on success.
6194  * @remark
6195  * @see
6196  */
6197 static int
6198 __mmplayer_gst_create_pipeline(mm_player_t* player)
6199 {
6200         GstBus  *bus = NULL;
6201         MMPlayerGstElement *mainbin = NULL;
6202         MMHandleType attrs = 0;
6203         GstElement* element = NULL;
6204         GstElement* elem_src_audio = NULL;
6205         GstElement* elem_src_subtitle = NULL;
6206         GstElement* es_video_queue = NULL;
6207         GstElement* es_audio_queue = NULL;
6208         GstElement* es_subtitle_queue = NULL;
6209         GList* element_bucket = NULL;
6210         gboolean need_state_holder = TRUE;
6211         gint i = 0;
6212 #ifdef SW_CODEC_ONLY
6213         int surface_type = 0;
6214 #endif
6215         MMPLAYER_FENTER();
6216
6217         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6218
6219         /* get profile attribute */
6220         attrs = MMPLAYER_GET_ATTRS(player);
6221         if (!attrs) {
6222                 LOGE("cannot get content attribute\n");
6223                 goto INIT_ERROR;
6224         }
6225
6226         /* create pipeline handles */
6227         if (player->pipeline) {
6228                 LOGW("pipeline should be released before create new one\n");
6229                 goto INIT_ERROR;
6230         }
6231
6232         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6233         if (player->pipeline == NULL)
6234                 goto INIT_ERROR;
6235
6236         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6237
6238
6239         /* create mainbin */
6240         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6241         if (mainbin == NULL)
6242                 goto INIT_ERROR;
6243
6244         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6245
6246         /* create pipeline */
6247         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6248         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6249         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6250                 LOGE("failed to create pipeline\n");
6251                 goto INIT_ERROR;
6252         }
6253         player->demux_pad_index = 0;
6254         player->subtitle_language_list = NULL;
6255
6256         player->is_subtitle_force_drop = FALSE;
6257         player->last_multiwin_status = FALSE;
6258
6259         _mmplayer_track_initialize(player);
6260         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6261
6262         /* create source element */
6263         switch (player->profile.uri_type) {
6264         /* rtsp streamming */
6265         case MM_PLAYER_URI_TYPE_URL_RTSP:
6266                 {
6267                         gint network_bandwidth;
6268                         gchar *user_agent, *wap_profile;
6269
6270                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6271
6272                         if (!element) {
6273                                 LOGE("failed to create streaming source element\n");
6274                                 break;
6275                         }
6276
6277                         /* make it zero */
6278                         network_bandwidth = 0;
6279                         user_agent = wap_profile = NULL;
6280
6281                         /* get attribute */
6282                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6283                         mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6284                         mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6285
6286                         SECURE_LOGD("user_agent : %s\n", user_agent);
6287                         SECURE_LOGD("wap_profile : %s\n", wap_profile);
6288
6289                         /* setting property to streaming source */
6290                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6291                         if (user_agent)
6292                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6293                         if (wap_profile)
6294                                 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6295
6296                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6297                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6298                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6299                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6300
6301                         player->use_decodebin = FALSE;
6302                 }
6303                 break;
6304
6305         /* http streaming*/
6306         case MM_PLAYER_URI_TYPE_URL_HTTP:
6307                 {
6308                         gchar *user_agent, *proxy, *cookies, **cookie_list;
6309                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6310                         user_agent = proxy = cookies = NULL;
6311                         cookie_list = NULL;
6312                         gint mode = MM_PLAYER_PD_MODE_NONE;
6313
6314                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6315
6316                         player->pd_mode = mode;
6317
6318                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6319
6320                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6321                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6322                                 if (!element) {
6323                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6324                                         break;
6325                                 }
6326                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6327
6328                                 /* get attribute */
6329                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6330                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6331                                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6332                                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6333
6334                                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6335                                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6336                                         LOGD("get timeout from ini\n");
6337                                         http_timeout = player->ini.http_timeout;
6338                                 }
6339
6340                                 /* get attribute */
6341                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6342                                 SECURE_LOGD("cookies : %s\n", cookies);
6343                                 SECURE_LOGD("proxy : %s\n", proxy);
6344                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6345                                 LOGD("timeout : %d\n",  http_timeout);
6346
6347                                 /* setting property to streaming source */
6348                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6349                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6350                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6351
6352                                 /* check if prosy is vailid or not */
6353                                 if (util_check_valid_url(proxy))
6354                                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6355                                 /* parsing cookies */
6356                                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6357                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6358                                 if (user_agent)
6359                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6360
6361                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6362                                         LOGW("it's dash. and it's still experimental feature.");
6363                         } else {
6364                                 // progressive download
6365                                 gchar* location = NULL;
6366
6367                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6368                                         gchar *path = NULL;
6369
6370                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6371
6372                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6373
6374                                         LOGD("PD Location : %s\n", path);
6375
6376                                         if (path) {
6377                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6378                                                         LOGE("failed to get storage info");
6379                                                         break;
6380                                                 }
6381                                                 player->pd_file_save_path = g_strdup(path);
6382                                         } else {
6383                                                 LOGE("can't find pd location so, it should be set \n");
6384                                                 break;
6385                                         }
6386                                 }
6387
6388                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6389                                 if (!element) {
6390                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6391                                         break;
6392                                 }
6393
6394                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6395                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6396                                 else
6397                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6398                                 g_object_get(element, "location", &location, NULL);
6399                                 LOGD("PD_LOCATION [%s].\n", location);
6400                                 if(location)
6401                                         g_free(location);
6402                         }
6403                 }
6404                 break;
6405
6406         /* file source */
6407         case MM_PLAYER_URI_TYPE_FILE:
6408                 {
6409                         LOGD("using filesrc for 'file://' handler.\n");
6410                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6411                                 LOGE("failed to get storage info");
6412                                 break;
6413                         }
6414
6415                         element = gst_element_factory_make("filesrc", "source");
6416                         if (!element) {
6417                                 LOGE("failed to create filesrc\n");
6418                                 break;
6419                         }
6420
6421                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6422                 }
6423                 break;
6424
6425         case MM_PLAYER_URI_TYPE_SS:
6426                 {
6427                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6428                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6429                         if (!element) {
6430                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6431                                 break;
6432                         }
6433
6434                         mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6435
6436                         if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6437                                 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6438                                 LOGD("get timeout from ini\n");
6439                                 http_timeout = player->ini.http_timeout;
6440                         }
6441
6442                         /* setting property to streaming source */
6443                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6444                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6445                 }
6446                 break;
6447         case MM_PLAYER_URI_TYPE_MS_BUFF:
6448                 {
6449                         LOGD("MS buff src is selected\n");
6450
6451                         if (player->v_stream_caps) {
6452                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6453                                 if (!element) {
6454                                         LOGF("failed to create video app source element[appsrc].\n");
6455                                         break;
6456                                 }
6457
6458                                 if (player->a_stream_caps) {
6459                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6460                                         if (!elem_src_audio) {
6461                                                 LOGF("failed to create audio app source element[appsrc].\n");
6462                                                 break;
6463                                         }
6464                                 }
6465                         } else if (player->a_stream_caps) {
6466                                 /* no video, only audio pipeline*/
6467                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6468                                 if (!element) {
6469                                         LOGF("failed to create audio app source element[appsrc].\n");
6470                                         break;
6471                                 }
6472                         }
6473
6474                         if (player->s_stream_caps) {
6475                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6476                                 if (!elem_src_subtitle) {
6477                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6478                                         break;
6479                                 }
6480                         }
6481
6482                         LOGD("setting app sources properties.\n");
6483                         LOGD("location : %s\n", player->profile.uri);
6484
6485                         if (player->v_stream_caps && element) {
6486                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6487                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6488                                                                                                 "caps", player->v_stream_caps, NULL);
6489
6490                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6491                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6492                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6493                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6494
6495                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6496                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6497                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6498                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6499
6500                                 if (player->a_stream_caps && elem_src_audio) {
6501                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6502                                                                                                                         "caps", player->a_stream_caps, NULL);
6503
6504                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6505                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6506                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6507                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6508
6509                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6510                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6511                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6512                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6513                                 }
6514                         } else if (player->a_stream_caps && element) {
6515                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6516                                                                                                 "caps", player->a_stream_caps, NULL);
6517
6518                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6519                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6520                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6521                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6522
6523                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6524                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6525                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6526                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6527                         }
6528
6529                         if (player->s_stream_caps && elem_src_subtitle) {
6530                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6531                                                                                                                  "caps", player->s_stream_caps, NULL);
6532
6533                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6534                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6535                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6536                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6537
6538                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6539
6540                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6541                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6542                         }
6543
6544                         if (player->v_stream_caps && element) {
6545                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6546                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6547                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6548                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6549
6550                                 if (player->a_stream_caps && elem_src_audio) {
6551                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6552                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6553                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6554                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6555                                 }
6556                         } else if (player->a_stream_caps && element) {
6557                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6558                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6559                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6560                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6561                         }
6562
6563                         if (player->s_stream_caps && elem_src_subtitle)
6564                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6565                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6566
6567                         need_state_holder = FALSE;
6568
6569                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6570                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6571                                 LOGE("failed to commit\n");
6572                 }
6573                 break;
6574         /* appsrc */
6575         case MM_PLAYER_URI_TYPE_MEM:
6576                 {
6577                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6578
6579                         LOGD("mem src is selected\n");
6580
6581                         element = gst_element_factory_make("appsrc", "mem-source");
6582                         if (!element) {
6583                                 LOGE("failed to create appsrc element\n");
6584                                 break;
6585                         }
6586
6587                         g_object_set(element, "stream-type", stream_type, NULL);
6588                         g_object_set(element, "size", player->mem_buf.len, NULL);
6589                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6590
6591                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6592                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6593                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6594                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6595                 }
6596                 break;
6597         case MM_PLAYER_URI_TYPE_URL:
6598                 break;
6599
6600         case MM_PLAYER_URI_TYPE_TEMP:
6601                 break;
6602
6603         case MM_PLAYER_URI_TYPE_NONE:
6604         default:
6605                 break;
6606         }
6607
6608         /* check source element is OK */
6609         if (!element) {
6610                 LOGE("no source element was created.\n");
6611                 goto INIT_ERROR;
6612         }
6613
6614         /* take source element */
6615         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6616         mainbin[MMPLAYER_M_SRC].gst = element;
6617         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6618
6619         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6620                 player->streamer = __mm_player_streaming_create();
6621                 __mm_player_streaming_initialize(player->streamer);
6622         }
6623
6624         if (MMPLAYER_IS_HTTP_PD(player)) {
6625                 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6626
6627                 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6628                 element = gst_element_factory_make("queue2", "queue2");
6629                 if (!element) {
6630                         LOGE("failed to create http streaming buffer element\n");
6631                         goto INIT_ERROR;
6632                 }
6633
6634                 /* take it */
6635                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6636                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6637                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6638
6639                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6640
6641                 __mm_player_streaming_set_queue2(player->streamer,
6642                                 element,
6643                                 TRUE,
6644                                 player->ini.http_max_size_bytes,
6645                                 pre_buffering_time,
6646                                 1.0,
6647                                 player->ini.http_buffering_limit,
6648                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6649                                 NULL,
6650                                 0);
6651         }
6652         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6653                 if (player->v_stream_caps) {
6654                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6655                         if (!es_video_queue) {
6656                                 LOGE("create es_video_queue for es player failed\n");
6657                                 goto INIT_ERROR;
6658                         }
6659                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6660                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6661                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6662                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6663
6664                         /* Adding audio appsrc to bucket */
6665                         if (player->a_stream_caps && elem_src_audio) {
6666                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6667                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6668                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6669
6670                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6671                                 if (!es_audio_queue) {
6672                                         LOGE("create es_audio_queue for es player failed\n");
6673                                         goto INIT_ERROR;
6674                                 }
6675                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6676
6677                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6678                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6679                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6680                         }
6681                 } else if (player->a_stream_caps) {
6682                         /* Only audio stream, no video */
6683                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6684                         if (!es_audio_queue) {
6685                                 LOGE("create es_audio_queue for es player failed\n");
6686                                 goto INIT_ERROR;
6687                         }
6688                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6689                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6690                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6691                 }
6692
6693                 if (player->s_stream_caps && elem_src_subtitle) {
6694                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6695                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6696                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6697
6698                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6699                         if (!es_subtitle_queue) {
6700                                 LOGE("create es_subtitle_queue for es player failed\n");
6701                                 goto INIT_ERROR;
6702                         }
6703                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6704                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6705                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6706                 }
6707         }
6708
6709         /* create autoplugging element if src element is not a rtsp src */
6710         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6711                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6712                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6713                 element = NULL;
6714                 enum MainElementID elemId = MMPLAYER_M_NUM;
6715
6716                 if ((player->use_decodebin) &&
6717                         ((MMPLAYER_IS_HTTP_PD(player)) ||
6718                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6719                         elemId = MMPLAYER_M_AUTOPLUG;
6720                         element = __mmplayer_create_decodebin(player);
6721                         if (element) {
6722                                 /* default size of mq in decodebin is 2M
6723                                  * but it can cause blocking issue during seeking depends on content. */
6724                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6725                         }
6726                         need_state_holder = FALSE;
6727                 } else {
6728                         elemId = MMPLAYER_M_TYPEFIND;
6729                         element = gst_element_factory_make("typefind", "typefinder");
6730                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6731                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6732                 }
6733
6734
6735                 /* check autoplug element is OK */
6736                 if (!element) {
6737                         LOGE("can not create element(%d)\n", elemId);
6738                         goto INIT_ERROR;
6739                 }
6740
6741                 mainbin[elemId].id = elemId;
6742                 mainbin[elemId].gst = element;
6743
6744                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6745         }
6746
6747         /* add elements to pipeline */
6748         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6749                 LOGE("Failed to add elements to pipeline\n");
6750                 goto INIT_ERROR;
6751         }
6752
6753
6754         /* linking elements in the bucket by added order. */
6755         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6756                 LOGE("Failed to link some elements\n");
6757                 goto INIT_ERROR;
6758         }
6759
6760
6761         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6762         if (need_state_holder) {
6763                 /* create */
6764                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6765                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6766
6767                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6768                         LOGE("fakesink element could not be created\n");
6769                         goto INIT_ERROR;
6770                 }
6771                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6772
6773                 /* take ownership of fakesink. we are reusing it */
6774                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6775
6776                 /* add */
6777                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6778                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6779                         LOGE("failed to add fakesink to bin\n");
6780                         goto INIT_ERROR;
6781                 }
6782         }
6783
6784         /* now we have completed mainbin. take it */
6785         player->pipeline->mainbin = mainbin;
6786
6787         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6788                 GstPad *srcpad = NULL;
6789
6790                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6791                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6792                         if (srcpad) {
6793                                 __mmplayer_gst_create_decoder(player,
6794                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6795                                                                                                 srcpad,
6796                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6797                                                                                                 "video_decodebin");
6798
6799                                 gst_object_unref(GST_OBJECT(srcpad));
6800                                 srcpad = NULL;
6801                         }
6802                 }
6803
6804                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6805                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6806                         if (srcpad) {
6807                                 __mmplayer_gst_create_decoder(player,
6808                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6809                                                                                                 srcpad,
6810                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6811                                                                                                 "audio_decodebin");
6812
6813                                 gst_object_unref(GST_OBJECT(srcpad));
6814                                 srcpad = NULL;
6815                         } // else error
6816                 } //  else error
6817
6818                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6819                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6820         }
6821
6822         /* connect bus callback */
6823         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6824         if (!bus) {
6825                 LOGE("cannot get bus from pipeline.\n");
6826                 goto INIT_ERROR;
6827         }
6828
6829         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6830
6831         player->context.thread_default = g_main_context_get_thread_default();
6832
6833         if (NULL == player->context.thread_default) {
6834                 player->context.thread_default = g_main_context_default();
6835                 LOGD("thread-default context is the global default context");
6836         }
6837         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6838
6839         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6840         if (__mmplayer_check_subtitle(player)) {
6841                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6842                         LOGE("fail to create text pipeline");
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         MMPLAYER_FLEAVE();
6853
6854         return MM_ERROR_NONE;
6855
6856 INIT_ERROR:
6857
6858         __mmplayer_gst_destroy_pipeline(player);
6859         g_list_free(element_bucket);
6860
6861         if (mainbin) {
6862                 /* release element which are not added to bin */
6863                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6864                         /* NOTE : skip pipeline */
6865                         if (mainbin[i].gst) {
6866                                 GstObject* parent = NULL;
6867                                 parent = gst_element_get_parent(mainbin[i].gst);
6868
6869                                 if (!parent) {
6870                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6871                                         mainbin[i].gst = NULL;
6872                                 } else
6873                                         gst_object_unref(GST_OBJECT(parent));
6874                         }
6875                 }
6876
6877                 /* release pipeline with it's childs */
6878                 if (mainbin[MMPLAYER_M_PIPE].gst)
6879                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6880
6881                 MMPLAYER_FREEIF(mainbin);
6882         }
6883
6884         MMPLAYER_FREEIF(player->pipeline);
6885         return MM_ERROR_PLAYER_INTERNAL;
6886 }
6887
6888 static void
6889 __mmplayer_reset_gapless_state(mm_player_t* player)
6890 {
6891         MMPLAYER_FENTER();
6892         MMPLAYER_RETURN_IF_FAIL(player
6893                 && player->pipeline
6894                 && player->pipeline->audiobin
6895                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6896
6897         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6898
6899         MMPLAYER_FLEAVE();
6900         return;
6901 }
6902
6903 static int
6904 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6905 {
6906         gint timeout = 0;
6907         int ret = MM_ERROR_NONE;
6908
6909         MMPLAYER_FENTER();
6910
6911         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6912
6913         /* cleanup stuffs */
6914         MMPLAYER_FREEIF(player->type);
6915         player->have_dynamic_pad = FALSE;
6916         player->no_more_pad = FALSE;
6917         player->num_dynamic_pad = 0;
6918         player->demux_pad_index = 0;
6919         player->subtitle_language_list = NULL;
6920         player->use_deinterleave = FALSE;
6921         player->max_audio_channels = 0;
6922         player->video_share_api_delta = 0;
6923         player->video_share_clock_delta = 0;
6924         player->video_hub_download_mode = 0;
6925         __mmplayer_reset_gapless_state(player);
6926
6927         if (player->streamer) {
6928                 __mm_player_streaming_deinitialize(player->streamer);
6929                 __mm_player_streaming_destroy(player->streamer);
6930                 player->streamer = NULL;
6931         }
6932
6933         /* cleanup unlinked mime type */
6934         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6935         MMPLAYER_FREEIF(player->unlinked_video_mime);
6936         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6937
6938         /* cleanup running stuffs */
6939         __mmplayer_cancel_eos_timer(player);
6940
6941         /* cleanup gst stuffs */
6942         if (player->pipeline) {
6943                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6944                 GstTagList* tag_list = player->pipeline->tag_list;
6945
6946                 /* first we need to disconnect all signal hander */
6947                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6948
6949                 /* disconnecting bus watch */
6950                 if (player->bus_watcher)
6951                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6952                 player->bus_watcher = 0;
6953
6954                 if (mainbin) {
6955                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6956                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6957                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6958                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6959                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6960                         gst_object_unref(bus);
6961
6962                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6963                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6964                         if (ret != MM_ERROR_NONE) {
6965                                 LOGE("fail to change state to NULL\n");
6966                                 return MM_ERROR_PLAYER_INTERNAL;
6967                         }
6968
6969                         LOGW("succeeded in chaning state to NULL\n");
6970
6971                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6972
6973                         /* free fakesink */
6974                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6975                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6976
6977                         /* free avsysaudiosink
6978                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6979                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6980                         */
6981                         MMPLAYER_FREEIF(audiobin);
6982                         MMPLAYER_FREEIF(videobin);
6983                         MMPLAYER_FREEIF(textbin);
6984                         MMPLAYER_FREEIF(mainbin);
6985                 }
6986
6987                 if (tag_list)
6988                         gst_tag_list_free(tag_list);
6989
6990                 MMPLAYER_FREEIF(player->pipeline);
6991         }
6992         MMPLAYER_FREEIF(player->album_art);
6993
6994         if (player->v_stream_caps) {
6995                 gst_caps_unref(player->v_stream_caps);
6996                 player->v_stream_caps = NULL;
6997         }
6998         if (player->a_stream_caps) {
6999                 gst_caps_unref(player->a_stream_caps);
7000                 player->a_stream_caps = NULL;
7001         }
7002
7003         if (player->s_stream_caps) {
7004                 gst_caps_unref(player->s_stream_caps);
7005                 player->s_stream_caps = NULL;
7006         }
7007         _mmplayer_track_destroy(player);
7008
7009         if (player->sink_elements)
7010                 g_list_free(player->sink_elements);
7011         player->sink_elements = NULL;
7012
7013         if (player->bufmgr) {
7014                 tbm_bufmgr_deinit(player->bufmgr);
7015                 player->bufmgr = NULL;
7016         }
7017
7018         LOGW("finished destroy pipeline\n");
7019
7020         MMPLAYER_FLEAVE();
7021
7022         return ret;
7023 }
7024
7025 static int __gst_realize(mm_player_t* player)
7026 {
7027         gint timeout = 0;
7028         int ret = MM_ERROR_NONE;
7029
7030         MMPLAYER_FENTER();
7031
7032         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7033
7034         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7035
7036         ret = __mmplayer_gst_create_pipeline(player);
7037         if (ret) {
7038                 LOGE("failed to create pipeline\n");
7039                 return ret;
7040         }
7041
7042         /* set pipeline state to READY */
7043         /* NOTE : state change to READY must be performed sync. */
7044         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7045         ret = __mmplayer_gst_set_state(player,
7046                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7047
7048         if (ret != MM_ERROR_NONE) {
7049                 /* return error if failed to set state */
7050                 LOGE("failed to set READY state");
7051                 return ret;
7052         }
7053
7054         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7055
7056         /* create dot before error-return. for debugging */
7057         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7058
7059         MMPLAYER_FLEAVE();
7060
7061         return ret;
7062 }
7063
7064 static int __gst_unrealize(mm_player_t* player)
7065 {
7066         int ret = MM_ERROR_NONE;
7067
7068         MMPLAYER_FENTER();
7069
7070         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7071
7072         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7073         MMPLAYER_PRINT_STATE(player);
7074
7075         /* release miscellaneous information */
7076         __mmplayer_release_misc(player);
7077
7078         /* destroy pipeline */
7079         ret = __mmplayer_gst_destroy_pipeline(player);
7080         if (ret != MM_ERROR_NONE) {
7081                 LOGE("failed to destory pipeline\n");
7082                 return ret;
7083         }
7084
7085         /* release miscellaneous information.
7086            these info needs to be released after pipeline is destroyed. */
7087         __mmplayer_release_misc_post(player);
7088
7089         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7090
7091         MMPLAYER_FLEAVE();
7092
7093         return ret;
7094 }
7095
7096 static int __gst_pending_seek(mm_player_t* player)
7097 {
7098         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7099         int ret = MM_ERROR_NONE;
7100
7101         MMPLAYER_FENTER();
7102
7103         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7104
7105         if (!player->pending_seek.is_pending) {
7106                 LOGD("pending seek is not reserved. nothing to do.\n");
7107                 return ret;
7108         }
7109
7110         /* check player state if player could pending seek or not. */
7111         current_state = MMPLAYER_CURRENT_STATE(player);
7112
7113         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7114                 LOGW("try to pending seek in %s state, try next time. \n",
7115                         MMPLAYER_STATE_GET_NAME(current_state));
7116                 return ret;
7117         }
7118
7119         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7120
7121         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7122
7123         if (MM_ERROR_NONE != ret)
7124                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7125
7126         player->pending_seek.is_pending = FALSE;
7127
7128         MMPLAYER_FLEAVE();
7129
7130         return ret;
7131 }
7132
7133 static int __gst_start(mm_player_t* player)
7134 {
7135         gboolean sound_extraction = 0;
7136         int ret = MM_ERROR_NONE;
7137         gboolean async = FALSE;
7138
7139         MMPLAYER_FENTER();
7140
7141         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7142
7143         /* get sound_extraction property */
7144         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7145
7146         /* NOTE : if SetPosition was called before Start. do it now */
7147         /* streaming doesn't support it. so it should be always sync */
7148         /* !!create one more api to check if there is pending seek rather than checking variables */
7149         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7150                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7151                 ret = __gst_pause(player, FALSE);
7152                 if (ret != MM_ERROR_NONE) {
7153                         LOGE("failed to set state to PAUSED for pending seek\n");
7154                         return ret;
7155                 }
7156
7157                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7158
7159                 if (sound_extraction) {
7160                         LOGD("setting pcm extraction\n");
7161
7162                         ret = __mmplayer_set_pcm_extraction(player);
7163                         if (MM_ERROR_NONE != ret) {
7164                                 LOGW("failed to set pcm extraction\n");
7165                                 return ret;
7166                         }
7167                 } else {
7168                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7169                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7170                 }
7171         }
7172
7173         LOGD("current state before doing transition");
7174         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7175         MMPLAYER_PRINT_STATE(player);
7176
7177         /* set pipeline state to PLAYING  */
7178         if (player->es_player_push_mode)
7179                 async = TRUE;
7180         /* set pipeline state to PLAYING  */
7181         ret = __mmplayer_gst_set_state(player,
7182                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7183
7184         if (ret == MM_ERROR_NONE) {
7185                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7186         } else {
7187                 LOGE("failed to set state to PLAYING");
7188                 return ret;
7189         }
7190
7191         /* generating debug info before returning error */
7192         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7193
7194         MMPLAYER_FLEAVE();
7195
7196         return ret;
7197 }
7198
7199 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7200 {
7201         MMPLAYER_FENTER();
7202
7203         MMPLAYER_RETURN_IF_FAIL(player
7204                 && player->pipeline
7205                 && player->pipeline->audiobin
7206                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7207
7208         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7209
7210         usleep(time);
7211
7212         MMPLAYER_FLEAVE();
7213 }
7214
7215 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7216 {
7217         MMPLAYER_FENTER();
7218
7219         MMPLAYER_RETURN_IF_FAIL(player
7220                 && player->pipeline
7221                 && player->pipeline->audiobin
7222                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7223
7224         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7225
7226         MMPLAYER_FLEAVE();
7227 }
7228
7229 static int __gst_stop(mm_player_t* player)
7230 {
7231         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7232         MMHandleType attrs = 0;
7233         gboolean fadedown = FALSE;
7234         gboolean rewind = FALSE;
7235         gint timeout = 0;
7236         int ret = MM_ERROR_NONE;
7237         gboolean async = FALSE;
7238
7239         MMPLAYER_FENTER();
7240
7241         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7242         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7243
7244         LOGD("current state before doing transition");
7245         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7246         MMPLAYER_PRINT_STATE(player);
7247
7248         attrs = MMPLAYER_GET_ATTRS(player);
7249         if (!attrs) {
7250                 LOGE("cannot get content attribute\n");
7251                 return MM_ERROR_PLAYER_INTERNAL;
7252         }
7253
7254         mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7255
7256         /* enable fadedown */
7257         if (fadedown || player->sound_focus.by_asm_cb)
7258                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7259
7260         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7261         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7262
7263         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7264                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7265                 rewind = TRUE;
7266
7267         if (player->es_player_push_mode)
7268                 async = TRUE;
7269         /* set gst state */
7270         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7271
7272         /* disable fadeout */
7273         if (fadedown || player->sound_focus.by_asm_cb)
7274                 __mmplayer_undo_sound_fadedown(player);
7275
7276         /* return if set_state has failed */
7277         if (ret != MM_ERROR_NONE) {
7278                 LOGE("failed to set state.\n");
7279                 return ret;
7280         }
7281
7282         /* rewind */
7283         if (rewind) {
7284                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7285                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7286                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7287                         LOGW("failed to rewind\n");
7288                         ret = MM_ERROR_PLAYER_SEEK;
7289                 }
7290         }
7291
7292         /* initialize */
7293         player->sent_bos = FALSE;
7294
7295         if (player->es_player_push_mode) //for cloudgame
7296                 timeout = 0;
7297
7298         /* wait for seek to complete */
7299         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7300         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7301                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7302         } else {
7303                 LOGE("fail to stop player.\n");
7304                 ret = MM_ERROR_PLAYER_INTERNAL;
7305                 __mmplayer_dump_pipeline_state(player);
7306         }
7307
7308         /* generate dot file if enabled */
7309         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7310
7311         MMPLAYER_FLEAVE();
7312
7313         return ret;
7314 }
7315
7316 int __gst_pause(mm_player_t* player, gboolean async)
7317 {
7318         int ret = MM_ERROR_NONE;
7319
7320         MMPLAYER_FENTER();
7321
7322         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7323         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7324
7325         LOGD("current state before doing transition");
7326         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7327         MMPLAYER_PRINT_STATE(player);
7328
7329         /* set pipeline status to PAUSED */
7330         player->ignore_asyncdone = TRUE;
7331
7332         ret = __mmplayer_gst_set_state(player,
7333                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7334
7335         player->ignore_asyncdone = FALSE;
7336
7337         if (FALSE == async) {
7338                 if (ret != MM_ERROR_NONE) {
7339                         GstMessage *msg = NULL;
7340                         GTimer *timer = NULL;
7341                         gdouble MAX_TIMEOUT_SEC = 3;
7342
7343                         LOGE("failed to set state to PAUSED");
7344
7345                         if (player->msg_posted) {
7346                                 LOGE("error msg is already posted.");
7347                                 return ret;
7348                         }
7349
7350                         timer = g_timer_new();
7351                         g_timer_start(timer);
7352
7353                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7354
7355                         do {
7356                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7357                                 if (msg) {
7358                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7359                                                 GError *error = NULL;
7360
7361                                                 /* parse error code */
7362                                                 gst_message_parse_error(msg, &error, NULL);
7363
7364                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7365                                                         /* Note : the streaming error from the streaming source is handled
7366                                                          *   using __mmplayer_handle_streaming_error.
7367                                                          */
7368                                                         __mmplayer_handle_streaming_error(player, msg);
7369
7370                                                 } else if (error) {
7371                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7372
7373                                                         if (error->domain == GST_STREAM_ERROR)
7374                                                                 ret = __gst_handle_stream_error(player, error, msg);
7375                                                         else if (error->domain == GST_RESOURCE_ERROR)
7376                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7377                                                         else if (error->domain == GST_LIBRARY_ERROR)
7378                                                                 ret = __gst_handle_library_error(player, error->code);
7379                                                         else if (error->domain == GST_CORE_ERROR)
7380                                                                 ret = __gst_handle_core_error(player, error->code);
7381                                                 }
7382                                                 player->msg_posted = TRUE;
7383                                         }
7384                                         gst_message_unref(msg);
7385                                 }
7386                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7387                         /* clean */
7388                         gst_object_unref(bus);
7389                         g_timer_stop(timer);
7390                         g_timer_destroy(timer);
7391
7392                         return ret;
7393
7394                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7395                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7396
7397                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7398
7399                 } else if (ret == MM_ERROR_NONE) {
7400
7401                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7402                 }
7403         }
7404
7405         /* generate dot file before returning error */
7406         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7407
7408         MMPLAYER_FLEAVE();
7409
7410         return ret;
7411 }
7412
7413 int __gst_resume(mm_player_t* player, gboolean async)
7414 {
7415         int ret = MM_ERROR_NONE;
7416         gint timeout = 0;
7417
7418         MMPLAYER_FENTER();
7419
7420         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7421                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7422
7423         LOGD("current state before doing transition");
7424         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7425         MMPLAYER_PRINT_STATE(player);
7426
7427         /* generate dot file before returning error */
7428         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7429
7430         if (async)
7431                 LOGD("do async state transition to PLAYING.\n");
7432
7433         /* set pipeline state to PLAYING */
7434         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7435
7436         ret = __mmplayer_gst_set_state(player,
7437                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7438         if (ret != MM_ERROR_NONE) {
7439                 LOGE("failed to set state to PLAYING\n");
7440                 return ret;
7441         } else {
7442                 if (async == FALSE) {
7443                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7444                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7445                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7446                 }
7447         }
7448
7449         /* generate dot file before returning error */
7450         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7451
7452         MMPLAYER_FLEAVE();
7453
7454         return ret;
7455 }
7456
7457 static int
7458 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7459 {
7460         unsigned long dur_msec = 0;
7461         gint64 dur_nsec = 0;
7462         gint64 pos_nsec = 0;
7463         gboolean ret = TRUE;
7464         gboolean accurated = FALSE;
7465         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7466
7467         MMPLAYER_FENTER();
7468         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7469         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7470
7471         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7472                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7473                 goto PENDING;
7474
7475         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7476                 /* check duration */
7477                 /* NOTE : duration cannot be zero except live streaming.
7478                  *              Since some element could have some timing problemn with quering duration, try again.
7479                  */
7480                 if (!player->duration) {
7481                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7482                         {
7483                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7484                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7485                                 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7486                                         player->pending_seek.is_pending = TRUE;
7487                                         player->pending_seek.format = format;
7488                                         player->pending_seek.pos = position;
7489                                         player->doing_seek = FALSE;
7490                                         MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7491                                         return MM_ERROR_NONE;
7492                                 } else {
7493                                         goto SEEK_ERROR;
7494                                 }
7495                         }
7496                         player->duration = dur_nsec;
7497                 }
7498
7499                 if (player->duration) {
7500                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7501                 } else {
7502                         LOGE("could not get the duration. fail to seek.\n");
7503                         goto SEEK_ERROR;
7504                 }
7505         }
7506         LOGD("playback rate: %f\n", player->playback_rate);
7507
7508         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7509         if (accurated)
7510                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7511         else
7512                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7513
7514         /* do seek */
7515         switch (format) {
7516         case MM_PLAYER_POS_FORMAT_TIME:
7517         {
7518                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7519                         GstQuery *query = NULL;
7520                         gboolean seekable = FALSE;
7521
7522                         /* check position is valid or not */
7523                         if (position > dur_msec)
7524                                 goto INVALID_ARGS;
7525
7526                         query = gst_query_new_seeking (GST_FORMAT_TIME);
7527                         if (gst_element_query (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7528                                 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
7529                                 gst_query_unref (query);
7530
7531                                 if (!seekable) {
7532                                         LOGW("non-seekable content");
7533                                         player->doing_seek = FALSE;
7534                                         return MM_ERROR_PLAYER_NO_OP;
7535                                 }
7536                         } else {
7537                                 LOGW("failed to get seeking query");
7538                                 gst_query_unref (query); /* keep seeking operation */
7539                         }
7540
7541                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7542
7543                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7544                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7545                            This causes problem is position calculation during normal pause resume scenarios also.
7546                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7547                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7548                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7549                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7550                                         LOGW("getting current position failed in seek\n");
7551
7552                                 player->last_position = pos_nsec;
7553                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7554                         }
7555
7556                         if (player->doing_seek) {
7557                                 LOGD("not completed seek");
7558                                 return MM_ERROR_PLAYER_DOING_SEEK;
7559                         }
7560                 }
7561
7562                 if (!internal_called)
7563                         player->doing_seek = TRUE;
7564
7565                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7566
7567                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7568                         gint64 cur_time = 0;
7569
7570                         /* get current position */
7571                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7572
7573                         /* flush */
7574                         GstEvent *event = gst_event_new_seek(1.0,
7575                                                         GST_FORMAT_TIME,
7576                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7577                                                         GST_SEEK_TYPE_SET, cur_time,
7578                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7579                         if (event)
7580                                 __gst_send_event_to_sink(player, event);
7581
7582                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7583                                 __gst_pause(player, FALSE);
7584                 }
7585
7586                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7587                         that's why set position through property. */
7588                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7589                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7590                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7591                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7592
7593                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7594                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7595                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7596                         player->doing_seek = FALSE;
7597                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7598                 } else {
7599                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7600                                                         GST_FORMAT_TIME, seek_flags,
7601                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7602                 }
7603
7604                 if (!ret) {
7605                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7606                         goto SEEK_ERROR;
7607                 }
7608         }
7609         break;
7610
7611         case MM_PLAYER_POS_FORMAT_PERCENT:
7612         {
7613                 LOGD("seeking to(%lu)%% \n", position);
7614
7615                 if (player->doing_seek) {
7616                         LOGD("not completed seek");
7617                         return MM_ERROR_PLAYER_DOING_SEEK;
7618                 }
7619
7620                 if (!internal_called)
7621                         player->doing_seek = TRUE;
7622
7623                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7624                 pos_nsec = (gint64)((position * player->duration) / 100);
7625                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7626                                                 GST_FORMAT_TIME, seek_flags,
7627                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7628                 if (!ret) {
7629                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7630                         goto SEEK_ERROR;
7631                 }
7632         }
7633         break;
7634
7635         default:
7636                 goto INVALID_ARGS;
7637         }
7638
7639         /* NOTE : store last seeking point to overcome some bad operation
7640           *     (returning zero when getting current position) of some elements
7641           */
7642         player->last_position = pos_nsec;
7643
7644         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7645         if (player->playback_rate > 1.0)
7646                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7647
7648         MMPLAYER_FLEAVE();
7649         return MM_ERROR_NONE;
7650
7651 PENDING:
7652         player->pending_seek.is_pending = TRUE;
7653         player->pending_seek.format = format;
7654         player->pending_seek.pos = position;
7655
7656         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7657                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7658
7659         return MM_ERROR_NONE;
7660
7661 INVALID_ARGS:
7662         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7663         return MM_ERROR_INVALID_ARGUMENT;
7664
7665 SEEK_ERROR:
7666         player->doing_seek = FALSE;
7667         return MM_ERROR_PLAYER_SEEK;
7668 }
7669
7670 #define TRICKPLAY_OFFSET GST_MSECOND
7671
7672 static int
7673 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7674 {
7675         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7676         gint64 pos_msec = 0;
7677         gboolean ret = TRUE;
7678
7679         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7680                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7681
7682         current_state = MMPLAYER_CURRENT_STATE(player);
7683
7684         /* NOTE : query position except paused state to overcome some bad operation
7685          * please refer to below comments in details
7686          */
7687         if (current_state != MM_PLAYER_STATE_PAUSED)
7688                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7689
7690         /* NOTE : get last point to overcome some bad operation of some elements
7691          *(returning zero when getting current position in paused state
7692          * and when failed to get postion during seeking
7693          */
7694         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7695                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7696
7697                 if (player->playback_rate < 0.0)
7698                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7699                 else
7700                         pos_msec = player->last_position;
7701
7702                 if (!ret)
7703                         pos_msec = player->last_position;
7704                 else
7705                         player->last_position = pos_msec;
7706
7707                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7708
7709         } else {
7710                 if (player->duration > 0 && pos_msec > player->duration)
7711                         pos_msec = player->duration;
7712
7713                 if (player->sound_focus.keep_last_pos) {
7714                         LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7715                         pos_msec = player->last_position;
7716                 } else {
7717                         player->last_position = pos_msec;
7718                 }
7719         }
7720
7721         switch (format) {
7722         case MM_PLAYER_POS_FORMAT_TIME:
7723                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7724                 break;
7725
7726         case MM_PLAYER_POS_FORMAT_PERCENT:
7727         {
7728                 if (player->duration <= 0) {
7729                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7730                         *position = 0;
7731                 } else {
7732                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7733                         *position = pos_msec * 100 / player->duration;
7734                 }
7735                 break;
7736         }
7737         default:
7738                 return MM_ERROR_PLAYER_INTERNAL;
7739         }
7740
7741         return MM_ERROR_NONE;
7742 }
7743
7744
7745 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7746 {
7747 #define STREAMING_IS_FINISHED   0
7748 #define BUFFERING_MAX_PER       100
7749 #define DEFAULT_PER_VALUE       -1
7750 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7751
7752         MMPlayerGstElement *mainbin = NULL;
7753         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7754         gint64 buffered_total = 0;
7755         unsigned long position = 0;
7756         gint buffered_sec = -1;
7757         GstBufferingMode mode = GST_BUFFERING_STREAM;
7758         gint64 content_size_time = player->duration;
7759         guint64 content_size_bytes = player->http_content_size;
7760
7761         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7762                                                 player->pipeline &&
7763                                                 player->pipeline->mainbin,
7764                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7765
7766         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7767
7768         *start_pos = 0;
7769         *stop_pos = 0;
7770
7771         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7772                 /* and rtsp is not ready yet. */
7773                 LOGW("it's only used for http streaming case.\n");
7774                 return MM_ERROR_PLAYER_NO_OP;
7775         }
7776
7777         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7778                 LOGW("Time format is not supported yet.\n");
7779                 return MM_ERROR_INVALID_ARGUMENT;
7780         }
7781
7782         if (content_size_time <= 0 || content_size_bytes <= 0) {
7783                 LOGW("there is no content size.");
7784                 return MM_ERROR_NONE;
7785         }
7786
7787         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7788                 LOGW("fail to get current position.");
7789                 return MM_ERROR_NONE;
7790         }
7791
7792         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7793                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7794
7795         mainbin = player->pipeline->mainbin;
7796         start_per = (gint)(ceil(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7797
7798         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7799                 GstQuery *query = NULL;
7800                 gint byte_in_rate = 0, byte_out_rate = 0;
7801                 gint64 estimated_total = 0;
7802
7803                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7804                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7805                         LOGW("fail to get buffering query from queue2");
7806                         if (query)
7807                                 gst_query_unref(query);
7808                         return MM_ERROR_NONE;
7809                 }
7810
7811                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7812                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7813
7814                 if (mode == GST_BUFFERING_STREAM) {
7815                         /* using only queue in case of push mode(ts / mp3) */
7816                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7817                                 GST_FORMAT_BYTES, &buffered_total)) {
7818                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7819                                 stop_per = 100 * buffered_total / content_size_bytes;
7820                         }
7821                 } else {
7822                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7823                         guint idx = 0;
7824                         guint num_of_ranges = 0;
7825                         gint64 start_byte = 0, stop_byte = 0;
7826
7827                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7828                         if (estimated_total != STREAMING_IS_FINISHED) {
7829                                 /* buffered size info from queue2 */
7830                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7831                                 for (idx = 0; idx < num_of_ranges; idx++) {
7832                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7833                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7834
7835                                         buffered_total += (stop_byte - start_byte);
7836                                 }
7837                         } else
7838                                 stop_per = BUFFERING_MAX_PER;
7839                 }
7840                 gst_query_unref(query);
7841         }
7842
7843         if (stop_per == DEFAULT_PER_VALUE) {
7844                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7845                 if (dur_sec > 0) {
7846                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7847
7848                         /* buffered size info from multiqueue */
7849                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7850                                 guint curr_size_bytes = 0;
7851                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7852                                         "curr-size-bytes", &curr_size_bytes, NULL);
7853                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7854                                 buffered_total += curr_size_bytes;
7855                         }
7856
7857                         if (avg_byterate > 0)
7858                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7859                         else if (player->total_maximum_bitrate > 0)
7860                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7861                         else if (player->total_bitrate > 0)
7862                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7863
7864                         if (buffered_sec >= 0)
7865                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7866                 }
7867         }
7868
7869         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7870         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7871
7872         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7873                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7874
7875         return MM_ERROR_NONE;
7876 }
7877
7878 static int
7879 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7880 {
7881         MMPLAYER_FENTER();
7882
7883         if (!player) {
7884                 LOGW("set_message_callback is called with invalid player handle\n");
7885                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7886         }
7887
7888         player->msg_cb = callback;
7889         player->msg_cb_param = user_param;
7890
7891         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7892
7893         MMPLAYER_FLEAVE();
7894
7895         return MM_ERROR_NONE;
7896 }
7897
7898 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7899 {
7900         int ret = MM_ERROR_PLAYER_INVALID_URI;
7901         char *path = NULL;
7902
7903         MMPLAYER_FENTER();
7904
7905         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7906         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7907         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7908
7909         memset(data, 0, sizeof(MMPlayerParseProfile));
7910
7911         if ((path = strstr(uri, "es_buff://"))) {
7912                 if (strlen(path)) {
7913                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7914                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7915                         ret = MM_ERROR_NONE;
7916                 }
7917         } else if ((path = strstr(uri, "rtsp://"))) {
7918                 if (strlen(path)) {
7919                         if ((path = strstr(uri, "/wfd1.0/"))) {
7920                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7921                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7922                                 ret = MM_ERROR_NONE;
7923                                 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7924                         } else {
7925                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7926                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7927                                 ret = MM_ERROR_NONE;
7928                         }
7929                 }
7930         } else if ((path = strstr(uri, "http://"))) {
7931                 if (strlen(path)) {
7932                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7933
7934                         if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7935                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7936                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7937                         else
7938                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7939
7940                         ret = MM_ERROR_NONE;
7941                 }
7942         } else if ((path = strstr(uri, "https://"))) {
7943                 if (strlen(path)) {
7944                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7945
7946                 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7947                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7948                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7949
7950                         data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7951
7952                         ret = MM_ERROR_NONE;
7953                 }
7954         } else if ((path = strstr(uri, "rtspu://"))) {
7955                 if (strlen(path)) {
7956                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7957                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958                         ret = MM_ERROR_NONE;
7959                 }
7960         } else if ((path = strstr(uri, "rtspr://"))) {
7961                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7962                 char *separater = strstr(path, "*");
7963
7964                 if (separater) {
7965                         int urgent_len = 0;
7966                         char *urgent = separater + strlen("*");
7967
7968                         if ((urgent_len = strlen(urgent))) {
7969                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7970                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7971                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7972                                 ret = MM_ERROR_NONE;
7973                         }
7974                 }
7975         } else if ((path = strstr(uri, "mms://"))) {
7976                 if (strlen(path)) {
7977                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7978                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7979                         ret = MM_ERROR_NONE;
7980                 }
7981         } else if ((path = strstr(uri, "mem://"))) {
7982                 if (strlen(path)) {
7983                         int mem_size = 0;
7984                         char *buffer = NULL;
7985                         char *seperator = strchr(path, ',');
7986                         char ext[100] = {0,}, size[100] = {0,};
7987
7988                         if (seperator) {
7989                                 if ((buffer = strstr(path, "ext="))) {
7990                                         buffer += strlen("ext=");
7991
7992                                         if (strlen(buffer)) {
7993                                                 strncpy(ext, buffer, 99);
7994
7995                                                 if ((seperator = strchr(ext, ','))
7996                                                         || (seperator = strchr(ext, ' '))
7997                                                         || (seperator = strchr(ext, '\0'))) {
7998                                                         seperator[0] = '\0';
7999                                                 }
8000                                         }
8001                                 }
8002
8003                                 if ((buffer = strstr(path, "size="))) {
8004                                         buffer += strlen("size=");
8005
8006                                         if (strlen(buffer) > 0) {
8007                                                 strncpy(size, buffer, 99);
8008
8009                                                 if ((seperator = strchr(size, ','))
8010                                                         || (seperator = strchr(size, ' '))
8011                                                         || (seperator = strchr(size, '\0'))) {
8012                                                         seperator[0] = '\0';
8013                                                 }
8014
8015                                                 mem_size = atoi(size);
8016                                         }
8017                                 }
8018                         }
8019
8020                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8021                         if (mem_size && param) {
8022                                 if (data->mem)
8023                                         free(data->mem);
8024
8025                                 data->mem = malloc(mem_size);
8026
8027                                 if (data->mem) {
8028                                         memcpy(data->mem, param, mem_size);
8029                                         data->mem_size = mem_size;
8030                                 } else {
8031                                         LOGE("failed to alloc mem %d", mem_size);
8032                                 }
8033
8034                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8035                                 ret = MM_ERROR_NONE;
8036                         }
8037                 }
8038         } else {
8039                 gchar *location = NULL;
8040                 GError *err = NULL;
8041
8042                 if ((path = strstr(uri, "file://"))) {
8043
8044                         location = g_filename_from_uri(uri, NULL, &err);
8045
8046                         if (!location || (err != NULL)) {
8047                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8048                                  (err != NULL) ? err->message : "unknown error");
8049
8050                           if (err) g_error_free(err);
8051                           if (location) g_free(location);
8052
8053                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8054                           goto exit;
8055                         }
8056
8057                         LOGD("path from uri: %s", location);
8058                 }
8059
8060                 path = (location != NULL) ? (location) : ((char*)uri);
8061                 int file_stat = MM_ERROR_NONE;
8062
8063                 file_stat = util_exist_file_path(path);
8064
8065                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8066                 if (file_stat == MM_ERROR_NONE) {
8067                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8068
8069                         if (util_is_sdp_file(path)) {
8070                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8071                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8072                         } else {
8073                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8074                         }
8075                         ret = MM_ERROR_NONE;
8076                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8077                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8078                 } else {
8079                         LOGE("invalid uri, could not play..\n");
8080                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8081                 }
8082
8083                 if (location) g_free(location);
8084         }
8085
8086 exit:
8087         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8088                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8089         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8090                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8091
8092         /* dump parse result */
8093         SECURE_LOGW("incomming uri : %s\n", uri);
8094         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8095                 data->uri_type, data->mem, data->mem_size, data->urgent);
8096
8097         MMPLAYER_FLEAVE();
8098
8099         return ret;
8100 }
8101
8102 gboolean _asm_postmsg(gpointer *data)
8103 {
8104         mm_player_t* player = (mm_player_t*)data;
8105         MMMessageParamType msg = {0, };
8106
8107         MMPLAYER_FENTER();
8108         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8109         LOGW("get notified");
8110
8111         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8112                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8113                 LOGW("dispatched");
8114                 return FALSE;
8115         }
8116
8117
8118         msg.union_type = MM_MSG_UNION_CODE;
8119         msg.code = player->sound_focus.focus_changed_msg;
8120
8121         MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8122         player->resume_event_id = 0;
8123
8124         LOGW("dispatched");
8125         return FALSE;
8126 }
8127
8128 gboolean _asm_lazy_pause(gpointer *data)
8129 {
8130         mm_player_t* player = (mm_player_t*)data;
8131         int ret = MM_ERROR_NONE;
8132
8133         MMPLAYER_FENTER();
8134
8135         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8136
8137         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8138                 LOGD("Ready to proceed lazy pause\n");
8139                 ret = _mmplayer_pause((MMHandleType)player);
8140                 if (MM_ERROR_NONE != ret)
8141                         LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8142         } else
8143                 LOGD("Invalid state to proceed lazy pause\n");
8144
8145         /* unset mute */
8146         if (player->pipeline && player->pipeline->audiobin)
8147                 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8148
8149         player->sound_focus.by_asm_cb = FALSE; //should be reset here
8150
8151         MMPLAYER_FLEAVE();
8152
8153         return FALSE;
8154 }
8155
8156 gboolean
8157 __mmplayer_can_do_interrupt(mm_player_t *player)
8158 {
8159         if (!player || !player->pipeline || !player->attrs) {
8160                 LOGW("not initialized");
8161                 goto FAILED;
8162         }
8163
8164         if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8165                 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8166                 goto FAILED;
8167         }
8168
8169         /* check if seeking */
8170         if (player->doing_seek) {
8171                 MMMessageParamType msg_param;
8172                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8173                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8174                 player->doing_seek = FALSE;
8175                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8176                 goto FAILED;
8177         }
8178
8179         /* check other thread */
8180         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8181                 LOGW("locked already, cmd state : %d", player->cmd);
8182
8183                 /* check application command */
8184                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8185                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8186
8187                         /* lock will be released at mrp_resource_release_cb() */
8188                         MMPLAYER_CMD_LOCK(player);
8189                         goto INTERRUPT;
8190                 }
8191                 LOGW("nothing to do");
8192                 goto FAILED;
8193         } else {
8194                 LOGW("can interrupt immediately");
8195                 goto INTERRUPT;
8196         }
8197
8198 FAILED:    /* with CMD UNLOCKED */
8199         return FALSE;
8200
8201 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8202         return TRUE;
8203 }
8204
8205 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8206 static int
8207 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8208 {
8209         int ret = MM_ERROR_NONE;
8210         MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8211
8212         if (strstr(reason_for_change, "alarm")) {
8213                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8214
8215         } else if (strstr(reason_for_change, "notification")) {
8216                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8217
8218         } else if (strstr(reason_for_change, "emergency")) {
8219                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8220
8221         } else if (strstr(reason_for_change, "call-voice") ||
8222                                 strstr(reason_for_change, "call-video") ||
8223                                 strstr(reason_for_change, "voip") ||
8224                                 strstr(reason_for_change, "ringtone-voip") ||
8225                                 strstr(reason_for_change, "ringtone-call")) {
8226                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8227
8228         } else if (strstr(reason_for_change, "media") ||
8229                                 strstr(reason_for_change, "radio") ||
8230                                 strstr(reason_for_change, "loopback") ||
8231                                 strstr(reason_for_change, "system") ||
8232                                 strstr(reason_for_change, "voice-information") ||
8233                                 strstr(reason_for_change, "voice-recognition")) {
8234                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8235
8236         } else {
8237                 ret = MM_ERROR_INVALID_ARGUMENT;
8238                 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8239                 goto DONE;
8240         }
8241
8242         if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8243                 /* can acqurie */
8244                 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8245
8246         LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8247         *msg = focus_msg;
8248
8249 DONE:
8250         return ret;
8251 }
8252
8253 /* FIXME: will be updated with new funct */
8254 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8255                                        const char *reason_for_change, const char *additional_info, void *user_data)
8256 {
8257         mm_player_t* player = (mm_player_t*) user_data;
8258         int result = MM_ERROR_NONE;
8259         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8260
8261         LOGW("focus watch notified");
8262
8263         if (!__mmplayer_can_do_interrupt(player)) {
8264                 LOGW("no need to interrupt, so leave");
8265                 goto EXIT_WITHOUT_UNLOCK;
8266         }
8267
8268         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8269                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8270                 goto EXIT;
8271         }
8272
8273         LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8274                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8275
8276         player->sound_focus.cb_pending = TRUE;
8277         player->sound_focus.by_asm_cb = TRUE;
8278
8279         if (focus_state == FOCUS_IS_ACQUIRED) {
8280                 LOGW("watch: FOCUS_IS_ACQUIRED");
8281                 player->sound_focus.acquired = TRUE;
8282
8283                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8284                         player->sound_focus.focus_changed_msg = (int)msg;
8285
8286                 if (strstr(reason_for_change, "call") ||
8287                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8288                         strstr(reason_for_change, "alarm") ||
8289                         strstr(reason_for_change, "media")) {
8290                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8291                                 // hold 0.7 second to excute "fadedown mute" effect
8292                                 LOGW("do fade down->pause->undo fade down");
8293
8294                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8295
8296                                 result = _mmplayer_pause((MMHandleType)player);
8297                                 if (result != MM_ERROR_NONE) {
8298                                         LOGW("fail to set Pause state by asm");
8299                                         goto EXIT;
8300                                 }
8301                                 __mmplayer_undo_sound_fadedown(player);
8302                         } else
8303                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8304                                 _mmplayer_unrealize((MMHandleType)player);
8305                 } else {
8306                         LOGW("pause immediately");
8307                         result = _mmplayer_pause((MMHandleType)player);
8308                         if (result != MM_ERROR_NONE) {
8309                                 LOGW("fail to set Pause state by asm");
8310                                 goto EXIT;
8311                         }
8312                 }
8313         } else if (focus_state == FOCUS_IS_RELEASED) {
8314                 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8315                 player->sound_focus.acquired = FALSE;
8316                 player->sound_focus.antishock = TRUE;
8317                 player->sound_focus.by_asm_cb = FALSE;
8318
8319                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8320                         player->sound_focus.focus_changed_msg = (int)msg;
8321
8322                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8323                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8324                 goto DONE;
8325         } else
8326                 LOGW("unknown focus state %d", focus_state);
8327
8328 DONE:
8329         player->sound_focus.by_asm_cb = FALSE;
8330         player->sound_focus.cb_pending = FALSE;
8331
8332 EXIT:
8333         MMPLAYER_CMD_UNLOCK(player);
8334         LOGW("dispatched");
8335         return;
8336
8337 EXIT_WITHOUT_UNLOCK:
8338         LOGW("dispatched");
8339         return;
8340 }
8341
8342 void
8343 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8344         const char *reason_for_change, int option, const char *additional_info, void *user_data)
8345 {
8346         mm_player_t* player = (mm_player_t*) user_data;
8347         int result = MM_ERROR_NONE;
8348         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8349
8350         LOGW("get focus notified");
8351
8352         if (!__mmplayer_can_do_interrupt(player)) {
8353                 LOGW("no need to interrupt, so leave");
8354                 goto EXIT_WITHOUT_UNLOCK;
8355         }
8356
8357         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8358                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8359                 goto EXIT;
8360         }
8361
8362         LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8363                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8364
8365         player->sound_focus.cb_pending = TRUE;
8366         player->sound_focus.by_asm_cb = TRUE;
8367 //      player->sound_focus.event_src = event_src;
8368
8369         if (focus_state == FOCUS_IS_RELEASED) {
8370                 LOGW("FOCUS_IS_RELEASED");
8371                 player->sound_focus.acquired = FALSE;
8372
8373                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8374                         player->sound_focus.focus_changed_msg = (int)msg;
8375
8376                 if (strstr(reason_for_change, "call") ||
8377                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8378                         strstr(reason_for_change, "alarm") ||
8379                         strstr(reason_for_change, "media")) {
8380                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8381                                 //hold 0.7 second to excute "fadedown mute" effect
8382                                 LOGW("do fade down->pause->undo fade down");
8383
8384                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8385
8386                                 result = _mmplayer_pause((MMHandleType)player);
8387                                 if (result != MM_ERROR_NONE) {
8388                                         LOGW("fail to set Pause state by asm");
8389                                         goto EXIT;
8390                                 }
8391                                 __mmplayer_undo_sound_fadedown(player);
8392                         } else
8393                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8394                                 _mmplayer_unrealize((MMHandleType)player);
8395                 } else {
8396                         LOGW("pause immediately");
8397                         result = _mmplayer_pause((MMHandleType)player);
8398                         if (result != MM_ERROR_NONE) {
8399                                 LOGW("fail to set Pause state by asm");
8400                                 goto EXIT;
8401                         }
8402                 }
8403         } else if (focus_state == FOCUS_IS_ACQUIRED) {
8404                 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8405                 player->sound_focus.antishock = TRUE;
8406                 player->sound_focus.by_asm_cb = FALSE;
8407
8408                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8409                         player->sound_focus.focus_changed_msg = (int)msg;
8410
8411                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8412                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8413                 goto DONE;
8414         } else
8415                 LOGW("unknown focus state %d", focus_state);
8416
8417 DONE:
8418         player->sound_focus.by_asm_cb = FALSE;
8419         player->sound_focus.cb_pending = FALSE;
8420
8421 EXIT:
8422         if (mm_sound_update_focus_status(id, 0))
8423                 LOGE("failed to update focus status\n");
8424         MMPLAYER_CMD_UNLOCK(player);
8425         LOGW("dispatched");
8426         return;
8427
8428 EXIT_WITHOUT_UNLOCK:
8429         LOGW("dispatched");
8430         return;
8431 }
8432
8433
8434 int
8435 _mmplayer_create_player(MMHandleType handle)
8436 {
8437         int ret = MM_ERROR_PLAYER_INTERNAL;
8438         mm_player_t* player = MM_PLAYER_CAST(handle);
8439
8440         MMPLAYER_FENTER();
8441
8442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8443
8444         /* initialize player state */
8445         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8446         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8447         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8448         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8449
8450         /* check current state */
8451         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8452
8453         /* construct attributes */
8454         player->attrs = _mmplayer_construct_attribute(handle);
8455
8456         if (!player->attrs) {
8457                 LOGE("Failed to construct attributes\n");
8458                 return ret;
8459         }
8460
8461         /* initialize gstreamer with configured parameter */
8462         if (!__mmplayer_init_gstreamer(player)) {
8463                 LOGE("Initializing gstreamer failed\n");
8464                 _mmplayer_deconstruct_attribute(handle);
8465                 return ret;
8466         }
8467
8468         /* initialize factories if not using decodebin */
8469         if (player->factories == NULL)
8470                 __mmplayer_init_factories(player);
8471
8472         /* create lock. note that g_tread_init() has already called in gst_init() */
8473         g_mutex_init(&player->fsink_lock);
8474
8475         /* create update tag lock */
8476         g_mutex_init(&player->update_tag_lock);
8477
8478         /* create repeat mutex */
8479         g_mutex_init(&player->repeat_thread_mutex);
8480
8481         /* create repeat cond */
8482         g_cond_init(&player->repeat_thread_cond);
8483
8484         /* create repeat thread */
8485         player->repeat_thread =
8486                 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8487         if (!player->repeat_thread) {
8488                 LOGE("failed to create repeat_thread(%s)");
8489                 g_mutex_clear(&player->repeat_thread_mutex);
8490                 g_cond_clear(&player->repeat_thread_cond);
8491                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8492                 goto ERROR;
8493         }
8494
8495         /* create next play mutex */
8496         g_mutex_init(&player->next_play_thread_mutex);
8497
8498         /* create next play cond */
8499         g_cond_init(&player->next_play_thread_cond);
8500
8501         /* create next play thread */
8502         player->next_play_thread =
8503                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8504         if (!player->next_play_thread) {
8505                 LOGE("failed to create next play thread");
8506                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8507                 g_mutex_clear(&player->next_play_thread_mutex);
8508                 g_cond_clear(&player->next_play_thread_cond);
8509                 goto ERROR;
8510         }
8511
8512         ret = _mmplayer_initialize_video_capture(player);
8513         if (ret != MM_ERROR_NONE) {
8514                 LOGE("failed to initialize video capture\n");
8515                 goto ERROR;
8516         }
8517
8518         /* initialize resource manager */
8519         if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], player)) {
8520                 LOGE("failed to initialize resource manager\n");
8521                 goto ERROR;
8522         }
8523
8524         if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], player)) {
8525                 LOGE("failed to initialize resource manager\n");
8526                 goto ERROR;
8527         }
8528
8529         if (MMPLAYER_IS_HTTP_PD(player)) {
8530                 player->pd_downloader = NULL;
8531                 player->pd_file_save_path = NULL;
8532         }
8533
8534         /* create video bo lock and cond */
8535         g_mutex_init(&player->video_bo_mutex);
8536         g_cond_init(&player->video_bo_cond);
8537
8538         /* create media stream callback mutex */
8539         g_mutex_init(&player->media_stream_cb_lock);
8540
8541         player->streaming_type = STREAMING_SERVICE_NONE;
8542
8543         /* give default value of audio effect setting */
8544         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8545         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8546
8547         player->play_subtitle = FALSE;
8548         player->play_count = 0;
8549         player->use_decodebin = TRUE;
8550         player->ignore_asyncdone = FALSE;
8551         player->use_deinterleave = FALSE;
8552         player->max_audio_channels = 0;
8553         player->video_share_api_delta = 0;
8554         player->video_share_clock_delta = 0;
8555         player->has_closed_caption = FALSE;
8556         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8557         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8558         player->pending_resume = FALSE;
8559         if (player->ini.dump_element_keyword[0][0] == '\0')
8560                 player->ini.set_dump_element_flag = FALSE;
8561         else
8562                 player->ini.set_dump_element_flag = TRUE;
8563
8564         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8565         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8566         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8567
8568         /* set player state to null */
8569         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8570         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8571
8572         return MM_ERROR_NONE;
8573
8574 ERROR:
8575         /* free lock */
8576         g_mutex_clear(&player->fsink_lock);
8577
8578         /* free update tag lock */
8579         g_mutex_clear(&player->update_tag_lock);
8580
8581         /* free thread */
8582         if (player->repeat_thread) {
8583                 MMPLAYER_REPEAT_THREAD_LOCK(player);
8584                 player->repeat_thread_exit = TRUE;
8585                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8586                 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8587
8588                 g_thread_join(player->repeat_thread);
8589                 player->repeat_thread = NULL;
8590
8591                 g_mutex_clear(&player->repeat_thread_mutex);
8592                 g_cond_clear(&player->repeat_thread_cond);
8593         }
8594
8595         /* free next play thread */
8596         if (player->next_play_thread) {
8597                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8598                 player->next_play_thread_exit = TRUE;
8599                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8600                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8601
8602                 g_thread_join(player->next_play_thread);
8603                 player->next_play_thread = NULL;
8604
8605                 g_mutex_clear(&player->next_play_thread_mutex);
8606                 g_cond_clear(&player->next_play_thread_cond);
8607         }
8608
8609         /* release attributes */
8610         _mmplayer_deconstruct_attribute(handle);
8611
8612         MMPLAYER_FLEAVE();
8613
8614         return ret;
8615 }
8616
8617 static gboolean
8618 __mmplayer_init_gstreamer(mm_player_t* player)
8619 {
8620         static gboolean initialized = FALSE;
8621         static const int max_argc = 50;
8622         gint* argc = NULL;
8623         gchar** argv = NULL;
8624         gchar** argv2 = NULL;
8625         GError *err = NULL;
8626         int i = 0;
8627         int arg_count = 0;
8628
8629         if (initialized) {
8630                 LOGD("gstreamer already initialized.\n");
8631                 return TRUE;
8632         }
8633
8634         /* alloc */
8635         argc = malloc(sizeof(int));
8636         argv = malloc(sizeof(gchar*) * max_argc);
8637         argv2 = malloc(sizeof(gchar*) * max_argc);
8638
8639         if (!argc || !argv || !argv2)
8640                 goto ERROR;
8641
8642         memset(argv, 0, sizeof(gchar*) * max_argc);
8643         memset(argv2, 0, sizeof(gchar*) * max_argc);
8644
8645         /* add initial */
8646         *argc = 1;
8647         argv[0] = g_strdup("mmplayer");
8648
8649         /* add gst_param */
8650         for (i = 0; i < 5; i++) {
8651                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8652                 if (strlen(player->ini.gst_param[i]) > 0) {
8653                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8654                         (*argc)++;
8655                 }
8656         }
8657
8658         /* we would not do fork for scanning plugins */
8659         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8660         (*argc)++;
8661
8662         /* check disable registry scan */
8663         if (player->ini.skip_rescan) {
8664                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8665                 (*argc)++;
8666         }
8667
8668         /* check disable segtrap */
8669         if (player->ini.disable_segtrap) {
8670                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8671                 (*argc)++;
8672         }
8673
8674         LOGD("initializing gstreamer with following parameter\n");
8675         LOGD("argc : %d\n", *argc);
8676         arg_count = *argc;
8677
8678         for (i = 0; i < arg_count; i++) {
8679                 argv2[i] = argv[i];
8680                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8681         }
8682
8683         /* initializing gstreamer */
8684         if (!gst_init_check(argc, &argv, &err)) {
8685                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8686                 if (err)
8687                         g_error_free(err);
8688
8689                 goto ERROR;
8690         }
8691         /* release */
8692         for (i = 0; i < arg_count; i++) {
8693                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8694                 MMPLAYER_FREEIF(argv2[i]);
8695         }
8696
8697         MMPLAYER_FREEIF(argv);
8698         MMPLAYER_FREEIF(argv2);
8699         MMPLAYER_FREEIF(argc);
8700
8701         /* done */
8702         initialized = TRUE;
8703
8704         return TRUE;
8705
8706 ERROR:
8707
8708         /* release */
8709         for (i = 0; i < arg_count; i++) {
8710                 LOGD("free[%d] : %s\n", i, argv2[i]);
8711                 MMPLAYER_FREEIF(argv2[i]);
8712         }
8713
8714         MMPLAYER_FREEIF(argv);
8715         MMPLAYER_FREEIF(argv2);
8716         MMPLAYER_FREEIF(argc);
8717
8718         return FALSE;
8719 }
8720
8721 int
8722 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8723 {
8724         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8725
8726         if (player->pd_downloader) {
8727                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8728                 MMPLAYER_FREEIF(player->pd_downloader);
8729         }
8730
8731         if (MMPLAYER_IS_HTTP_PD(player)) {
8732                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8733                 MMPLAYER_FREEIF(player->pd_file_save_path);
8734         }
8735
8736         return MM_ERROR_NONE;
8737 }
8738
8739 static void
8740 __mmplayer_check_async_state_transition(mm_player_t* player)
8741 {
8742         GstState element_state = GST_STATE_VOID_PENDING;
8743         GstState element_pending_state = GST_STATE_VOID_PENDING;
8744         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8745         GstElement * element = NULL;
8746         gboolean async = FALSE;
8747
8748         /* check player handle */
8749         MMPLAYER_RETURN_IF_FAIL(player &&
8750                                                 player->pipeline &&
8751                                                 player->pipeline->mainbin &&
8752                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8753
8754         if (player->attrs)
8755                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8756
8757         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8758                 LOGD("don't need to check the pipeline state");
8759                 return;
8760         }
8761
8762         MMPLAYER_PRINT_STATE(player);
8763
8764         /* wait for state transition */
8765         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8766         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8767
8768         if (ret == GST_STATE_CHANGE_FAILURE) {
8769                 LOGE(" [%s] state : %s   pending : %s \n",
8770                         GST_ELEMENT_NAME(element),
8771                         gst_element_state_get_name(element_state),
8772                         gst_element_state_get_name(element_pending_state));
8773
8774                 /* dump state of all element */
8775                 __mmplayer_dump_pipeline_state(player);
8776
8777                 return;
8778         }
8779
8780         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8781         return;
8782 }
8783
8784 int
8785 _mmplayer_destroy(MMHandleType handle)
8786 {
8787         mm_player_t* player = MM_PLAYER_CAST(handle);
8788
8789         MMPLAYER_FENTER();
8790
8791         /* check player handle */
8792         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8793
8794         /* destroy can called at anytime */
8795         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8796
8797         /* check async state transition */
8798         __mmplayer_check_async_state_transition(player);
8799
8800         __mmplayer_destroy_streaming_ext(player);
8801
8802         /* release repeat thread */
8803         if (player->repeat_thread) {
8804                 MMPLAYER_REPEAT_THREAD_LOCK(player);
8805                 player->repeat_thread_exit = TRUE;
8806                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8807                 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8808
8809                 LOGD("waitting for repeat thread exit\n");
8810                 g_thread_join(player->repeat_thread);
8811                 g_mutex_clear(&player->repeat_thread_mutex);
8812                 g_cond_clear(&player->repeat_thread_cond);
8813                 LOGD("repeat thread released\n");
8814         }
8815
8816         /* release next play thread */
8817         if (player->next_play_thread) {
8818                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8819                 player->next_play_thread_exit = TRUE;
8820                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8821                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8822
8823                 LOGD("waitting for next play thread exit\n");
8824                 g_thread_join(player->next_play_thread);
8825                 g_mutex_clear(&player->next_play_thread_mutex);
8826                 g_cond_clear(&player->next_play_thread_cond);
8827                 LOGD("next play thread released\n");
8828         }
8829
8830         _mmplayer_release_video_capture(player);
8831
8832         /* flush any pending asm_cb */
8833         if (player->sound_focus.cb_pending) {
8834                 /* set a flag for make sure asm_cb to be returned immediately */
8835                 LOGW("asm cb has pending state");
8836                 player->sound_focus.exit_cb = TRUE;
8837
8838                 /* make sure to release any pending asm_cb which locked by cmd_lock */
8839                 MMPLAYER_CMD_UNLOCK(player);
8840                 sched_yield();
8841                 MMPLAYER_CMD_LOCK(player);
8842         }
8843
8844         /* withdraw asm */
8845         if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8846                 LOGE("failed to deregister asm server\n");
8847
8848         /* de-initialize resource manager */
8849         if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]))
8850                 LOGE("failed to deinitialize resource manager\n");
8851
8852         if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]))
8853                 LOGE("failed to deinitialize resource manager\n");
8854
8855 #ifdef USE_LAZY_PAUSE
8856         if (player->lazy_pause_event_id) {
8857                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8858                 player->lazy_pause_event_id = 0;
8859         }
8860 #endif
8861
8862         if (player->resume_event_id) {
8863                 g_source_remove(player->resume_event_id);
8864                 player->resume_event_id = 0;
8865         }
8866
8867         if (player->resumable_cancel_id) {
8868                 g_source_remove(player->resumable_cancel_id);
8869                 player->resumable_cancel_id = 0;
8870         }
8871
8872         /* release pipeline */
8873         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8874                 LOGE("failed to destory pipeline\n");
8875                 return MM_ERROR_PLAYER_INTERNAL;
8876         }
8877
8878         if (player->is_external_subtitle_present && player->subtitle_language_list) {
8879           g_list_free(player->subtitle_language_list);
8880           player->subtitle_language_list = NULL;
8881         }
8882
8883         __mmplayer_release_dump_list(player->dump_list);
8884
8885         /* release miscellaneous information.
8886            these info needs to be released after pipeline is destroyed. */
8887         __mmplayer_release_misc_post(player);
8888
8889         /* release attributes */
8890         _mmplayer_deconstruct_attribute(handle);
8891
8892         /* release factories */
8893         __mmplayer_release_factories(player);
8894
8895         /* release lock */
8896         g_mutex_clear(&player->fsink_lock);
8897
8898         /* release lock */
8899         g_mutex_clear(&player->update_tag_lock);
8900
8901         /* release video bo lock and cond */
8902         g_mutex_clear(&player->video_bo_mutex);
8903         g_cond_clear(&player->video_bo_cond);
8904
8905         /* release media stream callback lock */
8906         g_mutex_clear(&player->media_stream_cb_lock);
8907
8908         MMPLAYER_FLEAVE();
8909
8910         return MM_ERROR_NONE;
8911 }
8912
8913 int
8914 __mmplayer_realize_streaming_ext(mm_player_t* player)
8915 {
8916         int ret = MM_ERROR_NONE;
8917
8918         MMPLAYER_FENTER();
8919         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8920
8921         if (MMPLAYER_IS_HTTP_PD(player)) {
8922                 gboolean bret = FALSE;
8923
8924                 player->pd_downloader = _mmplayer_create_pd_downloader();
8925                 if (!player->pd_downloader) {
8926                         LOGE("Unable to create PD Downloader...");
8927                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8928                 }
8929
8930                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8931
8932                 if (FALSE == bret) {
8933                         LOGE("Unable to create PD Downloader...");
8934                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8935                 }
8936         }
8937
8938         MMPLAYER_FLEAVE();
8939         return ret;
8940 }
8941
8942 int
8943 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid)
8944 {
8945         mm_player_t* player = (mm_player_t*)hplayer;
8946         MMHandleType attrs = 0;
8947         int ret = MM_ERROR_NONE;
8948
8949         attrs = MMPLAYER_GET_ATTRS(player);
8950         if (!attrs) {
8951                 LOGE("fail to get attributes.\n");
8952                 return MM_ERROR_PLAYER_INTERNAL;
8953         }
8954
8955         player->sound_focus.pid = pid;
8956
8957         /* register to asm */
8958         if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8959                                                 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8960                                                 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8961                                                 (void*)player)) {
8962                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8963                 LOGE("failed to register asm server\n");
8964                 return MM_ERROR_POLICY_INTERNAL;
8965         }
8966         return ret;
8967 }
8968
8969 int
8970 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8971 {
8972         mm_player_t* player = (mm_player_t*) hplayer;
8973
8974         MMPLAYER_FENTER();
8975
8976         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8977
8978         *pid = player->sound_focus.pid;
8979
8980         LOGD("registered pid[%d] %p", *pid, player);
8981
8982         MMPLAYER_FLEAVE();
8983
8984         return MM_ERROR_NONE;
8985 }
8986
8987 int
8988 _mmplayer_realize(MMHandleType hplayer)
8989 {
8990         mm_player_t* player = (mm_player_t*)hplayer;
8991         char *uri = NULL;
8992         void *param = NULL;
8993         gboolean update_registry = FALSE;
8994         MMHandleType attrs = 0;
8995         int ret = MM_ERROR_NONE;
8996
8997         MMPLAYER_FENTER();
8998
8999         /* check player handle */
9000         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9001
9002         /* check current state */
9003         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
9004
9005         attrs = MMPLAYER_GET_ATTRS(player);
9006         if (!attrs) {
9007                 LOGE("fail to get attributes.\n");
9008                 return MM_ERROR_PLAYER_INTERNAL;
9009         }
9010         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9011         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
9012
9013         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
9014                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9015
9016                 if (ret != MM_ERROR_NONE) {
9017                         LOGE("failed to parse profile\n");
9018                         return ret;
9019                 }
9020         }
9021
9022         /* profile.mem or mem_buf.buf have to be free when player is destroyed */
9023         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
9024                 player->mem_buf.buf = (char *)player->profile.mem;
9025                 player->mem_buf.len = player->profile.mem_size;
9026                 player->mem_buf.offset = 0;
9027         }
9028
9029         if (uri && (strstr(uri, "es_buff://"))) {
9030                 if (strstr(uri, "es_buff://push_mode"))
9031                         player->es_player_push_mode = TRUE;
9032                 else
9033                         player->es_player_push_mode = FALSE;
9034         }
9035
9036         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
9037                 LOGW("mms protocol is not supported format.\n");
9038                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9039         }
9040
9041         if (MMPLAYER_IS_STREAMING(player))
9042                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9043         else
9044                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9045
9046         player->smooth_streaming = FALSE;
9047         player->videodec_linked  = 0;
9048         player->videosink_linked = 0;
9049         player->audiodec_linked  = 0;
9050         player->audiosink_linked = 0;
9051         player->textsink_linked = 0;
9052         player->is_external_subtitle_present = FALSE;
9053         player->is_external_subtitle_added_now = FALSE;
9054         /* set the subtitle ON default */
9055         player->is_subtitle_off = FALSE;
9056
9057         /* registry should be updated for downloadable codec */
9058         mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9059
9060         if (update_registry) {
9061                 LOGD("updating registry...\n");
9062                 gst_update_registry();
9063
9064                 /* then we have to rebuild factories */
9065                 __mmplayer_release_factories(player);
9066                 __mmplayer_init_factories(player);
9067         }
9068
9069         /* realize pipeline */
9070         ret = __gst_realize(player);
9071         if (ret != MM_ERROR_NONE)
9072                 LOGE("fail to realize the player.\n");
9073         else
9074                 ret = __mmplayer_realize_streaming_ext(player);
9075
9076         MMPLAYER_FLEAVE();
9077
9078         return ret;
9079 }
9080
9081 int
9082 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9083 {
9084         MMPLAYER_FENTER();
9085         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9086
9087         /* destroy can called at anytime */
9088         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9089                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9090                 MMPLAYER_FREEIF(player->pd_downloader);
9091         }
9092
9093         MMPLAYER_FLEAVE();
9094         return MM_ERROR_NONE;
9095 }
9096
9097 int
9098 _mmplayer_unrealize(MMHandleType hplayer)
9099 {
9100         mm_player_t* player = (mm_player_t*)hplayer;
9101         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9102         int ret = MM_ERROR_NONE;
9103
9104         MMPLAYER_FENTER();
9105
9106         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9107
9108         /* check current state */
9109         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9110
9111         /* check async state transition */
9112         __mmplayer_check_async_state_transition(player);
9113
9114         __mmplayer_unrealize_streaming_ext(player);
9115
9116         /* unrealize pipeline */
9117         ret = __gst_unrealize(player);
9118
9119         /* set asm stop if success */
9120         if (MM_ERROR_NONE == ret) {
9121                 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9122                 if (ret != MM_ERROR_NONE)
9123                         LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9124
9125                 if (!player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb && /* is being released */
9126                         !player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb &&
9127                         _mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
9128                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9129                                 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
9130                                 if (ret != MM_ERROR_NONE)
9131                                         LOGE("failed to release decoder resource, ret(0x%x)\n", ret);
9132                         }
9133                 }
9134
9135                 if (!player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER].by_rm_cb && /* is being released */
9136                         !player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY].by_rm_cb &&
9137                         _mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
9138                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9139                                 ret = _mmplayer_resource_manager_release(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
9140                                 if (ret != MM_ERROR_NONE)
9141                                         LOGE("failed to release overlay resource, ret(0x%x)\n", ret);
9142                         }
9143                 }
9144
9145                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
9146                         if (resource_state == RESOURCE_STATE_PREPARED) {
9147                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
9148                                 if (ret != MM_ERROR_NONE)
9149                                         LOGE("failed to unprepare decoder resource, ret(0x%x)\n", ret);
9150                         }
9151                 }
9152
9153
9154                 if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY], &resource_state) == MM_ERROR_NONE) {
9155                         if (resource_state == RESOURCE_STATE_PREPARED) {
9156                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_OVERLAY]);
9157                                 if (ret != MM_ERROR_NONE)
9158                                         LOGE("failed to unprepare overlay resource, ret(0x%x)\n", ret);
9159                         }
9160                 }
9161         } else
9162                 LOGE("failed and don't change asm state to stop");
9163
9164         MMPLAYER_FLEAVE();
9165
9166         return ret;
9167 }
9168
9169 int
9170 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
9171 {
9172         mm_player_t* player = (mm_player_t*)hplayer;
9173
9174         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9175
9176         return __gst_set_message_callback(player, callback, user_param);
9177 }
9178
9179 int
9180 _mmplayer_get_state(MMHandleType hplayer, int* state)
9181 {
9182         mm_player_t *player = (mm_player_t*)hplayer;
9183
9184         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9185
9186         *state = MMPLAYER_CURRENT_STATE(player);
9187
9188         return MM_ERROR_NONE;
9189 }
9190
9191
9192 int
9193 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
9194 {
9195         mm_player_t* player = (mm_player_t*) hplayer;
9196         GstElement* vol_element = NULL;
9197         int i = 0;
9198
9199         MMPLAYER_FENTER();
9200
9201         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9202
9203         LOGD("volume [L]=%f:[R]=%f\n",
9204                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9205
9206         /* invalid factor range or not */
9207         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9208                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9209                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
9210                         return MM_ERROR_INVALID_ARGUMENT;
9211                 }
9212         }
9213
9214         /* not support to set other value into each channel */
9215         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9216                 return MM_ERROR_INVALID_ARGUMENT;
9217
9218         /* Save volume to handle. Currently the first array element will be saved. */
9219         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9220
9221         /* check pipeline handle */
9222         if (!player->pipeline || !player->pipeline->audiobin) {
9223                 LOGD("audiobin is not created yet\n");
9224                 LOGD("but, current stored volume will be set when it's created.\n");
9225
9226                 /* NOTE : stored volume will be used in create_audiobin
9227                  * returning MM_ERROR_NONE here makes application to able to
9228                  * set volume at anytime.
9229                  */
9230                 return MM_ERROR_NONE;
9231         }
9232
9233         /* setting volume to volume element */
9234         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9235
9236         if (vol_element) {
9237                 LOGD("volume is set [%f]\n", player->sound.volume);
9238                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9239         }
9240
9241         MMPLAYER_FLEAVE();
9242
9243         return MM_ERROR_NONE;
9244 }
9245
9246
9247 int
9248 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9249 {
9250         mm_player_t* player = (mm_player_t*) hplayer;
9251         int i = 0;
9252
9253         MMPLAYER_FENTER();
9254
9255         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9256         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9257
9258         /* returning stored volume */
9259         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9260                 volume->level[i] = player->sound.volume;
9261
9262         MMPLAYER_FLEAVE();
9263
9264         return MM_ERROR_NONE;
9265 }
9266
9267
9268
9269 int
9270 _mmplayer_set_mute(MMHandleType hplayer, int mute)
9271 {
9272         mm_player_t* player = (mm_player_t*) hplayer;
9273         GstElement* vol_element = NULL;
9274
9275         MMPLAYER_FENTER();
9276
9277         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9278
9279         /* mute value shoud 0 or 1 */
9280         if (mute != 0 && mute != 1) {
9281                 LOGE("bad mute value\n");
9282
9283                 /* FIXIT : definitly, we need _BAD_PARAM error code */
9284                 return MM_ERROR_INVALID_ARGUMENT;
9285         }
9286
9287         player->sound.mute = mute;
9288
9289         /* just hold mute value if pipeline is not ready */
9290         if (!player->pipeline || !player->pipeline->audiobin) {
9291                 LOGD("pipeline is not ready. holding mute value\n");
9292                 return MM_ERROR_NONE;
9293         }
9294
9295         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9296
9297         /* NOTE : volume will only created when the bt is enabled */
9298         if (vol_element) {
9299                 LOGD("mute : %d\n", mute);
9300                 g_object_set(vol_element, "mute", mute, NULL);
9301         } else
9302                 LOGD("volume elemnet is not created. using volume in audiosink\n");
9303
9304         MMPLAYER_FLEAVE();
9305
9306         return MM_ERROR_NONE;
9307 }
9308
9309 int
9310 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
9311 {
9312         mm_player_t* player = (mm_player_t*) hplayer;
9313
9314         MMPLAYER_FENTER();
9315
9316         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9317         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9318
9319         /* just hold mute value if pipeline is not ready */
9320         if (!player->pipeline || !player->pipeline->audiobin) {
9321                 LOGD("pipeline is not ready. returning stored value\n");
9322                 *pmute = player->sound.mute;
9323                 return MM_ERROR_NONE;
9324         }
9325
9326         *pmute = player->sound.mute;
9327
9328         MMPLAYER_FLEAVE();
9329
9330         return MM_ERROR_NONE;
9331 }
9332
9333 int
9334 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9335 {
9336         mm_player_t* player = (mm_player_t*) hplayer;
9337
9338         MMPLAYER_FENTER();
9339
9340         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9341
9342         player->video_stream_changed_cb = callback;
9343         player->video_stream_changed_cb_user_param = user_param;
9344         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9345
9346         MMPLAYER_FLEAVE();
9347
9348         return MM_ERROR_NONE;
9349 }
9350
9351 int
9352 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9353 {
9354         mm_player_t* player = (mm_player_t*) hplayer;
9355
9356         MMPLAYER_FENTER();
9357
9358         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9359
9360         player->audio_stream_changed_cb = callback;
9361         player->audio_stream_changed_cb_user_param = user_param;
9362         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9363
9364         MMPLAYER_FLEAVE();
9365
9366         return MM_ERROR_NONE;
9367 }
9368
9369 int
9370 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9371 {
9372         mm_player_t* player = (mm_player_t*) hplayer;
9373
9374         MMPLAYER_FENTER();
9375
9376         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9377
9378         player->audio_stream_render_cb_ex = callback;
9379         player->audio_stream_cb_user_param = user_param;
9380         player->audio_stream_sink_sync = sync;
9381         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);
9382
9383         MMPLAYER_FLEAVE();
9384
9385         return MM_ERROR_NONE;
9386 }
9387
9388 int
9389 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9390 {
9391         mm_player_t* player = (mm_player_t*) hplayer;
9392
9393         MMPLAYER_FENTER();
9394
9395         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9396
9397         if (callback && !player->bufmgr)
9398                 player->bufmgr = tbm_bufmgr_init(-1);
9399
9400         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9401         player->video_stream_cb = callback;
9402         player->video_stream_cb_user_param = user_param;
9403
9404         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9405
9406         MMPLAYER_FLEAVE();
9407
9408         return MM_ERROR_NONE;
9409 }
9410
9411 int
9412 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9413 {
9414         mm_player_t* player = (mm_player_t*) hplayer;
9415
9416         MMPLAYER_FENTER();
9417
9418         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9419
9420         player->audio_stream_cb = callback;
9421         player->audio_stream_cb_user_param = user_param;
9422         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9423
9424         MMPLAYER_FLEAVE();
9425
9426         return MM_ERROR_NONE;
9427 }
9428
9429 // set prepare size
9430 int
9431 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9432 {
9433         mm_player_t* player = (mm_player_t*) hplayer;
9434
9435         MMPLAYER_FENTER();
9436
9437         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9438
9439         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
9440                 return MM_ERROR_PLAYER_INVALID_STATE;
9441
9442         LOGD("pre buffer size : %d sec\n", second);
9443
9444         if (second <= 0) {
9445                 LOGE("bad size value\n");
9446                 return MM_ERROR_INVALID_ARGUMENT;
9447         }
9448
9449         if (player->streamer == NULL) {
9450                 player->streamer = __mm_player_streaming_create();
9451                 __mm_player_streaming_initialize(player->streamer);
9452         }
9453
9454         player->streamer->buffering_req.initial_second = second;
9455
9456         MMPLAYER_FLEAVE();
9457
9458         return MM_ERROR_NONE;
9459 }
9460
9461 // set runtime mode
9462 int
9463 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9464 {
9465         mm_player_t* player = (mm_player_t*) hplayer;
9466
9467         MMPLAYER_FENTER();
9468
9469         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9470
9471         LOGD("mode %d\n", mode);
9472
9473         if ((mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9474                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9475                 return MM_ERROR_INVALID_ARGUMENT;
9476
9477         if (player->streamer == NULL) {
9478                 player->streamer = __mm_player_streaming_create();
9479                 __mm_player_streaming_initialize(player->streamer);
9480         }
9481
9482         player->streamer->buffering_req.mode = mode;
9483
9484         if ((second > 0) &&
9485                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9486                 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9487                 player->streamer->buffering_req.runtime_second = second;
9488
9489         MMPLAYER_FLEAVE();
9490
9491         return MM_ERROR_NONE;
9492 }
9493
9494 static int
9495 __mmplayer_start_streaming_ext(mm_player_t *player)
9496 {
9497         gint ret = MM_ERROR_NONE;
9498
9499         MMPLAYER_FENTER();
9500         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9501
9502         if (MMPLAYER_IS_HTTP_PD(player)) {
9503                 if (!player->pd_downloader) {
9504                         ret = __mmplayer_realize_streaming_ext(player);
9505
9506                         if (ret != MM_ERROR_NONE) {
9507                                 LOGE("failed to realize streaming ext\n");
9508                                 return ret;
9509                         }
9510                 }
9511
9512                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9513                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9514                         if (!ret) {
9515                                 LOGE("ERROR while starting PD...\n");
9516                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9517                         }
9518                         ret = MM_ERROR_NONE;
9519                 }
9520         }
9521
9522         MMPLAYER_FLEAVE();
9523         return ret;
9524 }
9525
9526 int
9527 _mmplayer_start(MMHandleType hplayer)
9528 {
9529         mm_player_t* player = (mm_player_t*) hplayer;
9530         gint ret = MM_ERROR_NONE;
9531
9532         MMPLAYER_FENTER();
9533
9534         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9535
9536         /* check current state */
9537         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9538
9539         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9540         if (ret != MM_ERROR_NONE) {
9541                 LOGE("failed to acquire sound focus.\n");
9542                 return ret;
9543         }
9544
9545         /* NOTE : we should check and create pipeline again if not created as we destroy
9546          * whole pipeline when stopping in streamming playback
9547          */
9548         if (!player->pipeline) {
9549                 ret = __gst_realize(player);
9550                 if (MM_ERROR_NONE != ret) {
9551                         LOGE("failed to realize before starting. only in streamming\n");
9552                         /* unlock */
9553                         return ret;
9554                 }
9555         }
9556
9557         ret = __mmplayer_start_streaming_ext(player);
9558         if (ret != MM_ERROR_NONE)
9559                 LOGE("failed to start streaming ext \n");
9560
9561         /* start pipeline */
9562         ret = __gst_start(player);
9563         if (ret != MM_ERROR_NONE)
9564                 LOGE("failed to start player.\n");
9565
9566         MMPLAYER_FLEAVE();
9567
9568         return ret;
9569 }
9570
9571 /* NOTE: post "not supported codec message" to application
9572  * when one codec is not found during AUTOPLUGGING in MSL.
9573  * So, it's separated with error of __mmplayer_gst_callback().
9574  * And, if any codec is not found, don't send message here.
9575  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9576  */
9577 int
9578 __mmplayer_handle_missed_plugin(mm_player_t* player)
9579 {
9580         MMMessageParamType msg_param;
9581         memset(&msg_param, 0, sizeof(MMMessageParamType));
9582         gboolean post_msg_direct = FALSE;
9583
9584         MMPLAYER_FENTER();
9585
9586         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9587
9588         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9589                         player->not_supported_codec, player->can_support_codec);
9590
9591         if (player->not_found_demuxer) {
9592                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9593                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9594
9595                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9596                 MMPLAYER_FREEIF(msg_param.data);
9597
9598                 return MM_ERROR_NONE;
9599         }
9600
9601         if (player->not_supported_codec) {
9602                 if (player->can_support_codec) {
9603                         // There is one codec to play
9604                         post_msg_direct = TRUE;
9605                 } else {
9606                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9607                                 post_msg_direct = TRUE;
9608                 }
9609
9610                 if (post_msg_direct) {
9611                         MMMessageParamType msg_param;
9612                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9613
9614                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9615                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9616
9617                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9618                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9619                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9620                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9621
9622                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9623                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9624                         }
9625
9626                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9627
9628                         MMPLAYER_FREEIF(msg_param.data);
9629
9630                         return MM_ERROR_NONE;
9631                 } else {
9632                         // no any supported codec case
9633                         LOGW("not found any codec, posting error code to application.\n");
9634
9635                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9636                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9637                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9638                         } else {
9639                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9640                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9641                         }
9642
9643                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9644
9645                         MMPLAYER_FREEIF(msg_param.data);
9646                 }
9647         }
9648
9649         MMPLAYER_FLEAVE();
9650
9651         return MM_ERROR_NONE;
9652 }
9653
9654 static void __mmplayer_check_pipeline(mm_player_t* player)
9655 {
9656         GstState element_state = GST_STATE_VOID_PENDING;
9657         GstState element_pending_state = GST_STATE_VOID_PENDING;
9658         gint timeout = 0;
9659         int ret = MM_ERROR_NONE;
9660
9661         if (player->gapless.reconfigure) {
9662                 LOGW("pipeline is under construction.\n");
9663
9664                 MMPLAYER_PLAYBACK_LOCK(player);
9665                 MMPLAYER_PLAYBACK_UNLOCK(player);
9666
9667                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9668
9669                 /* wait for state transition */
9670                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9671
9672                 if (ret == GST_STATE_CHANGE_FAILURE)
9673                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9674         }
9675 }
9676
9677 /* NOTE : it should be able to call 'stop' anytime*/
9678 int
9679 _mmplayer_stop(MMHandleType hplayer)
9680 {
9681         mm_player_t* player = (mm_player_t*)hplayer;
9682         int ret = MM_ERROR_NONE;
9683
9684         MMPLAYER_FENTER();
9685
9686         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9687
9688         /* check current state */
9689         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9690
9691         /* check pipline building state */
9692         __mmplayer_check_pipeline(player);
9693         __mmplayer_reset_gapless_state(player);
9694
9695         /* NOTE : application should not wait for EOS after calling STOP */
9696         __mmplayer_cancel_eos_timer(player);
9697
9698         __mmplayer_unrealize_streaming_ext(player);
9699
9700         /* reset */
9701         player->doing_seek = FALSE;
9702
9703         /* stop pipeline */
9704         ret = __gst_stop(player);
9705
9706         if (ret != MM_ERROR_NONE)
9707                 LOGE("failed to stop player.\n");
9708
9709         MMPLAYER_FLEAVE();
9710
9711         return ret;
9712 }
9713
9714 int
9715 _mmplayer_pause(MMHandleType hplayer)
9716 {
9717         mm_player_t* player = (mm_player_t*)hplayer;
9718         gint64 pos_msec = 0;
9719         gboolean async = FALSE;
9720         gint ret = MM_ERROR_NONE;
9721
9722         MMPLAYER_FENTER();
9723
9724         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9725
9726         /* check current state */
9727         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9728
9729         /* check pipline building state */
9730         __mmplayer_check_pipeline(player);
9731
9732         switch (MMPLAYER_CURRENT_STATE(player)) {
9733         case MM_PLAYER_STATE_READY:
9734                 {
9735                         /* check prepare async or not.
9736                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9737                          */
9738                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9739                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9740
9741                         /* Changing back sync of rtspsrc to async */
9742                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9743                                 LOGD("async prepare working mode for rtsp");
9744                                 async = TRUE;
9745                         }
9746                 }
9747                 break;
9748
9749         case MM_PLAYER_STATE_PLAYING:
9750                 {
9751                         /* NOTE : store current point to overcome some bad operation
9752                         *(returning zero when getting current position in paused state) of some
9753                         * elements
9754                         */
9755                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9756                                 LOGW("getting current position failed in paused\n");
9757
9758                         player->last_position = pos_msec;
9759
9760                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9761                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9762                            This causes problem is position calculation during normal pause resume scenarios also.
9763                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9764                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9765                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9766                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9767                         }
9768                 }
9769                 break;
9770         }
9771
9772         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9773                 LOGD("doing async pause in case of ms buff src");
9774                 async = TRUE;
9775         }
9776
9777         /* pause pipeline */
9778         ret = __gst_pause(player, async);
9779
9780         if (ret != MM_ERROR_NONE)
9781                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9782
9783         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9784                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9785                         LOGE("failed to update display_rotation");
9786         }
9787
9788         MMPLAYER_FLEAVE();
9789
9790         return ret;
9791 }
9792
9793 int
9794 _mmplayer_resume(MMHandleType hplayer)
9795 {
9796         mm_player_t* player = (mm_player_t*)hplayer;
9797         int ret = MM_ERROR_NONE;
9798         gboolean async = FALSE;
9799
9800         MMPLAYER_FENTER();
9801
9802         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9803
9804         /* Changing back sync mode rtspsrc to async */
9805         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9806                 LOGD("async resume for rtsp case");
9807                 async = TRUE;
9808         }
9809
9810         /* check current state */
9811         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9812
9813         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9814         if (ret != MM_ERROR_NONE) {
9815                 LOGE("failed to acquire sound focus.\n");
9816                 return ret;
9817         }
9818
9819         ret = __gst_resume(player, async);
9820
9821         if (ret != MM_ERROR_NONE)
9822                 LOGE("failed to resume player.\n");
9823
9824         MMPLAYER_FLEAVE();
9825
9826         return ret;
9827 }
9828
9829 int
9830 __mmplayer_set_play_count(mm_player_t* player, gint count)
9831 {
9832         MMHandleType attrs = 0;
9833
9834         MMPLAYER_FENTER();
9835
9836         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9837
9838         attrs =  MMPLAYER_GET_ATTRS(player);
9839         if (!attrs) {
9840                 LOGE("fail to get attributes.\n");
9841                 return MM_ERROR_PLAYER_INTERNAL;
9842         }
9843
9844         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9845         if (mmf_attrs_commit(attrs)) /* return -1 if error */
9846                 LOGE("failed to commit\n");
9847
9848         MMPLAYER_FLEAVE();
9849
9850         return  MM_ERROR_NONE;
9851 }
9852
9853 int
9854 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9855 {
9856         mm_player_t* player = (mm_player_t*)hplayer;
9857         gint64 start_pos = 0;
9858         gint64 end_pos = 0;
9859         gint infinity = -1;
9860
9861         MMPLAYER_FENTER();
9862
9863         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9864         MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9865
9866         player->section_repeat = TRUE;
9867         player->section_repeat_start = start;
9868         player->section_repeat_end = end;
9869
9870         start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9871         end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9872
9873         __mmplayer_set_play_count(player, infinity);
9874
9875         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9876                                         player->playback_rate,
9877                                         GST_FORMAT_TIME,
9878                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9879                                         GST_SEEK_TYPE_SET, start_pos,
9880                                         GST_SEEK_TYPE_SET, end_pos))) {
9881                 LOGE("failed to activate section repeat\n");
9882
9883                 return MM_ERROR_PLAYER_SEEK;
9884         }
9885
9886         LOGD("succeeded to set section repeat from %d to %d\n",
9887                 player->section_repeat_start, player->section_repeat_end);
9888
9889         MMPLAYER_FLEAVE();
9890
9891         return  MM_ERROR_NONE;
9892 }
9893
9894 static int
9895 __mmplayer_set_pcm_extraction(mm_player_t* player)
9896 {
9897         gint64 start_nsec = 0;
9898         gint64 end_nsec = 0;
9899         gint64 dur_nsec = 0;
9900         gint64 dur_msec = 0;
9901         int required_start = 0;
9902         int required_end = 0;
9903         int ret = 0;
9904
9905         MMPLAYER_FENTER();
9906
9907         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9908
9909         mm_attrs_multiple_get(player->attrs,
9910                 NULL,
9911                 "pcm_extraction_start_msec", &required_start,
9912                 "pcm_extraction_end_msec", &required_end,
9913                 NULL);
9914
9915         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9916
9917         if (required_start == 0 && required_end == 0) {
9918                 LOGD("extracting entire stream");
9919                 return MM_ERROR_NONE;
9920         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9921                 LOGD("invalid range for pcm extraction");
9922                 return MM_ERROR_INVALID_ARGUMENT;
9923         }
9924
9925         /* get duration */
9926         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9927         if (!ret) {
9928                 LOGE("failed to get duration");
9929                 return MM_ERROR_PLAYER_INTERNAL;
9930         }
9931         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9932
9933         if (dur_msec < required_end) {
9934                 // FIXME
9935                 LOGD("invalid end pos for pcm extraction");
9936                 return MM_ERROR_INVALID_ARGUMENT;
9937         }
9938
9939         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9940         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9941
9942         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9943                                         1.0,
9944                                         GST_FORMAT_TIME,
9945                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9946                                         GST_SEEK_TYPE_SET, start_nsec,
9947                                         GST_SEEK_TYPE_SET, end_nsec))) {
9948                 LOGE("failed to seek for pcm extraction\n");
9949
9950                 return MM_ERROR_PLAYER_SEEK;
9951         }
9952
9953         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9954
9955         MMPLAYER_FLEAVE();
9956
9957         return MM_ERROR_NONE;
9958 }
9959
9960 int
9961 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9962 {
9963         mm_player_t* player = (mm_player_t*)hplayer;
9964         gint64 cur_pos = 0;
9965         gint onetime = 1;
9966
9967         MMPLAYER_FENTER();
9968
9969         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9970
9971         player->section_repeat = FALSE;
9972
9973         __mmplayer_set_play_count(player, onetime);
9974
9975         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9976
9977         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9978                                         1.0,
9979                                         GST_FORMAT_TIME,
9980                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9981                                         GST_SEEK_TYPE_SET, cur_pos,
9982                                         GST_SEEK_TYPE_SET, player->duration))) {
9983                 LOGE("failed to deactivate section repeat\n");
9984
9985                 return MM_ERROR_PLAYER_SEEK;
9986         }
9987
9988         MMPLAYER_FENTER();
9989
9990         return MM_ERROR_NONE;
9991 }
9992
9993 int
9994 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9995 {
9996         mm_player_t* player = (mm_player_t*)hplayer;
9997         gint64 pos_msec = 0;
9998         int ret = MM_ERROR_NONE;
9999         int mute = FALSE;
10000         signed long long start = 0, stop = 0;
10001         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10002         MMPLAYER_FENTER();
10003
10004         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10005         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
10006
10007         /* The sound of video is not supported under 0.0 and over 2.0. */
10008         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
10009                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10010                         mute = TRUE;
10011         }
10012         _mmplayer_set_mute(hplayer, mute);
10013
10014         if (player->playback_rate == rate)
10015                 return MM_ERROR_NONE;
10016
10017         /* If the position is reached at start potion during fast backward, EOS is posted.
10018          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10019          * */
10020         player->playback_rate = rate;
10021
10022         current_state = MMPLAYER_CURRENT_STATE(player);
10023
10024         if (current_state != MM_PLAYER_STATE_PAUSED)
10025                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10026
10027         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
10028
10029         if ((current_state == MM_PLAYER_STATE_PAUSED)
10030                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
10031                 LOGW("returning last point : %lld\n", player->last_position);
10032                 pos_msec = player->last_position;
10033         }
10034
10035         if (rate >= 0) {
10036                 start = pos_msec;
10037                 stop = GST_CLOCK_TIME_NONE;
10038         } else {
10039                 start = GST_CLOCK_TIME_NONE;
10040                 stop = pos_msec;
10041         }
10042
10043         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10044                                 player->playback_rate,
10045                                 GST_FORMAT_TIME,
10046                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10047                                 GST_SEEK_TYPE_SET, start,
10048                                 GST_SEEK_TYPE_SET, stop)) {
10049                 LOGE("failed to set speed playback\n");
10050                 return MM_ERROR_PLAYER_SEEK;
10051         }
10052
10053         LOGD("succeeded to set speed playback as %0.1f\n", rate);
10054
10055         MMPLAYER_FLEAVE();
10056
10057         return MM_ERROR_NONE;;
10058 }
10059
10060 int
10061 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
10062 {
10063         mm_player_t* player = (mm_player_t*)hplayer;
10064         int ret = MM_ERROR_NONE;
10065
10066         MMPLAYER_FENTER();
10067
10068         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10069
10070         /* check pipline building state */
10071         __mmplayer_check_pipeline(player);
10072
10073         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10074
10075         MMPLAYER_FLEAVE();
10076
10077         return ret;
10078 }
10079
10080 int
10081 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
10082 {
10083         mm_player_t* player = (mm_player_t*)hplayer;
10084         int ret = MM_ERROR_NONE;
10085
10086         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10087
10088         ret = __gst_get_position(player, format, position);
10089
10090         return ret;
10091 }
10092
10093 int
10094 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
10095 {
10096         mm_player_t* player = (mm_player_t*)hplayer;
10097         int ret = MM_ERROR_NONE;
10098
10099         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10100
10101         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10102
10103         return ret;
10104 }
10105
10106 int
10107 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
10108 {
10109         mm_player_t* player = (mm_player_t*)hplayer;
10110         int ret = MM_ERROR_NONE;
10111
10112         MMPLAYER_FENTER();
10113
10114         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10115
10116         ret = __gst_adjust_subtitle_position(player, format, position);
10117
10118         MMPLAYER_FLEAVE();
10119
10120         return ret;
10121 }
10122 int
10123 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
10124 {
10125         mm_player_t* player = (mm_player_t*)hplayer;
10126         int ret = MM_ERROR_NONE;
10127
10128         MMPLAYER_FENTER();
10129
10130         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10131
10132         ret = __gst_adjust_video_position(player, offset);
10133
10134         MMPLAYER_FLEAVE();
10135
10136         return ret;
10137 }
10138
10139 static gboolean
10140 __mmplayer_is_midi_type(gchar* str_caps)
10141 {
10142         if ((g_strrstr(str_caps, "audio/midi")) ||
10143                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10144                 (g_strrstr(str_caps, "application/x-smaf")) ||
10145                 (g_strrstr(str_caps, "audio/x-imelody")) ||
10146                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10147                 (g_strrstr(str_caps, "audio/xmf")) ||
10148                 (g_strrstr(str_caps, "audio/mxmf"))) {
10149                 LOGD("midi\n");
10150                 return TRUE;
10151         }
10152
10153         return FALSE;
10154 }
10155
10156 static gboolean
10157 __mmplayer_is_only_mp3_type(gchar *str_caps)
10158 {
10159         if (g_strrstr(str_caps, "application/x-id3") ||
10160                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10161                 return TRUE;
10162         return FALSE;
10163 }
10164
10165 static void
10166 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10167 {
10168         GstStructure* caps_structure = NULL;
10169         gint samplerate = 0;
10170         gint channels = 0;
10171
10172         MMPLAYER_FENTER();
10173         MMPLAYER_RETURN_IF_FAIL(player && caps);
10174
10175         caps_structure = gst_caps_get_structure(caps, 0);
10176
10177         /* set stream information */
10178         gst_structure_get_int(caps_structure, "rate", &samplerate);
10179         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10180
10181         gst_structure_get_int(caps_structure, "channels", &channels);
10182         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10183
10184         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
10185 }
10186
10187 static void
10188 __mmplayer_update_content_type_info(mm_player_t* player)
10189 {
10190         MMPLAYER_FENTER();
10191         MMPLAYER_RETURN_IF_FAIL(player && player->type);
10192
10193         if (__mmplayer_is_midi_type(player->type)) {
10194                 player->bypass_audio_effect = TRUE;
10195         } else if (g_strrstr(player->type, "application/x-hls")) {
10196                 /* If it can't know exact type when it parses uri because of redirection case,
10197                  * it will be fixed by typefinder or when doing autoplugging.
10198                  */
10199                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10200                 if (player->streamer) {
10201                         player->streamer->is_adaptive_streaming = TRUE;
10202                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10203                         player->streamer->buffering_req.runtime_second = 5;
10204                 }
10205         } else if (g_strrstr(player->type, "application/dash+xml")) {
10206                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10207         }
10208
10209         MMPLAYER_FLEAVE();
10210 }
10211
10212 static void
10213 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
10214 GstCaps *caps, gpointer data)
10215 {
10216         mm_player_t* player = (mm_player_t*)data;
10217         GstPad* pad = NULL;
10218
10219         MMPLAYER_FENTER();
10220
10221         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10222
10223         /* store type string */
10224         MMPLAYER_FREEIF(player->type);
10225         player->type = gst_caps_to_string(caps);
10226         if (player->type)
10227                 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10228
10229         if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10230                 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10231                 (g_strrstr(player->type, "audio/x-raw-int"))) {
10232                 LOGE("not support media format\n");
10233
10234                 if (player->msg_posted == FALSE) {
10235                         MMMessageParamType msg_param;
10236                         memset(&msg_param, 0, sizeof(MMMessageParamType));
10237
10238                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10239                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10240
10241                         /* don't post more if one was sent already */
10242                         player->msg_posted = TRUE;
10243                 }
10244                 return;
10245         }
10246
10247         __mmplayer_update_content_type_info(player);
10248
10249         pad = gst_element_get_static_pad(tf, "src");
10250         if (!pad) {
10251                 LOGE("fail to get typefind src pad.\n");
10252                 return;
10253         }
10254
10255         if (player->use_decodebin) {
10256                 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10257                         gboolean async = FALSE;
10258                         LOGE("failed to autoplug %s\n", player->type);
10259
10260                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10261
10262                         if (async && player->msg_posted == FALSE)
10263                                 __mmplayer_handle_missed_plugin(player);
10264
10265                         goto DONE;
10266                 }
10267         } else {
10268                 /* try to plug */
10269                 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10270                         gboolean async = FALSE;
10271                         LOGE("failed to autoplug %s\n", player->type);
10272
10273                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10274
10275                         if (async && player->msg_posted == FALSE)
10276                                 __mmplayer_handle_missed_plugin(player);
10277
10278                         goto DONE;
10279                 }
10280
10281                 /* finish autopluging if no dynamic pad waiting */
10282                 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10283                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
10284                                 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10285                 }
10286         }
10287
10288 DONE:
10289         gst_object_unref(GST_OBJECT(pad));
10290
10291         MMPLAYER_FLEAVE();
10292
10293         return;
10294 }
10295
10296 static GstElement *
10297 __mmplayer_create_decodebin(mm_player_t* player)
10298 {
10299         GstElement *decodebin = NULL;
10300
10301         MMPLAYER_FENTER();
10302
10303         /* create decodebin */
10304         decodebin = gst_element_factory_make("decodebin", NULL);
10305
10306         if (!decodebin) {
10307                 LOGE("fail to create decodebin\n");
10308                 goto ERROR;
10309         }
10310
10311         /* raw pad handling signal */
10312         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10313                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10314
10315         /* no-more-pad pad handling signal */
10316         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10317                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10318
10319         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10320                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10321
10322         /* This signal is emitted when a pad for which there is no further possible
10323            decoding is added to the decodebin.*/
10324         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10325                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10326
10327         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10328            before looking for any elements that can handle that stream.*/
10329         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10330                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10331
10332         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10333            before looking for any elements that can handle that stream.*/
10334         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10335                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10336
10337         /* This signal is emitted once decodebin has finished decoding all the data.*/
10338         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10339                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10340
10341         /* This signal is emitted when a element is added to the bin.*/
10342         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10343                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
10344
10345 ERROR:
10346         return decodebin;
10347 }
10348
10349 static gboolean
10350 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10351 {
10352         MMPlayerGstElement* mainbin = NULL;
10353         GstElement* decodebin = NULL;
10354         GstElement* queue2 = NULL;
10355         GstPad* sinkpad = NULL;
10356         GstPad* qsrcpad = NULL;
10357         gint64 dur_bytes = 0L;
10358
10359         guint max_buffer_size_bytes = 0;
10360         gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10361
10362         MMPLAYER_FENTER();
10363         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10364
10365         mainbin = player->pipeline->mainbin;
10366
10367         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10368                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10369                 LOGD("creating http streaming buffering queue(queue2)\n");
10370
10371                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10372                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10373                 } else {
10374                         queue2 = gst_element_factory_make("queue2", "queue2");
10375                         if (!queue2) {
10376                                 LOGE("failed to create buffering queue element\n");
10377                                 goto ERROR;
10378                         }
10379
10380                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10381                                 LOGE("failed to add buffering queue\n");
10382                                 goto ERROR;
10383                         }
10384
10385                         sinkpad = gst_element_get_static_pad(queue2, "sink");
10386                         qsrcpad = gst_element_get_static_pad(queue2, "src");
10387
10388                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10389                                 LOGE("failed to link buffering queue\n");
10390                                 goto ERROR;
10391                         }
10392
10393                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10394                                 LOGE("fail to get duration.\n");
10395
10396                         LOGD("dur_bytes = %lld\n", dur_bytes);
10397
10398                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10399
10400                         if (dur_bytes > 0) {
10401                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10402                                         type = MUXED_BUFFER_TYPE_FILE;
10403                                 } else {
10404                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10405                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10406                                 }
10407                         } else {
10408                                 dur_bytes = 0;
10409                         }
10410
10411                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
10412                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10413                         if (!g_strrstr(player->type, "video/mpegts")) {
10414                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10415                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10416
10417                                 __mm_player_streaming_set_queue2(player->streamer,
10418                                                                                                 queue2,
10419                                                                                                 FALSE,
10420                                                                                                 max_buffer_size_bytes,
10421                                                                                                 player->ini.http_buffering_time,
10422                                                                                                 1.0,                                                            // no meaning
10423                                                                                                 player->ini.http_buffering_limit,       // no meaning
10424                                                                                                 type,
10425                                                                                                 player->http_file_buffering_path,
10426                                                                                                 (guint64)dur_bytes);
10427                         }
10428
10429                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10430                                 LOGE("failed to sync queue2 state with parent\n");
10431                                 goto ERROR;
10432                         }
10433
10434                         srcpad = qsrcpad;
10435
10436                         gst_object_unref(GST_OBJECT(sinkpad));
10437
10438                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10439                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10440                 }
10441         }
10442
10443         /* create decodebin */
10444         decodebin = __mmplayer_create_decodebin(player);
10445
10446         if (!decodebin) {
10447                 LOGE("can not create autoplug element\n");
10448                 goto ERROR;
10449         }
10450
10451         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10452                 LOGE("failed to add decodebin\n");
10453                 goto ERROR;
10454         }
10455
10456         /* to force caps on the decodebin element and avoid reparsing stuff by
10457         * typefind. It also avoids a deadlock in the way typefind activates pads in
10458         * the state change */
10459         g_object_set(decodebin, "sink-caps", caps, NULL);
10460
10461         sinkpad = gst_element_get_static_pad(decodebin, "sink");
10462
10463         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10464                 LOGE("failed to link decodebin\n");
10465                 goto ERROR;
10466         }
10467
10468         gst_object_unref(GST_OBJECT(sinkpad));
10469
10470         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10471         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10472
10473         /* set decodebin property about buffer in streaming playback. *
10474          * in case of hls, it does not need to have big buffer        *
10475          * because it is kind of adaptive streaming.                  */
10476         if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10477            (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10478                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10479                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10480                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10481
10482                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10483                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10484                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10485                 }
10486
10487                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10488                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
10489                                                                                         "low-percent", 1,   // 1%
10490                                                                                         "max-size-bytes", max_size_bytes,
10491                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
10492                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
10493         }
10494
10495         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10496                 LOGE("failed to sync decodebin state with parent\n");
10497                 goto ERROR;
10498         }
10499
10500         MMPLAYER_FLEAVE();
10501
10502         return TRUE;
10503
10504 ERROR:
10505
10506         if (sinkpad)
10507                 gst_object_unref(GST_OBJECT(sinkpad));
10508
10509         if (queue2) {
10510                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10511                  * You need to explicitly set elements to the NULL state before
10512                  * dropping the final reference, to allow them to clean up.
10513                  */
10514                 gst_element_set_state(queue2, GST_STATE_NULL);
10515
10516                 /* And, it still has a parent "player".
10517                  * You need to let the parent manage the object instead of unreffing the object directly.
10518                  */
10519                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10520                 gst_object_unref(queue2);
10521                 queue2 = NULL;
10522         }
10523
10524         if (decodebin) {
10525                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10526                  * You need to explicitly set elements to the NULL state before
10527                  * dropping the final reference, to allow them to clean up.
10528                  */
10529                 gst_element_set_state(decodebin, GST_STATE_NULL);
10530
10531                 /* And, it still has a parent "player".
10532                  * You need to let the parent manage the object instead of unreffing the object directly.
10533                  */
10534
10535                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10536                 gst_object_unref(decodebin);
10537                 decodebin = NULL;
10538         }
10539
10540         return FALSE;
10541 }
10542
10543 /* it will return first created element */
10544 static gboolean
10545 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps)
10546 {
10547         MMPlayerGstElement* mainbin = NULL;
10548         const char* mime = NULL;
10549         const GList* item = NULL;
10550         const gchar* klass = NULL;
10551         GstCaps* res = NULL;
10552         gboolean skip = FALSE;
10553         GstPad* queue_pad = NULL;
10554         GstElement* queue = NULL;
10555         GstElement *element = NULL;
10556
10557         MMPLAYER_FENTER();
10558
10559         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10560
10561         mainbin = player->pipeline->mainbin;
10562
10563         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10564
10565         /* return if we got raw output */
10566         if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10567                 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10568
10569                 element = (GstElement*)gst_pad_get_parent(pad);
10570 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10571  * No queue will be added. I think it can caused breaking sound when playing raw audio
10572  * frames but there's no different. Decodebin also doesn't add with those wav fils.
10573  * Anyway, currentely raw-queue seems not necessary.
10574  */
10575 #if 1
10576                 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10577                  * has linked. if so, we need to add queue for quality of output. note that
10578                  * decodebin also has same problem.
10579                  */
10580                 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10581
10582                 /* add queue if needed */
10583                 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10584                         || g_strrstr(klass, "Parse")) &&  !g_str_has_prefix(mime, "text")) {
10585                         LOGD("adding raw queue\n");
10586
10587                         queue = gst_element_factory_make("queue", NULL);
10588                         if (!queue) {
10589                                 LOGW("failed to create queue\n");
10590                                 goto ERROR;
10591                         }
10592
10593                         /* warmup */
10594                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10595                                 LOGW("failed to set state READY to queue\n");
10596                                 goto ERROR;
10597                         }
10598
10599                         /* add to pipeline */
10600                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10601                                 LOGW("failed to add queue\n");
10602                                 goto ERROR;
10603                         }
10604
10605                         /* link queue */
10606                         queue_pad = gst_element_get_static_pad(queue, "sink");
10607
10608                         if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10609                                 LOGW("failed to link queue\n");
10610                                 goto ERROR;
10611                         }
10612                         gst_object_unref(GST_OBJECT(queue_pad));
10613                         queue_pad = NULL;
10614
10615                         /* running */
10616                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10617                                 LOGW("failed to set state PAUSED to queue\n");
10618                                 goto ERROR;
10619                         }
10620
10621                         /* replace given pad to queue:src */
10622                         pad = gst_element_get_static_pad(queue, "src");
10623                         if (!pad) {
10624                                 LOGW("failed to get pad from queue\n");
10625                                 goto ERROR;
10626                         }
10627                 }
10628 #endif
10629                 /* check if player can do start continually */
10630                 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10631
10632                 if (__mmplayer_link_sink(player, pad))
10633                         __mmplayer_gst_decode_callback(element, pad, player);
10634
10635                 gst_object_unref(GST_OBJECT(element));
10636                 element = NULL;
10637
10638                 return TRUE;
10639         }
10640
10641         item = player->factories;
10642         for (; item != NULL; item = item->next) {
10643                 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10644                 const GList *pads;
10645                 gint idx = 0;
10646
10647                 skip = FALSE;
10648
10649                 /* filtering exclude keyword */
10650                 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10651                         if (g_strrstr(GST_OBJECT_NAME(factory),
10652                                         player->ini.exclude_element_keyword[idx])) {
10653                                 LOGW("skipping [%s] by exculde keyword [%s]\n",
10654                                         GST_OBJECT_NAME(factory),
10655                                         player->ini.exclude_element_keyword[idx]);
10656
10657                                 skip = TRUE;
10658                                 break;
10659                         }
10660                 }
10661
10662                 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10663                         // omx decoder can not support mpeg4video data partitioned
10664                         // rtsp streaming didn't know mpeg4video data partitioned format
10665                         // so, if rtsp playback, player will skip omx_mpeg4dec.
10666                         LOGW("skipping [%s] when rtsp streaming \n",
10667                                         GST_OBJECT_NAME(factory));
10668
10669                         skip = TRUE;
10670                 }
10671
10672                 if (skip) continue;
10673
10674                 /* check factory class for filtering */
10675                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10676
10677                 /*parsers are not required in case of external feeder*/
10678                 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10679                         continue;
10680
10681                 /* NOTE : msl don't need to use image plugins.
10682                  * So, those plugins should be skipped for error handling.
10683                  */
10684                 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10685                         LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10686                         continue;
10687                 }
10688
10689                 /* check pad compatability */
10690                 for (pads = gst_element_factory_get_static_pad_templates(factory);
10691                                         pads != NULL; pads = pads->next) {
10692                         GstStaticPadTemplate *temp1 = pads->data;
10693                         GstCaps* static_caps = NULL;
10694
10695                         if (temp1->direction != GST_PAD_SINK
10696                                 || temp1->presence != GST_PAD_ALWAYS)
10697                                 continue;
10698
10699                         /* using existing caps */
10700                         if (GST_IS_CAPS(&temp1->static_caps.caps))
10701                                 static_caps = gst_caps_ref(temp1->static_caps.caps);
10702                         /* create one */
10703                         else
10704                                 static_caps = gst_caps_from_string(temp1->static_caps.string);
10705
10706                         res = gst_caps_intersect((GstCaps*)caps, static_caps);
10707                         gst_caps_unref(static_caps);
10708                         static_caps = NULL;
10709
10710                         if (res && !gst_caps_is_empty(res)) {
10711                                 GstElement *new_element;
10712                                 GList *elements = player->parsers;
10713                                 char *name_template = g_strdup(temp1->name_template);
10714                                 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10715                                 gst_caps_unref(res);
10716
10717                                 /* check ALP Codec can be used or not */
10718                                 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10719                                         /* consider mp3 audio only */
10720                                         if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10721                                                 /* try to use ALP decoder first instead of selected decoder */
10722                                                 GstElement *element = NULL;
10723                                                 GstElementFactory * element_facory;
10724                                                 gchar *path = NULL;
10725                                                 guint64 data_size = 0;
10726                                                 #define MIN_THRESHOLD_SIZE  320 * 1024 // 320K
10727                                                 struct stat sb;
10728
10729                                                 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10730
10731                                                 if (stat(path, &sb) == 0)
10732                                                         data_size = (guint64)sb.st_size;
10733                                                 LOGD("file size : %u", data_size);
10734
10735                                                 if (data_size > MIN_THRESHOLD_SIZE) {
10736                                                         LOGD("checking if ALP can be used or not");
10737                                                         element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10738                                                         if (element) {
10739                                                                 /* check availability because multi-instance is not supported */
10740                                                                 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10741
10742                                                                 if (ret != GST_STATE_CHANGE_SUCCESS) {
10743                                                                         // use just selected decoder
10744                                                                         gst_object_unref(element);
10745                                                                 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10746                                                                         // replace facotry to use omx
10747                                                                         /* clean  */
10748                                                                         gst_element_set_state(element, GST_STATE_NULL);
10749                                                                         gst_object_unref(element);
10750
10751                                                                         element_facory = gst_element_factory_find("omx_mp3dec");
10752                                                                         /* replace, otherwise use selected thing instead */
10753                                                                         if (element_facory) {
10754                                                                                 factory = element_facory;
10755                                                                                 name_to_plug = GST_OBJECT_NAME(factory);
10756                                                                         }
10757                                                                 }
10758                                                         }
10759                                                 }
10760                                         }
10761                                 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10762                                         if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10763                                                 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10764                                                 if (env != NULL) {
10765                                                         if (strncasecmp(env, "yes", 3) == 0) {
10766                                                                 LOGD("skipping [%s] by disabled\n", name_to_plug);
10767                                                                 MMPLAYER_FREEIF(name_template);
10768                                                                 continue;
10769                                                         }
10770                                                 }
10771                                         }
10772                                 }
10773
10774                                 LOGD("found %s to plug\n", name_to_plug);
10775
10776                                 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10777                                 if (!new_element) {
10778                                         LOGE("failed to create element [%s]. continue with next.\n",
10779                                                 GST_OBJECT_NAME(factory));
10780
10781                                         MMPLAYER_FREEIF(name_template);
10782
10783                                         continue;
10784                                 }
10785
10786                                 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10787                                  * because parser can accept its own output as input.
10788                                  */
10789                                 if (g_strrstr(klass, "Parser")) {
10790                                         gchar *selected = NULL;
10791
10792                                         for (; elements; elements = g_list_next(elements)) {
10793                                                 gchar *element_name = elements->data;
10794
10795                                                 if (g_strrstr(element_name, name_to_plug)) {
10796                                                         LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10797                                                         skip = TRUE;
10798                                                 }
10799                                         }
10800
10801                                         if (skip) {
10802                                                 MMPLAYER_FREEIF(name_template);
10803                                                 continue;
10804                                         }
10805
10806                                         selected = g_strdup(name_to_plug);
10807                                         player->parsers = g_list_append(player->parsers, selected);
10808                                 }
10809
10810                                 /* store specific handles for futher control */
10811                                 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10812                                         /* FIXIT : first value will be overwritten if there's more
10813                                          * than 1 demuxer/parser
10814                                          */
10815                                         LOGD("plugged element is demuxer. take it\n");
10816                                         mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10817                                         mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10818
10819                                         /*Added for multi audio support */
10820                                         if (g_strrstr(klass, "Demux")) {
10821                                                 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10822                                                 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10823
10824                                                 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10825                                                 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10826                                                 this code should be removed after mpegtsdemux is fixed */
10827                                                 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10828                                                         LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10829                                                         player->no_more_pad = TRUE;
10830                                                 }
10831                                         }
10832                                         if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10833                                                 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10834                                 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10835                                         if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10836                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10837                                                 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10838                                                 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10839                                         } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10840                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10841                                                 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10842                                                 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10843                                         }
10844                                         /* NOTE : IF one codec is found, add it to supported_codec and remove from
10845                                          * missing plugin. Both of them are used to check what's supported codec
10846                                          * before returning result of play start. And, missing plugin should be
10847                                          * updated here for multi track files.
10848                                          */
10849                                         if (g_str_has_prefix(mime, "video")) {
10850                                                 GstPad *src_pad = NULL;
10851                                                 GstPadTemplate *pad_templ = NULL;
10852                                                 GstCaps *caps = NULL;
10853                                                 gchar *caps_str = NULL;
10854
10855                                                 LOGD("found VIDEO decoder\n");
10856                                                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10857                                                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10858
10859                                                 src_pad = gst_element_get_static_pad(new_element, "src");
10860                                                 pad_templ = gst_pad_get_pad_template(src_pad);
10861                                                 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10862
10863                                                 caps_str = gst_caps_to_string(caps);
10864
10865                                                 /* clean */
10866                                                 MMPLAYER_FREEIF(caps_str);
10867                                                 gst_object_unref(src_pad);
10868                                         } else if (g_str_has_prefix(mime, "audio")) {
10869                                                 LOGD("found AUDIO decoder\n");
10870                                                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10871                                                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10872                                         }
10873                                 }
10874
10875                                 if (!__mmplayer_close_link(player, pad, new_element,
10876                                                         name_template, gst_element_factory_get_static_pad_templates(factory))) {
10877                                         MMPLAYER_FREEIF(name_template);
10878                                         if (player->keep_detecting_vcodec)
10879                                                 continue;
10880
10881                                         /* Link is failed even though a supportable codec is found. */
10882                                         __mmplayer_check_not_supported_codec(player, klass, mime);
10883
10884                                         LOGE("failed to call _close_link\n");
10885                                         return FALSE;
10886                                 }
10887
10888                                 MMPLAYER_FREEIF(name_template);
10889                                 return TRUE;
10890                         }
10891
10892                         gst_caps_unref(res);
10893                         break;
10894                 }
10895         }
10896
10897         /* There is no available codec. */
10898         __mmplayer_check_not_supported_codec(player, klass, mime);
10899
10900         MMPLAYER_FLEAVE();
10901         return FALSE;
10902
10903 ERROR:
10904         /* release */
10905         if (queue)
10906                 gst_object_unref(queue);
10907
10908         if (queue_pad)
10909                 gst_object_unref(queue_pad);
10910
10911         if (element)
10912                 gst_object_unref(element);
10913
10914         return FALSE;
10915 }
10916
10917
10918 static int
10919 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10920 {
10921         MMPLAYER_FENTER();
10922
10923         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10924         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10925
10926         LOGD("class : %s, mime : %s \n", factory_class, mime);
10927
10928         /* add missing plugin */
10929         /* NOTE : msl should check missing plugin for image mime type.
10930          * Some motion jpeg clips can have playable audio track.
10931          * So, msl have to play audio after displaying popup written video format not supported.
10932          */
10933         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10934                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10935                         LOGD("not found demuxer\n");
10936                         player->not_found_demuxer = TRUE;
10937                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10938
10939                         goto DONE;
10940                 }
10941         }
10942
10943         if (!g_strrstr(factory_class, "Demuxer")) {
10944                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10945                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10946                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10947
10948                         /* check that clip have multi tracks or not */
10949                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10950                                 LOGD("video plugin is already linked\n");
10951                         } else {
10952                                 LOGW("add VIDEO to missing plugin\n");
10953                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10954                         }
10955                 } else if (g_str_has_prefix(mime, "audio")) {
10956                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10957                                 LOGD("audio plugin is already linked\n");
10958                         } else {
10959                                 LOGW("add AUDIO to missing plugin\n");
10960                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10961                         }
10962                 }
10963         }
10964
10965 DONE:
10966         MMPLAYER_FLEAVE();
10967
10968         return MM_ERROR_NONE;
10969 }
10970
10971
10972 static void
10973 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10974 {
10975         mm_player_t* player = (mm_player_t*)data;
10976
10977         MMPLAYER_FENTER();
10978
10979         MMPLAYER_RETURN_IF_FAIL(player);
10980
10981         /* remove fakesink. */
10982         if (!__mmplayer_gst_remove_fakesink(player,
10983                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10984                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10985                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10986                  * source element are not same. To overcome this situation, this function will called
10987                  * several places and several times. Therefore, this is not an error case.
10988                  */
10989                 return;
10990         }
10991
10992         LOGD("pipeline has completely constructed\n");
10993
10994         if ((player->ini.async_start) &&
10995                 (player->msg_posted == FALSE) &&
10996                 (player->cmd >= MMPLAYER_COMMAND_START))
10997                 __mmplayer_handle_missed_plugin(player);
10998
10999         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
11000 }
11001
11002 static gboolean
11003 __mmplayer_verify_next_play_path(mm_player_t *player)
11004 {
11005         MMHandleType attrs = 0;
11006         MMPlayerParseProfile profile;
11007         gint uri_idx = 0, check_cnt = 0;
11008         char *uri = NULL;
11009         gint mode = MM_PLAYER_PD_MODE_NONE;
11010         gint video = 0;
11011         gint count = 0;
11012         gint gapless = 0;
11013         guint num_of_list = 0;
11014         static int profile_tv = -1;
11015
11016         MMPLAYER_FENTER();
11017
11018         LOGD("checking for gapless play");
11019
11020         if (player->pipeline->textbin) {
11021                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
11022                 goto ERROR;
11023         }
11024
11025         attrs = MMPLAYER_GET_ATTRS(player);
11026         if (!attrs) {
11027                 LOGE("fail to get attributes.\n");
11028                 goto ERROR;
11029         }
11030
11031         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
11032
11033         if (__builtin_expect(profile_tv == -1, 0)) {
11034                 char *profileName;
11035                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
11036                 switch (*profileName) {
11037                         case 't':
11038                         case 'T':
11039                                 profile_tv = 1;
11040                                 break;
11041                         default:
11042                                 profile_tv = 0;
11043                 }
11044                 free(profileName);
11045         }
11046         /* gapless playback is not supported in case of video at TV profile. */
11047         if (profile_tv && video) {
11048                 LOGW("not support video gapless playback");
11049                 goto ERROR;
11050         }
11051
11052         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
11053                 if (mode == TRUE) {
11054                         LOGW("pd mode\n");
11055                         goto ERROR;
11056                 }
11057         }
11058
11059         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
11060                 LOGE("can not get play count\n");
11061
11062         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
11063                 LOGE("can not get gapless mode\n");
11064
11065         if (video && !gapless) {
11066                 LOGW("not enabled video gapless playback");
11067                 goto ERROR;
11068         }
11069
11070         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
11071                 gapless = 1;
11072
11073         if (!gapless) {
11074                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
11075                 goto ERROR;
11076         }
11077
11078         num_of_list = g_list_length(player->uri_info.uri_list);
11079
11080         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11081
11082         if (num_of_list == 0) {
11083                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11084                         LOGE("can not get profile_uri\n");
11085                         goto ERROR;
11086                 }
11087
11088                 if (!uri) {
11089                         LOGE("uri list is empty.\n");
11090                         goto ERROR;
11091                 }
11092
11093                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11094                 LOGD("add original path : %s ", uri);
11095
11096                 num_of_list = 1;
11097                 uri = NULL;
11098         }
11099
11100         uri_idx = player->uri_info.uri_idx;
11101
11102         while (TRUE) {
11103                 check_cnt++;
11104
11105                 if (check_cnt > num_of_list) {
11106                         LOGE("there is no valid uri.");
11107                         goto ERROR;
11108                 }
11109
11110                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11111
11112                 if (uri_idx < num_of_list-1) {
11113                         uri_idx++;
11114                 } else {
11115                         if ((count <= 1) && (count != -1)) {
11116                                 LOGD("no repeat.");
11117                                 goto ERROR;
11118                         } else if (count > 1) {
11119                                 /* decrease play count */
11120                                 /* we succeeded to rewind. update play count and then wait for next EOS */
11121                                 count--;
11122
11123                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11124
11125                                 /* commit attribute */
11126                                 if (mmf_attrs_commit(attrs))
11127                                         LOGE("failed to commit attribute\n");
11128                         }
11129
11130                         /* count < 0 : repeat continually */
11131                         uri_idx = 0;
11132                 }
11133
11134                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11135                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11136
11137                 if (uri == NULL) {
11138                         LOGW("next uri does not exist\n");
11139                         continue;
11140                 }
11141
11142                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11143                         LOGE("failed to parse profile\n");
11144                         continue;
11145                 }
11146
11147                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11148                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11149                         LOGW("uri type is not supported(%d).", profile.uri_type);
11150                         continue;
11151                 }
11152
11153                 break;
11154         }
11155
11156         player->uri_info.uri_idx = uri_idx;
11157         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11158
11159         if (mmf_attrs_commit(player->attrs)) {
11160                 LOGE("failed to commit.\n");
11161                 goto ERROR;
11162         }
11163
11164         LOGD("next uri %s(%d)\n", uri, uri_idx);
11165
11166         return TRUE;
11167
11168 ERROR:
11169
11170         LOGE("unable to play next path. EOS will be posted soon.\n");
11171         return FALSE;
11172 }
11173
11174 static void
11175 __mmplayer_initialize_next_play(mm_player_t *player)
11176 {
11177         int i;
11178
11179         MMPLAYER_FENTER();
11180
11181         player->smooth_streaming = FALSE;
11182         player->videodec_linked = 0;
11183         player->audiodec_linked = 0;
11184         player->videosink_linked = 0;
11185         player->audiosink_linked = 0;
11186         player->textsink_linked = 0;
11187         player->is_external_subtitle_present = FALSE;
11188         player->is_external_subtitle_added_now = FALSE;
11189         player->not_supported_codec = MISSING_PLUGIN_NONE;
11190         player->can_support_codec = FOUND_PLUGIN_NONE;
11191         player->pending_seek.is_pending = FALSE;
11192         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11193         player->pending_seek.pos = 0;
11194         player->msg_posted = FALSE;
11195         player->has_many_types = FALSE;
11196         player->no_more_pad = FALSE;
11197         player->not_found_demuxer = 0;
11198         player->doing_seek = FALSE;
11199         player->max_audio_channels = 0;
11200         player->is_subtitle_force_drop = FALSE;
11201         player->play_subtitle = FALSE;
11202         player->adjust_subtitle_pos = 0;
11203
11204         player->updated_bitrate_count = 0;
11205         player->total_bitrate = 0;
11206         player->updated_maximum_bitrate_count = 0;
11207         player->total_maximum_bitrate = 0;
11208
11209         _mmplayer_track_initialize(player);
11210         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11211
11212         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11213                 player->bitrate[i] = 0;
11214                 player->maximum_bitrate[i] = 0;
11215         }
11216
11217         if (player->v_stream_caps) {
11218                 gst_caps_unref(player->v_stream_caps);
11219                 player->v_stream_caps = NULL;
11220         }
11221
11222         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11223         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11224
11225         /* clean found parsers */
11226         if (player->parsers) {
11227                 GList *parsers = player->parsers;
11228                 for (; parsers; parsers = g_list_next(parsers)) {
11229                         gchar *name = parsers->data;
11230                         MMPLAYER_FREEIF(name);
11231                 }
11232                 g_list_free(player->parsers);
11233                 player->parsers = NULL;
11234         }
11235
11236         /* clean found audio decoders */
11237         if (player->audio_decoders) {
11238                 GList *a_dec = player->audio_decoders;
11239                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11240                         gchar *name = a_dec->data;
11241                         MMPLAYER_FREEIF(name);
11242                 }
11243                 g_list_free(player->audio_decoders);
11244                 player->audio_decoders = NULL;
11245         }
11246
11247         MMPLAYER_FLEAVE();
11248 }
11249
11250 static void
11251 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11252 {
11253         MMPlayerGstElement *mainbin = NULL;
11254         MMMessageParamType msg_param = {0,};
11255         GstElement *element = NULL;
11256         MMHandleType attrs = 0;
11257         char *uri = NULL;
11258         enum MainElementID elemId = MMPLAYER_M_NUM;
11259
11260         MMPLAYER_FENTER();
11261
11262         if ((player == NULL) ||
11263                 (player->pipeline == NULL) ||
11264                 (player->pipeline->mainbin == NULL)) {
11265                 LOGE("player is null.\n");
11266                 goto ERROR;
11267         }
11268
11269         mainbin = player->pipeline->mainbin;
11270         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11271
11272         attrs = MMPLAYER_GET_ATTRS(player);
11273         if (!attrs) {
11274                 LOGE("fail to get attributes.\n");
11275                 goto ERROR;
11276         }
11277
11278         /* Initialize Player values */
11279         __mmplayer_initialize_next_play(player);
11280
11281         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11282
11283         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11284                 LOGE("failed to parse profile\n");
11285                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11286                 goto ERROR;
11287         }
11288
11289         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11290                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11291                 LOGE("it's dash or hls. not support.");
11292                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11293                 goto ERROR;
11294         }
11295
11296         /* setup source */
11297         switch (player->profile.uri_type) {
11298         /* file source */
11299         case MM_PLAYER_URI_TYPE_FILE:
11300         {
11301                 LOGD("using filesrc for 'file://' handler.\n");
11302                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
11303                         LOGE("failed to get storage info");
11304                         break;
11305                 }
11306
11307                 element = gst_element_factory_make("filesrc", "source");
11308
11309                 if (!element) {
11310                         LOGE("failed to create filesrc\n");
11311                         break;
11312                 }
11313
11314                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
11315                 break;
11316         }
11317         case MM_PLAYER_URI_TYPE_URL_HTTP:
11318         {
11319                 gchar *user_agent, *proxy, *cookies, **cookie_list;
11320                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11321                 user_agent = proxy = cookies = NULL;
11322                 cookie_list = NULL;
11323
11324                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11325                 if (!element) {
11326                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11327                         break;
11328                 }
11329                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11330
11331                 /* get attribute */
11332                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11333                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11334                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11335                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11336
11337                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11338                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11339                         LOGD("get timeout from ini\n");
11340                         http_timeout = player->ini.http_timeout;
11341                 }
11342
11343                 /* get attribute */
11344                 SECURE_LOGD("location : %s\n", player->profile.uri);
11345                 SECURE_LOGD("cookies : %s\n", cookies);
11346                 SECURE_LOGD("proxy : %s\n", proxy);
11347                 SECURE_LOGD("user_agent :  %s\n", user_agent);
11348                 LOGD("timeout : %d\n", http_timeout);
11349
11350                 /* setting property to streaming source */
11351                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11352                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11353                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11354
11355                 /* check if prosy is vailid or not */
11356                 if (util_check_valid_url(proxy))
11357                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11358                 /* parsing cookies */
11359                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11360                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11361                 if (user_agent)
11362                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11363                 break;
11364         }
11365         default:
11366                 LOGE("not support uri type %d\n", player->profile.uri_type);
11367                 break;
11368         }
11369
11370         if (!element) {
11371                 LOGE("no source element was created.\n");
11372                 goto ERROR;
11373         }
11374
11375         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11376                 LOGE("failed to add source element to pipeline\n");
11377                 gst_object_unref(GST_OBJECT(element));
11378                 element = NULL;
11379                 goto ERROR;
11380         }
11381
11382         /* take source element */
11383         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11384         mainbin[MMPLAYER_M_SRC].gst = element;
11385
11386         element = NULL;
11387
11388         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11389                 if (player->streamer == NULL) {
11390                         player->streamer = __mm_player_streaming_create();
11391                         __mm_player_streaming_initialize(player->streamer);
11392                 }
11393
11394                 elemId = MMPLAYER_M_TYPEFIND;
11395                 element = gst_element_factory_make("typefind", "typefinder");
11396                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11397                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11398         } else {
11399                 elemId = MMPLAYER_M_AUTOPLUG;
11400                 element = __mmplayer_create_decodebin(player);
11401         }
11402
11403         /* check autoplug element is OK */
11404         if (!element) {
11405                 LOGE("can not create element(%d)\n", elemId);
11406                 goto ERROR;
11407         }
11408
11409         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11410                 LOGE("failed to add sinkbin to pipeline\n");
11411                 gst_object_unref(GST_OBJECT(element));
11412                 element = NULL;
11413                 goto ERROR;
11414         }
11415
11416         mainbin[elemId].id = elemId;
11417         mainbin[elemId].gst = element;
11418
11419         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11420                 LOGE("Failed to link src - autoplug(or typefind)\n");
11421                 goto ERROR;
11422         }
11423
11424         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11425                 LOGE("Failed to change state of src element\n");
11426                 goto ERROR;
11427         }
11428
11429         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11430                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11431                         LOGE("Failed to change state of decodebin\n");
11432                         goto ERROR;
11433                 }
11434         } else {
11435                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11436                         LOGE("Failed to change state of src element\n");
11437                         goto ERROR;
11438                 }
11439         }
11440
11441         player->gapless.stream_changed = TRUE;
11442         player->gapless.running = TRUE;
11443         MMPLAYER_FLEAVE();
11444         return;
11445
11446 ERROR:
11447         if (player) {
11448                 MMPLAYER_PLAYBACK_UNLOCK(player);
11449
11450                 if (!player->msg_posted) {
11451                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11452                         player->msg_posted = TRUE;
11453                 }
11454         }
11455         return;
11456 }
11457
11458 static gboolean
11459 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11460 {
11461         mm_player_selector_t *selector = &player->selector[type];
11462         MMPlayerGstElement *sinkbin = NULL;
11463         enum MainElementID selectorId = MMPLAYER_M_NUM;
11464         enum MainElementID sinkId = MMPLAYER_M_NUM;
11465         GstPad *srcpad = NULL;
11466         GstPad *sinkpad = NULL;
11467         gboolean send_notice = FALSE;
11468
11469         MMPLAYER_FENTER();
11470         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11471
11472         LOGD("type %d", type);
11473
11474         switch (type) {
11475         case MM_PLAYER_TRACK_TYPE_AUDIO:
11476                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11477                 sinkId = MMPLAYER_A_BIN;
11478                 sinkbin = player->pipeline->audiobin;
11479                 break;
11480         case MM_PLAYER_TRACK_TYPE_VIDEO:
11481                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11482                 sinkId = MMPLAYER_V_BIN;
11483                 sinkbin = player->pipeline->videobin;
11484                 send_notice = TRUE;
11485                 break;
11486         case MM_PLAYER_TRACK_TYPE_TEXT:
11487                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11488                 sinkId = MMPLAYER_T_BIN;
11489                 sinkbin = player->pipeline->textbin;
11490                 break;
11491         default:
11492                 LOGE("requested type is not supportable");
11493                 return FALSE;
11494                 break;
11495         }
11496
11497         if (player->pipeline->mainbin[selectorId].gst) {
11498                 gint n;
11499
11500                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11501
11502                 if (selector->event_probe_id != 0)
11503                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
11504                 selector->event_probe_id = 0;
11505
11506                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11507                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11508
11509                         if (srcpad && sinkpad) {
11510                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
11511                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11512                                 gst_pad_unlink(srcpad, sinkpad);
11513
11514                                 /* send custom event to sink pad to handle it at video sink */
11515                                 if (send_notice) {
11516                                         LOGD("send custom event to sinkpad");
11517                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11518                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11519                                         gst_pad_send_event(sinkpad, event);
11520                                 }
11521                         }
11522
11523                         gst_object_unref(sinkpad);
11524                         sinkpad = NULL;
11525                 }
11526                 gst_object_unref(srcpad);
11527                 srcpad = NULL;
11528
11529                 LOGD("selector release");
11530
11531                 /* release and unref requests pad from the selector */
11532                 for (n = 0; n < selector->channels->len; n++) {
11533                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11534                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11535                 }
11536                 g_ptr_array_set_size(selector->channels, 0);
11537
11538                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11539                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11540
11541                 player->pipeline->mainbin[selectorId].gst = NULL;
11542                 selector = NULL;
11543         }
11544
11545         return TRUE;
11546 }
11547
11548 static void
11549 __mmplayer_deactivate_old_path(mm_player_t *player)
11550 {
11551         MMPLAYER_FENTER();
11552         MMPLAYER_RETURN_IF_FAIL(player);
11553
11554         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11555                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11556                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11557                 LOGE("deactivate selector error");
11558                 goto ERROR;
11559         }
11560
11561         _mmplayer_track_destroy(player);
11562         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11563
11564         if (player->streamer) {
11565                 __mm_player_streaming_deinitialize(player->streamer);
11566                 __mm_player_streaming_destroy(player->streamer);
11567                 player->streamer = NULL;
11568         }
11569
11570         MMPLAYER_PLAYBACK_LOCK(player);
11571         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11572
11573         MMPLAYER_FLEAVE();
11574         return;
11575
11576 ERROR:
11577
11578         if (!player->msg_posted) {
11579                 MMMessageParamType msg = {0,};
11580
11581                 /*post error*/
11582                 msg.code = MM_ERROR_PLAYER_INTERNAL;
11583                 LOGE("next_uri_play> deactivate error");
11584
11585                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11586                 player->msg_posted = TRUE;
11587         }
11588         return;
11589 }
11590
11591 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11592 {
11593         int result = MM_ERROR_NONE;
11594         mm_player_t* player = (mm_player_t*) hplayer;
11595         MMPLAYER_FENTER();
11596
11597         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11598
11599         if (file_path) {
11600                 player->http_file_buffering_path = (gchar*)file_path;
11601                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11602         }
11603         MMPLAYER_FLEAVE();
11604         return result;
11605 }
11606
11607 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11608 {
11609         int result = MM_ERROR_NONE;
11610         mm_player_t* player = (mm_player_t*) hplayer;
11611         MMPLAYER_FENTER();
11612
11613         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11614
11615         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11616         if (mmf_attrs_commit(player->attrs)) {
11617                 LOGE("failed to commit the original uri.\n");
11618                 result = MM_ERROR_PLAYER_INTERNAL;
11619         } else {
11620                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11621                         LOGE("failed to add the original uri in the uri list.\n");
11622         }
11623
11624         MMPLAYER_FLEAVE();
11625         return result;
11626 }
11627
11628 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11629 {
11630         mm_player_t* player = (mm_player_t*) hplayer;
11631         guint num_of_list = 0;
11632
11633         MMPLAYER_FENTER();
11634
11635         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11636         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11637
11638         if (player->pipeline && player->pipeline->textbin) {
11639                 LOGE("subtitle path is enabled.\n");
11640                 return MM_ERROR_PLAYER_INVALID_STATE;
11641         }
11642
11643         num_of_list = g_list_length(player->uri_info.uri_list);
11644
11645         if (is_first_path == TRUE) {
11646                 if (num_of_list == 0) {
11647                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11648                         LOGD("add original path : %s", uri);
11649                 } else {
11650                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11651                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11652
11653                         LOGD("change original path : %s", uri);
11654                 }
11655         } else {
11656                 MMHandleType attrs = 0;
11657                 attrs = MMPLAYER_GET_ATTRS(player);
11658
11659                 if (num_of_list == 0) {
11660                         char *original_uri = NULL;
11661
11662                         if (attrs) {
11663                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11664
11665                                 if (!original_uri) {
11666                                         LOGE("there is no original uri.");
11667                                         return MM_ERROR_PLAYER_INVALID_STATE;
11668                                 }
11669
11670                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11671                                 player->uri_info.uri_idx = 0;
11672
11673                                 LOGD("add original path at first : %s(%d)", original_uri);
11674                         }
11675                 }
11676
11677                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11678                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11679         }
11680
11681         MMPLAYER_FLEAVE();
11682         return MM_ERROR_NONE;
11683 }
11684
11685 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11686 {
11687         mm_player_t* player = (mm_player_t*) hplayer;
11688         char *next_uri = NULL;
11689         guint num_of_list = 0;
11690
11691         MMPLAYER_FENTER();
11692         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11693
11694         num_of_list = g_list_length(player->uri_info.uri_list);
11695
11696         if (num_of_list > 0) {
11697                 gint uri_idx = player->uri_info.uri_idx;
11698
11699                 if (uri_idx < num_of_list-1)
11700                         uri_idx++;
11701                 else
11702                         uri_idx = 0;
11703
11704                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11705                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11706
11707                 *uri = g_strdup(next_uri);
11708         }
11709
11710         MMPLAYER_FLEAVE();
11711         return MM_ERROR_NONE;
11712 }
11713
11714 static void
11715 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
11716 GstCaps *caps, gpointer data)
11717 {
11718         mm_player_t* player = (mm_player_t*)data;
11719         const gchar* klass = NULL;
11720         const gchar* mime = NULL;
11721         gchar* caps_str = NULL;
11722
11723         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11724         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11725         caps_str = gst_caps_to_string(caps);
11726
11727         LOGW("unknown type of caps : %s from %s",
11728                                         caps_str, GST_ELEMENT_NAME(elem));
11729
11730         MMPLAYER_FREEIF(caps_str);
11731
11732         /* There is no available codec. */
11733         __mmplayer_check_not_supported_codec(player, klass, mime);
11734 }
11735
11736 static gboolean
11737 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
11738 GstCaps * caps,  gpointer data)
11739 {
11740         mm_player_t* player = (mm_player_t*)data;
11741         const char* mime = NULL;
11742         gboolean ret = TRUE;
11743
11744         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11745         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11746
11747         if (g_str_has_prefix(mime, "audio")) {
11748                 GstStructure* caps_structure = NULL;
11749                 gint samplerate = 0;
11750                 gint channels = 0;
11751                 gchar *caps_str = NULL;
11752
11753                 caps_structure = gst_caps_get_structure(caps, 0);
11754                 gst_structure_get_int(caps_structure, "rate", &samplerate);
11755                 gst_structure_get_int(caps_structure, "channels", &channels);
11756
11757                 if ((channels > 0 && samplerate == 0)) {
11758                         LOGD("exclude audio...");
11759                         ret = FALSE;
11760                 }
11761
11762                 caps_str = gst_caps_to_string(caps);
11763                 /* set it directly because not sent by TAG */
11764                 if (g_strrstr(caps_str, "mobile-xmf"))
11765                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11766                 MMPLAYER_FREEIF(caps_str);
11767         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11768                 MMMessageParamType msg_param;
11769                 memset(&msg_param, 0, sizeof(MMMessageParamType));
11770                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11771                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11772                 LOGD("video file is not supported on this device");
11773                 ret = FALSE;
11774         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11775                 LOGD("already video linked");
11776                 ret = FALSE;
11777         } else {
11778                 LOGD("found new stream");
11779         }
11780
11781         return ret;
11782 }
11783
11784 static gint
11785 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
11786 GstCaps* caps, GstElementFactory* factory, gpointer data)
11787 {
11788         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11789          We are defining our own and will be removed when it actually exposed */
11790         typedef enum {
11791                 GST_AUTOPLUG_SELECT_TRY,
11792                 GST_AUTOPLUG_SELECT_EXPOSE,
11793                 GST_AUTOPLUG_SELECT_SKIP
11794         } GstAutoplugSelectResult;
11795
11796         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11797         mm_player_t* player = (mm_player_t*)data;
11798
11799         gchar* factory_name = NULL;
11800         gchar* caps_str = NULL;
11801         const gchar* klass = NULL;
11802         gint idx = 0;
11803
11804         factory_name = GST_OBJECT_NAME(factory);
11805         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11806         caps_str = gst_caps_to_string(caps);
11807
11808         LOGD("found new element [%s] to link", factory_name);
11809
11810         /* store type string */
11811         if (player->type == NULL) {
11812                 player->type = gst_caps_to_string(caps);
11813                 __mmplayer_update_content_type_info(player);
11814         }
11815
11816         /* filtering exclude keyword */
11817         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11818                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11819                         LOGW("skipping [%s] by exculde keyword [%s]\n",
11820                         factory_name, player->ini.exclude_element_keyword[idx]);
11821
11822                         // NOTE : does we need to check n_value against the number of item selected?
11823                         result = GST_AUTOPLUG_SELECT_SKIP;
11824                         goto DONE;
11825                 }
11826         }
11827
11828         /* exclude webm format */
11829         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11830          * because webm format is not supportable.
11831          * If webm is disabled in "autoplug-continue", there is no state change
11832          * failure or error because the decodebin will expose the pad directly.
11833          * It make MSL invoke _prepare_async_callback.
11834          * So, we need to disable webm format in "autoplug-select" */
11835         if (caps_str && strstr(caps_str, "webm")) {
11836                 LOGW("webm is not supported");
11837                 result = GST_AUTOPLUG_SELECT_SKIP;
11838                 goto DONE;
11839         }
11840
11841         /* check factory class for filtering */
11842         /* NOTE : msl don't need to use image plugins.
11843          * So, those plugins should be skipped for error handling.
11844          */
11845         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11846                 LOGD("skipping [%s] by not required\n", factory_name);
11847                 result = GST_AUTOPLUG_SELECT_SKIP;
11848                 goto DONE;
11849         }
11850
11851         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11852                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11853                 // TO CHECK : subtitle if needed, add subparse exception.
11854                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11855                 result = GST_AUTOPLUG_SELECT_SKIP;
11856                 goto DONE;
11857         }
11858
11859         if (g_strrstr(factory_name, "mpegpsdemux")) {
11860                 LOGD("skipping PS container - not support\n");
11861                 result = GST_AUTOPLUG_SELECT_SKIP;
11862                 goto DONE;
11863         }
11864
11865         if (g_strrstr(factory_name, "mssdemux"))
11866                 player->smooth_streaming = TRUE;
11867
11868         /* check ALP Codec can be used or not */
11869         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11870                 GstStructure* str = NULL;
11871                 gint channels = 0;
11872
11873                 str = gst_caps_get_structure(caps, 0);
11874                 if (str) {
11875                         gst_structure_get_int(str, "channels", &channels);
11876
11877                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11878                         if (player->max_audio_channels < channels)
11879                                 player->max_audio_channels = channels;
11880                 }
11881                 /* set stream information */
11882                 if (!player->audiodec_linked)
11883                         __mmplayer_set_audio_attrs(player, caps);
11884         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11885                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11886                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11887                         /* prepare resource manager for video decoder */
11888                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11889
11890                         if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state) == MM_ERROR_NONE) {
11891                                 /* prepare resource manager for video decoder */
11892                                 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11893                                         if (_mmplayer_resource_manager_prepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], RESOURCE_TYPE_VIDEO_DECODER)
11894                                                 != MM_ERROR_NONE) {
11895                                                 LOGW("could not prepare for video_decoder resource, skip it.");
11896                                                 result = GST_AUTOPLUG_SELECT_SKIP;
11897                                                 goto DONE;
11898                                         }
11899                                 }
11900                         }
11901
11902                         if (_mmplayer_resource_manager_get_state(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER], &resource_state)
11903                                         == MM_ERROR_NONE) {
11904                                 /* acquire resources for video playing */
11905                                 if (resource_state == RESOURCE_STATE_PREPARED) {
11906                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER])
11907                                                         != MM_ERROR_NONE) {
11908                                                 LOGE("could not acquire resources for video decoding\n");
11909                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager[RESOURCE_TYPE_VIDEO_DECODER]);
11910                                                 goto DONE;
11911                                         }
11912                                 }
11913                         }
11914                 }
11915         }
11916
11917         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11918                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11919                 gint stype = 0;
11920                 gint width = 0;
11921                 GstStructure *str = NULL;
11922                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11923
11924                 /* don't make video because of not required */
11925                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11926                         (player->set_mode.media_packet_video_stream == FALSE)) {
11927                         LOGD("no video because it's not required. -> return expose");
11928                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11929                         goto DONE;
11930                 }
11931
11932                 /* get w/h for omx state-tune */
11933                 str = gst_caps_get_structure(caps, 0);
11934                 gst_structure_get_int(str, "width", &width);
11935
11936                 if (width != 0) {
11937                         if (player->v_stream_caps) {
11938                                 gst_caps_unref(player->v_stream_caps);
11939                                 player->v_stream_caps = NULL;
11940                         }
11941
11942                         player->v_stream_caps = gst_caps_copy(caps);
11943                         LOGD("take caps for video state tune");
11944                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11945                 }
11946         }
11947
11948         if (g_strrstr(klass, "Decoder")) {
11949                 const char* mime = NULL;
11950                 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11951
11952                 if (g_str_has_prefix(mime, "video")) {
11953                         // __mmplayer_check_video_zero_cpoy(player, factory);
11954
11955                         player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11956                         player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11957
11958                         player->videodec_linked = 1;
11959                 } else if (g_str_has_prefix(mime, "audio")) {
11960                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11961                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11962
11963                         player->audiodec_linked = 1;
11964                 }
11965         }
11966
11967 DONE:
11968         MMPLAYER_FREEIF(caps_str);
11969
11970         return result;
11971 }
11972
11973
11974 #if 0
11975 static GValueArray*
11976 __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad,
11977 GstCaps * caps,  gpointer data)
11978 {
11979         //mm_player_t* player = (mm_player_t*)data;
11980
11981         LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11982         gst_caps_to_string(caps),
11983         GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11984
11985         return NULL;
11986 }
11987 #endif
11988
11989 static void
11990 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11991 gpointer data)
11992 {
11993         //mm_player_t* player = (mm_player_t*)data;
11994         GstCaps* caps = NULL;
11995
11996         LOGD("[Decodebin2] pad-removed signal\n");
11997
11998         caps = gst_pad_query_caps(new_pad, NULL);
11999         if (caps) {
12000                 gchar* caps_str = NULL;
12001                 caps_str = gst_caps_to_string(caps);
12002
12003                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
12004
12005                 MMPLAYER_FREEIF(caps_str);
12006         }
12007 }
12008
12009 static void
12010 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
12011 {
12012         mm_player_t* player = (mm_player_t*)data;
12013         GstIterator *iter = NULL;
12014         GValue item = { 0, };
12015         GstPad *pad = NULL;
12016         gboolean done = FALSE;
12017         gboolean is_all_drained = TRUE;
12018
12019         MMPLAYER_FENTER();
12020         MMPLAYER_RETURN_IF_FAIL(player);
12021
12022         LOGD("__mmplayer_gst_decode_drained");
12023
12024         if (player->use_deinterleave == TRUE) {
12025                 LOGD("group playing mode.");
12026                 return;
12027         }
12028
12029         if (!MMPLAYER_CMD_TRYLOCK(player)) {
12030                 LOGW("Fail to get cmd lock");
12031                 return;
12032         }
12033
12034         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
12035                 !__mmplayer_verify_next_play_path(player)) {
12036                 LOGD("decoding is finished.");
12037                 __mmplayer_reset_gapless_state(player);
12038                 MMPLAYER_CMD_UNLOCK(player);
12039                 return;
12040         }
12041
12042         player->gapless.reconfigure = TRUE;
12043
12044         /* check decodebin src pads whether they received EOS or not */
12045         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12046
12047         while (!done) {
12048                 switch (gst_iterator_next(iter, &item)) {
12049                 case GST_ITERATOR_OK:
12050                         pad = g_value_get_object(&item);
12051                         if (pad && !GST_PAD_IS_EOS(pad)) {
12052                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
12053                                 is_all_drained = FALSE;
12054                                 break;
12055                         }
12056                         g_value_reset(&item);
12057                         break;
12058                 case GST_ITERATOR_RESYNC:
12059                         gst_iterator_resync(iter);
12060                         break;
12061                 case GST_ITERATOR_ERROR:
12062                 case GST_ITERATOR_DONE:
12063                         done = TRUE;
12064                         break;
12065                 }
12066         }
12067         g_value_unset(&item);
12068         gst_iterator_free(iter);
12069
12070         if (!is_all_drained) {
12071                 LOGD("Wait util the all pads get EOS.");
12072                 MMPLAYER_CMD_UNLOCK(player);
12073                 MMPLAYER_FLEAVE();
12074                 return;
12075         }
12076
12077         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
12078         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
12079
12080         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
12081         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
12082         __mmplayer_deactivate_old_path(player);
12083         MMPLAYER_CMD_UNLOCK(player);
12084
12085         MMPLAYER_FLEAVE();
12086 }
12087
12088 static void
12089 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
12090 {
12091         mm_player_t* player = (mm_player_t*)data;
12092         const gchar* klass = NULL;
12093         gchar* factory_name = NULL;
12094
12095         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12096         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12097
12098         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12099
12100         if (__mmplayer_add_dump_buffer_probe(player, element))
12101                 LOGD("add buffer probe");
12102
12103         //<-
12104         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12105                 gchar* selected = NULL;
12106                 selected = g_strdup(GST_ELEMENT_NAME(element));
12107                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12108         }
12109         //-> temp code
12110
12111         if (g_strrstr(klass, "Parser")) {
12112                 gchar* selected = NULL;
12113
12114                 selected = g_strdup(factory_name);
12115                 player->parsers = g_list_append(player->parsers, selected);
12116         }
12117
12118         if (g_strrstr(klass, "Demuxer/Adaptive")) {
12119                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
12120                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
12121
12122                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
12123                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
12124
12125                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
12126                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
12127                                                 "max-video-width", player->adaptive_info.limit.width,
12128                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
12129
12130         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
12131                 /* FIXIT : first value will be overwritten if there's more
12132                  * than 1 demuxer/parser
12133                  */
12134
12135                 //LOGD("plugged element is demuxer. take it\n");
12136                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12137                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12138
12139                 /*Added for multi audio support */ // Q. del?
12140                 if (g_strrstr(klass, "Demux")) {
12141                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12142                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12143                 }
12144         }
12145
12146         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12147                 int surface_type = 0;
12148
12149                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12150         }
12151
12152         // to support trust-zone only
12153         if (g_strrstr(factory_name, "asfdemux")) {
12154                 LOGD("set file-location %s\n", player->profile.uri);
12155                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12156
12157                 if (player->video_hub_download_mode == TRUE)
12158                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12159         } else if (g_strrstr(factory_name, "legacyh264parse")) {
12160                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12161                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12162         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12163                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12164                         (__mmplayer_is_only_mp3_type(player->type))) {
12165                         LOGD("[mpegaudioparse] set streaming pull mode.");
12166                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12167                 }
12168         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12169                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12170
12171
12172         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12173                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12174                 LOGD("plugged element is multiqueue. take it\n");
12175
12176                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12177                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12178
12179                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12180                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12181                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12182                         __mm_player_streaming_set_multiqueue(player->streamer,
12183                                 element,
12184                                 TRUE,
12185                                 player->ini.http_buffering_time,
12186                                 1.0,
12187                                 player->ini.http_buffering_limit);
12188
12189                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12190                 }
12191         }
12192
12193         return;
12194 }
12195
12196 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12197 {
12198         MMPLAYER_FENTER();
12199         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12200
12201         if (MMPLAYER_IS_STREAMING(player))
12202                 return FALSE;
12203
12204         /* This callback can be set to music player only. */
12205         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12206                 LOGW("audio callback is not supported for video");
12207                 return FALSE;
12208         }
12209
12210         if (player->audio_stream_cb) {
12211                 GstPad *pad = NULL;
12212
12213                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12214
12215                 if (!pad) {
12216                         LOGE("failed to get sink pad from audiosink to probe data\n");
12217                         return FALSE;
12218                 }
12219                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12220                         __mmplayer_audio_stream_probe, player, NULL);
12221
12222                 gst_object_unref(pad);
12223
12224                 pad = NULL;
12225         } else {
12226                 LOGE("There is no audio callback to configure.\n");
12227                 return FALSE;
12228         }
12229
12230         MMPLAYER_FLEAVE();
12231
12232         return TRUE;
12233 }
12234
12235 static void
12236 __mmplayer_init_factories(mm_player_t* player)
12237 {
12238         MMPLAYER_RETURN_IF_FAIL(player);
12239
12240         player->factories = gst_registry_feature_filter(gst_registry_get(),
12241                 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12242         player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12243 }
12244
12245 static void
12246 __mmplayer_release_factories(mm_player_t* player)
12247 {
12248         MMPLAYER_FENTER();
12249         MMPLAYER_RETURN_IF_FAIL(player);
12250
12251         if (player->factories) {
12252                 gst_plugin_feature_list_free(player->factories);
12253                 player->factories = NULL;
12254         }
12255
12256         MMPLAYER_FLEAVE();
12257 }
12258
12259 static void
12260 __mmplayer_release_misc(mm_player_t* player)
12261 {
12262         int i;
12263         gboolean cur_mode = player->set_mode.rich_audio;
12264         MMPLAYER_FENTER();
12265
12266         MMPLAYER_RETURN_IF_FAIL(player);
12267
12268         player->video_stream_cb = NULL;
12269         player->video_stream_cb_user_param = NULL;
12270         player->video_stream_prerolled = FALSE;
12271
12272         player->audio_stream_cb = NULL;
12273         player->audio_stream_render_cb_ex = NULL;
12274         player->audio_stream_cb_user_param = NULL;
12275         player->audio_stream_sink_sync = false;
12276
12277         player->video_stream_changed_cb = NULL;
12278         player->video_stream_changed_cb_user_param = NULL;
12279
12280         player->audio_stream_changed_cb = NULL;
12281         player->audio_stream_changed_cb_user_param = NULL;
12282
12283         player->sent_bos = FALSE;
12284         player->playback_rate = DEFAULT_PLAYBACK_RATE;
12285
12286         player->doing_seek = FALSE;
12287
12288         player->updated_bitrate_count = 0;
12289         player->total_bitrate = 0;
12290         player->updated_maximum_bitrate_count = 0;
12291         player->total_maximum_bitrate = 0;
12292
12293         player->not_found_demuxer = 0;
12294
12295         player->last_position = 0;
12296         player->duration = 0;
12297         player->http_content_size = 0;
12298         player->not_supported_codec = MISSING_PLUGIN_NONE;
12299         player->can_support_codec = FOUND_PLUGIN_NONE;
12300         player->pending_seek.is_pending = FALSE;
12301         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12302         player->pending_seek.pos = 0;
12303         player->msg_posted = FALSE;
12304         player->has_many_types = FALSE;
12305         player->max_audio_channels = 0;
12306         player->video_share_api_delta = 0;
12307         player->video_share_clock_delta = 0;
12308         player->sound_focus.keep_last_pos = FALSE;
12309         player->sound_focus.acquired = FALSE;
12310         player->is_subtitle_force_drop = FALSE;
12311         player->play_subtitle = FALSE;
12312         player->adjust_subtitle_pos = 0;
12313         player->last_multiwin_status = FALSE;
12314         player->has_closed_caption = FALSE;
12315         player->set_mode.media_packet_video_stream = FALSE;
12316         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12317         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12318         /* recover mode */
12319         player->set_mode.rich_audio = cur_mode;
12320
12321         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12322                 player->bitrate[i] = 0;
12323                 player->maximum_bitrate[i] = 0;
12324         }
12325
12326         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12327
12328         /* remove media stream cb(appsrc cb) */
12329         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12330                 player->media_stream_buffer_status_cb[i] = NULL;
12331                 player->media_stream_seek_data_cb[i] = NULL;
12332                 player->buffer_cb_user_param[i] = NULL;
12333                 player->seek_cb_user_param[i] = NULL;
12334         }
12335         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12336
12337         /* free memory related to audio effect */
12338         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12339
12340         if (player->state_tune_caps) {
12341                 gst_caps_unref(player->state_tune_caps);
12342                 player->state_tune_caps = NULL;
12343         }
12344
12345         if (player->adaptive_info.var_list) {
12346                 g_list_free_full(player->adaptive_info.var_list, g_free);
12347                 player->adaptive_info.var_list = NULL;
12348         }
12349
12350         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12351         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12352         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12353
12354         MMPLAYER_FLEAVE();
12355 }
12356
12357 static void
12358 __mmplayer_release_misc_post(mm_player_t* player)
12359 {
12360         char *original_uri = NULL;
12361         MMPLAYER_FENTER();
12362
12363         /* player->pipeline is already released before. */
12364
12365         MMPLAYER_RETURN_IF_FAIL(player);
12366
12367         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12368         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12369
12370         /* clean found parsers */
12371         if (player->parsers) {
12372                 GList *parsers = player->parsers;
12373                 for (; parsers; parsers = g_list_next(parsers)) {
12374                         gchar *name = parsers->data;
12375                         MMPLAYER_FREEIF(name);
12376                 }
12377                 g_list_free(player->parsers);
12378                 player->parsers = NULL;
12379         }
12380
12381         /* clean found audio decoders */
12382         if (player->audio_decoders) {
12383                 GList *a_dec = player->audio_decoders;
12384                 for (; a_dec; a_dec = g_list_next(a_dec)) {
12385                         gchar *name = a_dec->data;
12386                         MMPLAYER_FREEIF(name);
12387                 }
12388                 g_list_free(player->audio_decoders);
12389                 player->audio_decoders = NULL;
12390         }
12391
12392         /* clean the uri list except original uri */
12393         if (player->uri_info.uri_list) {
12394                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12395
12396                 if (player->attrs) {
12397                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12398                         LOGD("restore original uri = %s\n", original_uri);
12399
12400                         if (mmf_attrs_commit(player->attrs))
12401                                 LOGE("failed to commit the original uri.\n");
12402                 }
12403
12404                 GList *uri_list = player->uri_info.uri_list;
12405                 for (; uri_list; uri_list = g_list_next(uri_list)) {
12406                         gchar *uri = uri_list->data;
12407                         MMPLAYER_FREEIF(uri);
12408                 }
12409                 g_list_free(player->uri_info.uri_list);
12410                 player->uri_info.uri_list = NULL;
12411         }
12412
12413         /* clear the audio stream buffer list */
12414         __mmplayer_audio_stream_clear_buffer(player, FALSE);
12415
12416         /* clear the video stream bo list */
12417         __mmplayer_video_stream_destroy_bo_list(player);
12418         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
12419
12420         if (player->profile.mem) {
12421                 free(player->profile.mem);
12422                 player->profile.mem = NULL;
12423                 player->mem_buf.buf = NULL;
12424         }
12425         player->uri_info.uri_idx = 0;
12426         MMPLAYER_FLEAVE();
12427 }
12428
12429 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12430 {
12431         GstElement *element = NULL;
12432         GstPad *sinkpad;
12433
12434         LOGD("creating %s to plug\n", name);
12435
12436         element = gst_element_factory_make(name, NULL);
12437         if (!element) {
12438                 LOGE("failed to create queue\n");
12439                 return NULL;
12440         }
12441
12442         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12443                 LOGE("failed to set state READY to %s\n", name);
12444                 gst_object_unref(element);
12445                 return NULL;
12446         }
12447
12448         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12449                 LOGE("failed to add %s\n", name);
12450                 gst_object_unref(element);
12451                 return NULL;
12452         }
12453
12454         sinkpad = gst_element_get_static_pad(element, "sink");
12455
12456         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12457                 LOGE("failed to link %s\n", name);
12458                 gst_object_unref(sinkpad);
12459                 gst_object_unref(element);
12460                 return NULL;
12461         }
12462
12463         LOGD("linked %s to pipeline successfully\n", name);
12464
12465         gst_object_unref(sinkpad);
12466
12467         return element;
12468 }
12469
12470 static gboolean
12471 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12472 const char *padname, const GList *templlist)
12473 {
12474         GstPad *pad = NULL;
12475         gboolean has_dynamic_pads = FALSE;
12476         gboolean has_many_types = FALSE;
12477         const char *klass = NULL;
12478         GstStaticPadTemplate *padtemplate = NULL;
12479         GstElementFactory *factory = NULL;
12480         GstElement* queue = NULL;
12481         GstElement* parser = NULL;
12482         GstPad *pssrcpad = NULL;
12483         GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12484         MMPlayerGstElement *mainbin = NULL;
12485         GstStructure* str = NULL;
12486         GstCaps* srccaps = NULL;
12487         GstState target_state = GST_STATE_READY;
12488         gboolean isvideo_decoder = FALSE;
12489         guint q_max_size_time = 0;
12490
12491         MMPLAYER_FENTER();
12492
12493         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12494                 player->pipeline &&
12495                 player->pipeline->mainbin,
12496                 FALSE);
12497
12498         mainbin = player->pipeline->mainbin;
12499
12500         LOGD("plugging pad %s:%s to newly create %s:%s\n",
12501                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12502                         GST_PAD_NAME(srcpad),
12503                         GST_ELEMENT_NAME(sinkelement),
12504                         padname);
12505
12506         factory = gst_element_get_factory(sinkelement);
12507         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12508
12509         /* check if player can do start continually */
12510         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12511
12512         /* need it to warm up omx before linking to pipeline */
12513         if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12514                 LOGD("get demux caps.\n");
12515                 if (player->state_tune_caps) {
12516                         gst_caps_unref(player->state_tune_caps);
12517                         player->state_tune_caps = NULL;
12518                 }
12519                 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12520         }
12521
12522         /* NOTE : OMX Codec can check if resource is available or not at this state. */
12523         if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12524                 if (player->state_tune_caps != NULL) {
12525                         LOGD("set demux's caps to omx codec if resource is available");
12526                         if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12527                                 target_state = GST_STATE_PAUSED;
12528                                 isvideo_decoder = TRUE;
12529                                 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12530                         } else
12531                                 LOGW("failed to set caps for state tuning");
12532                 }
12533                 gst_caps_unref(player->state_tune_caps);
12534                 player->state_tune_caps = NULL;
12535         }
12536
12537         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12538                 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12539                 if (isvideo_decoder) {
12540                         gst_element_set_state(sinkelement, GST_STATE_NULL);
12541                         gst_object_unref(G_OBJECT(sinkelement));
12542                         player->keep_detecting_vcodec = TRUE;
12543                 }
12544                 goto ERROR;
12545         }
12546
12547         /* add to pipeline */
12548         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12549                 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12550                 goto ERROR;
12551         }
12552
12553         LOGD("element klass : %s\n", klass);
12554
12555         /* added to support multi track files */
12556         /* only decoder case and any of the video/audio still need to link*/
12557         if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12558                 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12559
12560                 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12561                         gchar *src_demux_caps_str = NULL;
12562                         gchar *needed_parser = NULL;
12563                         GstCaps *src_demux_caps = NULL;
12564                         gboolean smooth_streaming = FALSE;
12565
12566                         src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12567                         src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12568
12569                         gst_caps_unref(src_demux_caps);
12570
12571                         if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12572                                 if (g_strrstr(name, "mssdemux")) {
12573                                         needed_parser = g_strdup("legacyh264parse");
12574                                         smooth_streaming = TRUE;
12575                                 } else
12576                                         needed_parser = g_strdup("h264parse");
12577                         } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12578                                 needed_parser = g_strdup("mpeg4videoparse");
12579
12580                         MMPLAYER_FREEIF(src_demux_caps_str);
12581
12582                         if (needed_parser) {
12583                                 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12584                                 MMPLAYER_FREEIF(needed_parser);
12585
12586                                 if (!parser) {
12587                                         LOGE("failed to create parser\n");
12588                                 } else {
12589                                         if (smooth_streaming)
12590                                                 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12591
12592                                         /* update srcpad if parser is created */
12593                                         pssrcpad = gst_element_get_static_pad(parser, "src");
12594                                         srcpad = pssrcpad;
12595                                 }
12596                         }
12597                 }
12598                 MMPLAYER_FREEIF(name);
12599
12600                 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12601                 if (!queue) {
12602                         LOGE("failed to create queue\n");
12603                         goto ERROR;
12604                 }
12605
12606                 /* update srcpad to link with decoder */
12607                 qsrcpad = gst_element_get_static_pad(queue, "src");
12608                 srcpad = qsrcpad;
12609
12610                 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12611
12612                 /* assigning queue handle for futher manipulation purpose */
12613                 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12614                 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12615                         mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12616                         mainbin[MMPLAYER_M_Q1].gst = queue;
12617
12618                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12619                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12620                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12621                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12622                         } else {
12623                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12624                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12625                         }
12626                 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12627                         mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12628                         mainbin[MMPLAYER_M_Q2].gst = queue;
12629
12630                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12631                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12632                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12633                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12634                         } else {
12635                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12636                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12637                         }
12638                 } else {
12639                         LOGE("Not supporting more then two elementary stream\n");
12640                         g_assert(1);
12641                 }
12642
12643                 pad = gst_element_get_static_pad(sinkelement, padname);
12644
12645                 if (!pad) {
12646                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12647                                 padname, GST_ELEMENT_NAME(sinkelement));
12648
12649                         pad = gst_element_get_static_pad(sinkelement, "sink");
12650                         if (!pad) {
12651                                 LOGE("failed to get pad(sink) from %s. \n",
12652                                 GST_ELEMENT_NAME(sinkelement));
12653                                 goto ERROR;
12654                         }
12655                 }
12656
12657                 /* to check the video/audio type set the proper flag*/
12658                 const gchar *mime_type = NULL;
12659                 srccaps = gst_pad_query_caps(srcpad, NULL);
12660                 if (!srccaps)
12661                         goto ERROR;
12662                 str = gst_caps_get_structure(srccaps, 0);
12663                 if (!str)
12664                         goto ERROR;
12665                 mime_type = gst_structure_get_name(str);
12666                 if (!mime_type)
12667                         goto ERROR;
12668
12669                 /* link queue and decoder. so, it will be queue - decoder. */
12670                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12671                         gst_object_unref(GST_OBJECT(pad));
12672                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12673
12674                         /* reconstitute supportable codec */
12675                         if (strstr(mime_type, "video"))
12676                                 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12677                         else if (strstr(mime_type, "audio"))
12678                                 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12679                         goto ERROR;
12680                 }
12681
12682                 if (strstr(mime_type, "video")) {
12683                         player->videodec_linked = 1;
12684                         LOGI("player->videodec_linked set to 1\n");
12685
12686                 } else if (strstr(mime_type, "audio")) {
12687                         player->audiodec_linked = 1;
12688                         LOGI("player->auddiodec_linked set to 1\n");
12689                 }
12690
12691                 gst_object_unref(GST_OBJECT(pad));
12692                 gst_caps_unref(GST_CAPS(srccaps));
12693                 srccaps = NULL;
12694         }
12695
12696         if (!MMPLAYER_IS_HTTP_PD(player)) {
12697                 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12698                         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12699                                 gint64 dur_bytes = 0L;
12700                                 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12701
12702                                 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12703                                         LOGD("creating http streaming buffering queue\n");
12704
12705                                         queue = gst_element_factory_make("queue2", "queue2");
12706                                         if (!queue) {
12707                                                 LOGE("failed to create buffering queue element\n");
12708                                                 goto ERROR;
12709                                         }
12710
12711                                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12712                                                 LOGE("failed to set state READY to buffering queue\n");
12713                                                 goto ERROR;
12714                                         }
12715
12716                                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12717                                                 LOGE("failed to add buffering queue\n");
12718                                                 goto ERROR;
12719                                         }
12720
12721                                         qsinkpad = gst_element_get_static_pad(queue, "sink");
12722                                         qsrcpad = gst_element_get_static_pad(queue, "src");
12723
12724                                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12725                                                 LOGE("failed to link buffering queue\n");
12726                                                 goto ERROR;
12727                                         }
12728                                         srcpad = qsrcpad;
12729
12730
12731                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12732                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12733
12734                                         if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12735                                                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12736                                                         LOGE("fail to get duration.\n");
12737
12738                                                 if (dur_bytes > 0) {
12739                                                         if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12740                                                                 type = MUXED_BUFFER_TYPE_FILE;
12741                                                         } else {
12742                                                                 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12743                                                                 if (player->streamer)
12744                                                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12745                                                         }
12746                                                 } else {
12747                                                         dur_bytes = 0;
12748                                                 }
12749                                         }
12750
12751                                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
12752                                         if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12753                                                 __mm_player_streaming_set_queue2(player->streamer,
12754                                                         queue,
12755                                                         TRUE,
12756                                                         player->ini.http_max_size_bytes,
12757                                                         player->ini.http_buffering_time,
12758                                                         1.0,
12759                                                         player->ini.http_buffering_limit,
12760                                                         type,
12761                                                         player->http_file_buffering_path,
12762                                                         (guint64)dur_bytes);
12763                                         }
12764                                 }
12765                         }
12766                 }
12767         }
12768         /* if it is not decoder or */
12769         /* in decoder case any of the video/audio still need to link*/
12770         if (!g_strrstr(klass, "Decoder")) {
12771                 pad = gst_element_get_static_pad(sinkelement, padname);
12772                 if (!pad) {
12773                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12774                                         padname, GST_ELEMENT_NAME(sinkelement));
12775
12776                         pad = gst_element_get_static_pad(sinkelement, "sink");
12777
12778                         if (!pad) {
12779                                 LOGE("failed to get pad(sink) from %s. \n",
12780                                         GST_ELEMENT_NAME(sinkelement));
12781                                 goto ERROR;
12782                         }
12783                 }
12784
12785                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12786                         gst_object_unref(GST_OBJECT(pad));
12787                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12788                         goto ERROR;
12789                 }
12790
12791                 gst_object_unref(GST_OBJECT(pad));
12792         }
12793
12794         for (; templlist != NULL; templlist = templlist->next) {
12795                 padtemplate = templlist->data;
12796
12797                 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12798
12799                 if (padtemplate->direction != GST_PAD_SRC ||
12800                         padtemplate->presence == GST_PAD_REQUEST)
12801                         continue;
12802
12803                 switch (padtemplate->presence) {
12804                 case GST_PAD_ALWAYS:
12805                         {
12806                                 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12807                                 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12808
12809                                 /* Check whether caps has many types */
12810                                 if (!gst_caps_is_fixed(caps)) {
12811                                         LOGD("always pad but, caps has many types");
12812                                         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12813                                         has_many_types = TRUE;
12814                                         break;
12815                                 }
12816
12817                                 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12818                                         gst_object_unref(GST_OBJECT(srcpad));
12819                                         gst_caps_unref(GST_CAPS(caps));
12820
12821                                         LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12822                                         goto ERROR;
12823                                 }
12824
12825                                 gst_caps_unref(GST_CAPS(caps));
12826                                 gst_object_unref(GST_OBJECT(srcpad));
12827
12828                         }
12829                         break;
12830
12831
12832                 case GST_PAD_SOMETIMES:
12833                         has_dynamic_pads = TRUE;
12834                         break;
12835
12836                 default:
12837                         break;
12838                 }
12839         }
12840
12841         /* check if player can do start continually */
12842         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12843
12844         if (has_dynamic_pads) {
12845                 player->have_dynamic_pad = TRUE;
12846                 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12847                         G_CALLBACK(__mmplayer_add_new_pad), player);
12848
12849                 /* for streaming, more then one typefind will used for each elementary stream
12850                  * so this doesn't mean the whole pipeline completion
12851                  */
12852                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12853                         MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12854                                 G_CALLBACK(__mmplayer_pipeline_complete), player);
12855                 }
12856         }
12857
12858         if (has_many_types) {
12859                 GstPad *pad = NULL;
12860
12861                 player->has_many_types = has_many_types;
12862
12863                 pad = gst_element_get_static_pad(sinkelement, "src");
12864                 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12865                 gst_object_unref(GST_OBJECT(pad));
12866         }
12867
12868
12869         /* check if player can do start continually */
12870         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12871
12872         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12873                 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12874                 goto ERROR;
12875         }
12876
12877         if (queue) {
12878                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12879                         LOGE("failed to set state PAUSED to queue\n");
12880                         goto ERROR;
12881                 }
12882
12883                 queue = NULL;
12884
12885                 gst_object_unref(GST_OBJECT(qsrcpad));
12886                 qsrcpad = NULL;
12887         }
12888
12889         if (parser) {
12890                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12891                         LOGE("failed to set state PAUSED to queue\n");
12892                         goto ERROR;
12893                 }
12894
12895                 parser = NULL;
12896
12897                 gst_object_unref(GST_OBJECT(pssrcpad));
12898                 pssrcpad = NULL;
12899         }
12900
12901         MMPLAYER_FLEAVE();
12902
12903         return TRUE;
12904
12905 ERROR:
12906
12907         if (queue) {
12908                 gst_object_unref(GST_OBJECT(qsrcpad));
12909
12910                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12911                  * You need to explicitly set elements to the NULL state before
12912                  * dropping the final reference, to allow them to clean up.
12913                  */
12914                 gst_element_set_state(queue, GST_STATE_NULL);
12915                 /* And, it still has a parent "player".
12916                  * You need to let the parent manage the object instead of unreffing the object directly.
12917                  */
12918
12919                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12920                 //gst_object_unref(queue);
12921         }
12922
12923         if (srccaps)
12924                 gst_caps_unref(GST_CAPS(srccaps));
12925
12926         return FALSE;
12927 }
12928
12929 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data)
12930 {
12931         const gchar *klass;
12932
12933         /* we only care about element factories */
12934         if (!GST_IS_ELEMENT_FACTORY(feature))
12935                 return FALSE;
12936
12937         /* only parsers, demuxers and decoders */
12938                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12939
12940         if (g_strrstr(klass, "Demux") == NULL &&
12941                         g_strrstr(klass, "Codec/Decoder") == NULL &&
12942                         g_strrstr(klass, "Depayloader") == NULL &&
12943                         g_strrstr(klass, "Parse") == NULL)
12944                 return FALSE;
12945         return TRUE;
12946 }
12947
12948
12949 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12950 {
12951         mm_player_t* player = (mm_player_t*) data;
12952         GstCaps *caps = NULL;
12953         GstStructure *str = NULL;
12954         const char *name;
12955
12956         MMPLAYER_FENTER();
12957
12958         MMPLAYER_RETURN_IF_FAIL(pad)
12959         MMPLAYER_RETURN_IF_FAIL(unused)
12960         MMPLAYER_RETURN_IF_FAIL(data)
12961
12962         caps = gst_pad_query_caps(pad, NULL);
12963         if (!caps)
12964                 return;
12965
12966         str = gst_caps_get_structure(caps, 0);
12967         if (!str)
12968                 return;
12969
12970         name = gst_structure_get_name(str);
12971         if (!name)
12972                 return;
12973         LOGD("name=%s\n", name);
12974
12975         if (!__mmplayer_try_to_plug(player, pad, caps)) {
12976                 LOGE("failed to autoplug for type(%s)\n", name);
12977                 gst_caps_unref(caps);
12978                 return;
12979         }
12980
12981         gst_caps_unref(caps);
12982
12983         __mmplayer_pipeline_complete(NULL, (gpointer)player);
12984
12985         MMPLAYER_FLEAVE();
12986
12987         return;
12988 }
12989
12990 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12991 {
12992         GstStructure *str;
12993         gint version = 0;
12994         const char *stream_type;
12995         gchar *version_field = NULL;
12996
12997         MMPLAYER_FENTER();
12998
12999         MMPLAYER_RETURN_IF_FAIL(player);
13000         MMPLAYER_RETURN_IF_FAIL(caps);
13001
13002         str = gst_caps_get_structure(caps, 0);
13003         if (!str)
13004                 return;
13005
13006         stream_type = gst_structure_get_name(str);
13007         if (!stream_type)
13008                 return;
13009
13010
13011         /* set unlinked mime type for downloadable codec */
13012         if (g_str_has_prefix(stream_type, "video/")) {
13013                 if (g_str_has_prefix(stream_type, "video/mpeg")) {
13014                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
13015                         version_field = MM_PLAYER_MPEG_VNAME;
13016                 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
13017                         gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
13018                         version_field = MM_PLAYER_WMV_VNAME;
13019
13020                 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
13021                         gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
13022                         version_field = MM_PLAYER_DIVX_VNAME;
13023                 }
13024
13025                 if (version)
13026                         player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13027                 else
13028                         player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
13029         } else if (g_str_has_prefix(stream_type, "audio/")) {
13030                 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
13031                         // mp3 or aac
13032                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
13033                         version_field = MM_PLAYER_MPEG_VNAME;
13034                 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
13035                         gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
13036                         version_field = MM_PLAYER_WMA_VNAME;
13037                 }
13038
13039                 if (version)
13040                         player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13041                 else
13042                         player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
13043         }
13044
13045         MMPLAYER_FLEAVE();
13046 }
13047
13048 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
13049 {
13050         mm_player_t* player = (mm_player_t*) data;
13051         GstCaps *caps = NULL;
13052         GstStructure *str = NULL;
13053         const char *name;
13054
13055         MMPLAYER_FENTER();
13056         MMPLAYER_RETURN_IF_FAIL(player);
13057         MMPLAYER_RETURN_IF_FAIL(pad);
13058
13059         GST_OBJECT_LOCK(pad);
13060         if ((caps = gst_pad_get_current_caps(pad)))
13061                 gst_caps_ref(caps);
13062         GST_OBJECT_UNLOCK(pad);
13063
13064         if (NULL == caps) {
13065                 caps = gst_pad_query_caps(pad, NULL);
13066                 if (!caps) return;
13067         }
13068
13069         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13070
13071         str = gst_caps_get_structure(caps, 0);
13072         if (!str)
13073                 return;
13074
13075         name = gst_structure_get_name(str);
13076         if (!name)
13077                 return;
13078
13079         player->num_dynamic_pad++;
13080         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
13081
13082         /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
13083           *     If want to play it, remove this code.
13084           */
13085         if (g_strrstr(name, "application")) {
13086                 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
13087                         /* If id3/ape tag comes, keep going */
13088                         LOGD("application mime exception : id3/ape tag");
13089                 } else {
13090                         /* Otherwise, we assume that this stream is subtile. */
13091                         LOGD(" application mime type pad is closed.");
13092                         return;
13093                 }
13094         } else if (g_strrstr(name, "audio")) {
13095                 gint samplerate = 0, channels = 0;
13096
13097                 if (player->audiodec_linked) {
13098                         gst_caps_unref(caps);
13099                         LOGD("multi tracks. skip to plug");
13100                         return;
13101                 }
13102
13103                 /* set stream information */
13104                 /* if possible, set it here because the caps is not distrubed by resampler. */
13105                 gst_structure_get_int(str, "rate", &samplerate);
13106                 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
13107
13108                 gst_structure_get_int(str, "channels", &channels);
13109                 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
13110
13111                 LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
13112         } else if (g_strrstr(name, "video")) {
13113                 gint stype;
13114                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
13115
13116                 /* don't make video because of not required */
13117                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
13118                         LOGD("no video because it's not required");
13119                         return;
13120                 }
13121
13122                 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13123         }
13124
13125         if (!__mmplayer_try_to_plug(player, pad, caps)) {
13126                 LOGE("failed to autoplug for type(%s)", name);
13127
13128                 __mmplayer_set_unlinked_mime_type(player, caps);
13129         }
13130
13131         gst_caps_unref(caps);
13132
13133         MMPLAYER_FLEAVE();
13134         return;
13135 }
13136
13137 gboolean
13138 __mmplayer_check_subtitle(mm_player_t* player)
13139 {
13140         MMHandleType attrs = 0;
13141         char *subtitle_uri = NULL;
13142
13143         MMPLAYER_FENTER();
13144
13145         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13146
13147         /* get subtitle attribute */
13148         attrs = MMPLAYER_GET_ATTRS(player);
13149         if (!attrs)
13150                 return FALSE;
13151
13152         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13153         if (!subtitle_uri || !strlen(subtitle_uri))
13154                 return FALSE;
13155
13156         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13157         player->is_external_subtitle_present = TRUE;
13158
13159         MMPLAYER_FLEAVE();
13160
13161         return TRUE;
13162 }
13163
13164 static gboolean
13165 __mmplayer_can_extract_pcm(mm_player_t* player)
13166 {
13167         MMHandleType attrs = 0;
13168         gboolean sound_extraction = FALSE;
13169
13170         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13171
13172         attrs = MMPLAYER_GET_ATTRS(player);
13173         if (!attrs) {
13174                 LOGE("fail to get attributes.");
13175                 return FALSE;
13176         }
13177
13178         /* get sound_extraction property */
13179         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13180
13181         if (!sound_extraction) {
13182                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13183                 return FALSE;
13184         }
13185
13186         return TRUE;
13187 }
13188
13189 static gboolean
13190 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13191 {
13192         LOGD("\n");
13193         MMMessageParamType msg_param;
13194         gchar *msg_src_element = NULL;
13195         GstStructure *s = NULL;
13196         guint error_id = 0;
13197         gchar *error_string = NULL;
13198
13199         MMPLAYER_FENTER();
13200
13201         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13202         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13203
13204         s = malloc(sizeof(GstStructure));
13205         if (s == NULL) {
13206                 LOGE("failed to alloc data.");
13207                 return FALSE;
13208         }
13209
13210         memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13211
13212         if (!gst_structure_get_uint(s, "error_id", &error_id))
13213                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13214
13215         switch (error_id) {
13216         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13217                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13218                 break;
13219         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13220                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13221                 break;
13222         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13223                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13224                 break;
13225         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13226                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13227                 break;
13228         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13229                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13230                 break;
13231         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13232                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13233                 break;
13234         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13235                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13236                 break;
13237         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13238                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13239                 break;
13240         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13241                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13242                 break;
13243         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13244                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13245                 break;
13246         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13247                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13248                 break;
13249         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13250                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13251                 break;
13252         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13253                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13254                 break;
13255         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13256                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13257                 break;
13258         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13259                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13260                 break;
13261         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13262                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13263                 break;
13264         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13265                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13266                 break;
13267         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13268                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13269                 break;
13270         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13271                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13272                 break;
13273         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13274                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13275                 break;
13276         case MMPLAYER_STREAMING_ERROR_GONE:
13277                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13278                 break;
13279         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13280                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13281                 break;
13282         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13283                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13284                 break;
13285         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13286                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13287                 break;
13288         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13289                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13290                 break;
13291         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13292                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13293                 break;
13294         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13295                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13296                 break;
13297         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13298                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13299                 break;
13300         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13301                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13302                 break;
13303         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13304                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13305                 break;
13306         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13307                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13308                 break;
13309         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13310                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13311                 break;
13312         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13313                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13314                 break;
13315         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13316                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13317                 break;
13318         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13319                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13320                 break;
13321         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13322                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13323                 break;
13324         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13325                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13326                 break;
13327         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13328                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13329                 break;
13330         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13331                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13332                 break;
13333         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13334                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13335                 break;
13336         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13337                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13338                 break;
13339         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13340                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13341                 break;
13342         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13343                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13344                 break;
13345         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13346                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13347                 break;
13348         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13349                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13350                 break;
13351         default:
13352                 {
13353                         MMPLAYER_FREEIF(s);
13354                         return MM_ERROR_PLAYER_STREAMING_FAIL;
13355                 }
13356         }
13357
13358         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13359         if (error_string)
13360                 msg_param.data = (void *) error_string;
13361
13362         if (message->src) {
13363                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13364
13365                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
13366                         msg_src_element, msg_param.code, (char*)msg_param.data);
13367         }
13368
13369         /* post error to application */
13370         if (!player->msg_posted) {
13371                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13372
13373                 /* don't post more if one was sent already */
13374                 player->msg_posted = TRUE;
13375         } else
13376                 LOGD("skip error post because it's sent already.\n");
13377
13378         MMPLAYER_FREEIF(s);
13379         MMPLAYER_FLEAVE();
13380         g_free(error_string);
13381
13382         return TRUE;
13383
13384 }
13385
13386 static void
13387 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13388 {
13389         MMPLAYER_RETURN_IF_FAIL(player);
13390
13391
13392         /* post now if delay is zero */
13393         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13394                 LOGD("eos delay is zero. posting EOS now\n");
13395                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13396
13397                 if (player->set_mode.pcm_extraction)
13398                         __mmplayer_cancel_eos_timer(player);
13399
13400                 return;
13401         }
13402
13403         /* cancel if existing */
13404         __mmplayer_cancel_eos_timer(player);
13405
13406         /* init new timeout */
13407         /* NOTE : consider give high priority to this timer */
13408         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13409
13410         player->eos_timer = g_timeout_add(delay_in_ms,
13411                 __mmplayer_eos_timer_cb, player);
13412
13413         player->context.global_default = g_main_context_default();
13414         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13415
13416         /* check timer is valid. if not, send EOS now */
13417         if (player->eos_timer == 0) {
13418                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13419                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13420         }
13421 }
13422
13423 static void
13424 __mmplayer_cancel_eos_timer(mm_player_t* player)
13425 {
13426         MMPLAYER_RETURN_IF_FAIL(player);
13427
13428         if (player->eos_timer) {
13429                 LOGD("cancel eos timer");
13430                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13431                 player->eos_timer = 0;
13432         }
13433
13434         return;
13435 }
13436
13437 static gboolean
13438 __mmplayer_eos_timer_cb(gpointer u_data)
13439 {
13440         mm_player_t* player = NULL;
13441         player = (mm_player_t*) u_data;
13442
13443         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13444
13445         if (player->play_count > 1) {
13446                 gint ret_value = 0;
13447                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13448                 if (ret_value == MM_ERROR_NONE) {
13449                         MMHandleType attrs = 0;
13450                         attrs = MMPLAYER_GET_ATTRS(player);
13451
13452                         /* we successeded to rewind. update play count and then wait for next EOS */
13453                         player->play_count--;
13454
13455                         mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13456                         mmf_attrs_commit(attrs);
13457                 } else {
13458                         LOGE("seeking to 0 failed in repeat play");
13459                 }
13460         } else {
13461                 /* posting eos */
13462                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13463         }
13464
13465         /* we are returning FALSE as we need only one posting */
13466         return FALSE;
13467 }
13468
13469 static gboolean
13470 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13471 {
13472         const gchar* name = NULL;
13473         GstStructure* str = NULL;
13474         GstCaps* srccaps = NULL;
13475
13476         MMPLAYER_FENTER();
13477
13478         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13479         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13480
13481         /* to check any of the decoder(video/audio) need to be linked  to parser*/
13482         srccaps = gst_pad_query_caps(srcpad, NULL);
13483         if (!srccaps)
13484                 goto ERROR;
13485
13486         str = gst_caps_get_structure(srccaps, 0);
13487         if (!str)
13488                 goto ERROR;
13489
13490         name = gst_structure_get_name(str);
13491         if (!name)
13492                 goto ERROR;
13493
13494         if (strstr(name, "video")) {
13495                 if (player->videodec_linked) {
13496                     LOGI("Video decoder already linked\n");
13497                         return FALSE;
13498                 }
13499         }
13500         if (strstr(name, "audio")) {
13501                 if (player->audiodec_linked) {
13502                     LOGI("Audio decoder already linked\n");
13503                         return FALSE;
13504                 }
13505         }
13506
13507         gst_caps_unref(srccaps);
13508
13509         MMPLAYER_FLEAVE();
13510
13511         return TRUE;
13512
13513 ERROR:
13514         if (srccaps)
13515                 gst_caps_unref(srccaps);
13516
13517         return FALSE;
13518 }
13519
13520 static gboolean
13521 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13522 {
13523         const gchar* name = NULL;
13524         GstStructure* str = NULL;
13525         GstCaps* srccaps = NULL;
13526
13527         MMPLAYER_FENTER();
13528
13529         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13530         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13531
13532         /* to check any of the decoder(video/audio) need to be linked   to parser*/
13533         srccaps = gst_pad_query_caps(srcpad, NULL);
13534         if (!srccaps)
13535                 goto ERROR;
13536
13537         str = gst_caps_get_structure(srccaps, 0);
13538         if (!str)
13539                 goto ERROR;
13540
13541         name = gst_structure_get_name(str);
13542         if (!name)
13543                 goto ERROR;
13544
13545         if (strstr(name, "video")) {
13546                 if (player->videosink_linked) {
13547                         LOGI("Video Sink already linked\n");
13548                         return FALSE;
13549                 }
13550         }
13551         if (strstr(name, "audio")) {
13552                 if (player->audiosink_linked) {
13553                         LOGI("Audio Sink already linked\n");
13554                         return FALSE;
13555                 }
13556         }
13557         if (strstr(name, "text")) {
13558                 if (player->textsink_linked) {
13559                         LOGI("Text Sink already linked\n");
13560                         return FALSE;
13561                 }
13562         }
13563
13564         gst_caps_unref(srccaps);
13565
13566         MMPLAYER_FLEAVE();
13567
13568         //return (!player->videosink_linked || !player->audiosink_linked);
13569         return TRUE;
13570
13571 ERROR:
13572         if (srccaps)
13573                 gst_caps_unref(srccaps);
13574
13575         return FALSE;
13576 }
13577
13578
13579 /* sending event to one of sinkelements */
13580 static gboolean
13581 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13582 {
13583         GstEvent * event2 = NULL;
13584         GList *sinks = NULL;
13585         gboolean res = FALSE;
13586         MMPLAYER_FENTER();
13587
13588         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13589         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13590
13591         /* While adding subtitles in live feeds seek is getting called.
13592            Adding defensive check in framework layer.*/
13593         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13594                 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13595                         LOGE ("Should not send seek event during live playback");
13596                         return TRUE;
13597                 }
13598         }
13599
13600         if (player->play_subtitle)
13601                 event2 = gst_event_copy((const GstEvent *)event);
13602
13603         sinks = player->sink_elements;
13604         while (sinks) {
13605                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13606
13607                 if (GST_IS_ELEMENT(sink)) {
13608                         /* keep ref to the event */
13609                         gst_event_ref(event);
13610
13611                         if ((res = gst_element_send_event(sink, event))) {
13612                                 LOGD("sending event[%s] to sink element [%s] success!\n",
13613                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13614
13615                                 /* rtsp case, asyn_done is not called after seek during pause state */
13616                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13617                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13618                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13619                                                         LOGD("RTSP seek completed, after pause state..\n");
13620                                                         player->doing_seek = FALSE;
13621                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13622                                                 }
13623
13624                                         }
13625                                 }
13626
13627                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13628                                         sinks = g_list_next(sinks);
13629                                         continue;
13630                                 } else {
13631                                         break;
13632                                 }
13633                         }
13634
13635                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13636                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13637                 }
13638
13639                 sinks = g_list_next(sinks);
13640         }
13641
13642 #if 0
13643         if (internal_sub)
13644           request pad name = sink0;
13645         else
13646           request pad name = sink1; // external
13647 #endif
13648
13649         /* Note : Textbin is not linked to the video or audio bin.
13650          * It needs to send the event to the text sink seperatelly.
13651          */
13652          if (player->play_subtitle) {
13653                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13654
13655                 if (GST_IS_ELEMENT(text_sink)) {
13656                         /* keep ref to the event */
13657                         gst_event_ref(event2);
13658
13659                         if ((res = gst_element_send_event(text_sink, event2)))
13660                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13661                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13662                         else
13663                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13664                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13665
13666                         gst_event_unref(event2);
13667                 }
13668          }
13669
13670         gst_event_unref(event);
13671
13672         MMPLAYER_FLEAVE();
13673
13674         return res;
13675 }
13676
13677 static void
13678 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13679 {
13680         MMPLAYER_FENTER();
13681
13682         MMPLAYER_RETURN_IF_FAIL(player);
13683         MMPLAYER_RETURN_IF_FAIL(sink);
13684
13685         player->sink_elements =
13686                 g_list_append(player->sink_elements, sink);
13687
13688         MMPLAYER_FLEAVE();
13689 }
13690
13691 static void
13692 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13693 {
13694         MMPLAYER_FENTER();
13695
13696         MMPLAYER_RETURN_IF_FAIL(player);
13697         MMPLAYER_RETURN_IF_FAIL(sink);
13698
13699         player->sink_elements =
13700                         g_list_remove(player->sink_elements, sink);
13701
13702         MMPLAYER_FLEAVE();
13703 }
13704
13705 static gboolean
13706 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13707                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13708                         gint64 cur, GstSeekType stop_type, gint64 stop)
13709 {
13710         GstEvent* event = NULL;
13711         gboolean result = FALSE;
13712
13713         MMPLAYER_FENTER();
13714
13715         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13716
13717         if (player->pipeline && player->pipeline->textbin)
13718                 __mmplayer_drop_subtitle(player, FALSE);
13719
13720         event = gst_event_new_seek(rate, format, flags, cur_type,
13721                 cur, stop_type, stop);
13722
13723         result = __gst_send_event_to_sink(player, event);
13724
13725         MMPLAYER_FLEAVE();
13726
13727         return result;
13728 }
13729
13730 /* NOTE : be careful with calling this api. please refer to below glib comment
13731  * glib comment : Note that there is a bug in GObject that makes this function much
13732  * less useful than it might seem otherwise. Once gobject is disposed, the callback
13733  * will no longer be called, but, the signal handler is not currently disconnected.
13734  * If the instance is itself being freed at the same time than this doesn't matter,
13735  * since the signal will automatically be removed, but if instance persists,
13736  * then the signal handler will leak. You should not remove the signal yourself
13737  * because in a future versions of GObject, the handler will automatically be
13738  * disconnected.
13739  *
13740  * It's possible to work around this problem in a way that will continue to work
13741  * with future versions of GObject by checking that the signal handler is still
13742  * connected before disconnected it:
13743  *
13744  *  if (g_signal_handler_is_connected(instance, id))
13745  *    g_signal_handler_disconnect(instance, id);
13746  */
13747 static void
13748 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13749 {
13750         GList* sig_list = NULL;
13751         MMPlayerSignalItem* item = NULL;
13752
13753         MMPLAYER_FENTER();
13754
13755         MMPLAYER_RETURN_IF_FAIL(player);
13756
13757         LOGD("release signals type : %d", type);
13758
13759         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
13760                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13761                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13762                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13763                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13764                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13765                 return;
13766         }
13767
13768         sig_list = player->signals[type];
13769
13770         for (; sig_list; sig_list = sig_list->next) {
13771                 item = sig_list->data;
13772
13773                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13774                         if (g_signal_handler_is_connected(item->obj, item->sig))
13775                                 g_signal_handler_disconnect(item->obj, item->sig);
13776                 }
13777
13778                 MMPLAYER_FREEIF(item);
13779         }
13780
13781         g_list_free(player->signals[type]);
13782         player->signals[type] = NULL;
13783
13784         MMPLAYER_FLEAVE();
13785
13786         return;
13787 }
13788
13789 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13790 {
13791         mm_player_t* player = 0;
13792         int prev_display_surface_type = 0;
13793         void *prev_display_overlay = NULL;
13794         const gchar *klass = NULL;
13795         gchar *cur_videosink_name = NULL;
13796         int ret = 0;
13797         int i = 0;
13798         int num_of_dec = 2; /* DEC1, DEC2 */
13799
13800         MMPLAYER_FENTER();
13801
13802         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13803         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13804
13805         player = MM_PLAYER_CAST(handle);
13806
13807         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
13808                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13809                 MMPLAYER_FLEAVE();
13810                 return MM_ERROR_INVALID_ARGUMENT;
13811         }
13812
13813         /* load previous attributes */
13814         if (player->attrs) {
13815                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13816                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13817                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13818                 if (prev_display_surface_type == surface_type) {
13819                         LOGD("incoming display surface type is same as previous one, do nothing..");
13820                         MMPLAYER_FLEAVE();
13821                         return MM_ERROR_NONE;
13822                 }
13823         } else {
13824                 LOGE("failed to load attributes");
13825                 MMPLAYER_FLEAVE();
13826                 return MM_ERROR_PLAYER_INTERNAL;
13827         }
13828
13829         /* check videosink element is created */
13830         if (!player->pipeline || !player->pipeline->videobin ||
13831                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13832                 LOGD("videosink element is not yet ready");
13833
13834                 /* videobin is not created yet, so we just set attributes related to display surface */
13835                 LOGD("store display attribute for given surface type(%d)", surface_type);
13836                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13837                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13838                 if (mmf_attrs_commit(player->attrs)) {
13839                         LOGE("failed to commit attribute");
13840                         MMPLAYER_FLEAVE();
13841                         return MM_ERROR_PLAYER_INTERNAL;
13842                 }
13843                 MMPLAYER_FLEAVE();
13844                 return MM_ERROR_NONE;
13845         } else {
13846                 /* get player command status */
13847                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13848                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13849                         MMPLAYER_FLEAVE();
13850                         return MM_ERROR_PLAYER_INVALID_STATE;
13851                 }
13852
13853                 /* surface change */
13854                 for (i = 0 ; i < num_of_dec ; i++) {
13855                         if (player->pipeline->mainbin &&
13856                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13857                                 GstElementFactory *decfactory;
13858                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13859
13860                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13861                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13862                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13863                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13864                                                 if (ret) {
13865                                                         goto ERROR_CASE;
13866                                                 } else {
13867                                                         LOGW("success to changing display surface(%d)", surface_type);
13868                                                         MMPLAYER_FLEAVE();
13869                                                         return MM_ERROR_NONE;
13870                                                 }
13871                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13872                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13873                                                 if (ret) {
13874                                                         goto ERROR_CASE;
13875                                                 } else {
13876                                                         LOGW("success to changing display surface(%d)", surface_type);
13877                                                         MMPLAYER_FLEAVE();
13878                                                         return MM_ERROR_NONE;
13879                                                 }
13880                                         } else {
13881                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13882                                                 ret = MM_ERROR_PLAYER_INTERNAL;
13883                                                 goto ERROR_CASE;
13884                                         }
13885                                 }
13886                         }
13887                 }
13888         }
13889
13890 ERROR_CASE:
13891         /* rollback to previous attributes */
13892         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13893         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13894         if (mmf_attrs_commit(player->attrs)) {
13895                 LOGE("failed to commit attributes to rollback");
13896                 MMPLAYER_FLEAVE();
13897                 return MM_ERROR_PLAYER_INTERNAL;
13898         }
13899         MMPLAYER_FLEAVE();
13900         return ret;
13901 }
13902
13903 /* NOTE : It does not support some use cases, eg using colorspace converter */
13904 int
13905 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13906 {
13907         GstPad *src_pad_dec = NULL;
13908         GstPad *sink_pad_videosink = NULL;
13909         GstPad *sink_pad_videobin = NULL;
13910         GstClock *clock = NULL;
13911         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13912         int ret = MM_ERROR_NONE;
13913         gboolean is_audiobin_created = TRUE;
13914
13915         MMPLAYER_FENTER();
13916
13917         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13918         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13919         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13920
13921         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13922         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13923
13924         /* get information whether if audiobin is created */
13925         if (!player->pipeline->audiobin ||
13926                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13927                 LOGW("audiobin is null, this video content may not have audio data");
13928                 is_audiobin_created = FALSE;
13929         }
13930
13931         /* get current state of player */
13932         previous_state = MMPLAYER_CURRENT_STATE(player);
13933         LOGD("previous state(%d)", previous_state);
13934
13935
13936         /* get src pad of decoder and block it */
13937         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13938         if (!src_pad_dec) {
13939                 LOGE("failed to get src pad from decode in mainbin");
13940                 return MM_ERROR_PLAYER_INTERNAL;
13941         }
13942
13943         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13944                 LOGW("trying to block pad(video)");
13945 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13946                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13947                         NULL, NULL, NULL);
13948                 {
13949                         LOGE("failed to set block pad(video)");
13950                         return MM_ERROR_PLAYER_INTERNAL;
13951                 }
13952                 LOGW("pad is blocked(video)");
13953         } else {
13954                 /* no data flows, so no need to do pad_block */
13955                 if (player->doing_seek)
13956                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
13957
13958                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13959         }
13960
13961         /* remove pad */
13962         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13963                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13964                 LOGE("failed to remove previous ghost_pad for videobin");
13965                 return MM_ERROR_PLAYER_INTERNAL;
13966         }
13967
13968         /* change state of videobin to NULL */
13969         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13970         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13971         if (ret != GST_STATE_CHANGE_SUCCESS) {
13972                 LOGE("failed to change state of videobin to NULL");
13973                 return MM_ERROR_PLAYER_INTERNAL;
13974         }
13975
13976         /* unlink between decoder and videobin and remove previous videosink from videobin */
13977         GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13978         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13979                 LOGE("failed to remove former videosink from videobin");
13980                 return MM_ERROR_PLAYER_INTERNAL;
13981         }
13982
13983         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13984
13985         /* create a new videosink and add it to videobin */
13986         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13987         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13988                 LOGE("failed to create videosink element\n");
13989                 MMPLAYER_FLEAVE();
13990                 return MM_ERROR_PLAYER_INTERNAL;
13991         }
13992         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13993         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13994         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13995
13996         /* save attributes */
13997         if (player->attrs) {
13998                 /* set a new display surface type */
13999                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
14000                 /* set a new diplay overlay */
14001                 switch (surface_type) {
14002                 case MM_DISPLAY_SURFACE_OVERLAY:
14003                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
14004                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14005                         break;
14006                 default:
14007                         LOGE("invalid type(%d) for changing display surface", surface_type);
14008                         MMPLAYER_FLEAVE();
14009                         return MM_ERROR_INVALID_ARGUMENT;
14010                 }
14011                 if (mmf_attrs_commit(player->attrs)) {
14012                         LOGE("failed to commit");
14013                         MMPLAYER_FLEAVE();
14014                         return MM_ERROR_PLAYER_INTERNAL;
14015                 }
14016         } else {
14017                 LOGE("player->attrs is null, failed to save attributes");
14018                 MMPLAYER_FLEAVE();
14019                 return MM_ERROR_PLAYER_INTERNAL;
14020         }
14021
14022         /* update video param */
14023         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
14024                 LOGE("failed to update video param");
14025                 return MM_ERROR_PLAYER_INTERNAL;
14026         }
14027
14028         /* change state of videobin to READY */
14029         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
14030         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
14031         if (ret != GST_STATE_CHANGE_SUCCESS) {
14032                 LOGE("failed to change state of videobin to READY");
14033                 return MM_ERROR_PLAYER_INTERNAL;
14034         }
14035
14036         /* change ghostpad */
14037         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
14038         if (!sink_pad_videosink) {
14039                 LOGE("failed to get sink pad from videosink element");
14040                 return MM_ERROR_PLAYER_INTERNAL;
14041         }
14042         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
14043         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
14044                 LOGE("failed to set active to ghost_pad");
14045                 return MM_ERROR_PLAYER_INTERNAL;
14046         }
14047         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
14048                 LOGE("failed to change ghostpad for videobin");
14049                 return MM_ERROR_PLAYER_INTERNAL;
14050         }
14051         gst_object_unref(sink_pad_videosink);
14052
14053         /* link decoder with videobin */
14054         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
14055         if (!sink_pad_videobin) {
14056                 LOGE("failed to get sink pad from videobin");
14057                 return MM_ERROR_PLAYER_INTERNAL;
14058         }
14059         if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
14060                 LOGE("failed to link");
14061                 return MM_ERROR_PLAYER_INTERNAL;
14062         }
14063         gst_object_unref(sink_pad_videobin);
14064
14065         /* clock setting for a new videosink plugin */
14066         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
14067                         so we set it from audiosink plugin or pipeline(system clock) */
14068         if (!is_audiobin_created) {
14069                 LOGW("audiobin is not created, get clock from pipeline..");
14070                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14071         } else {
14072                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14073         }
14074         if (clock) {
14075                 GstClockTime now;
14076                 GstClockTime base_time;
14077                 LOGD("set the clock to videosink");
14078                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
14079                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14080                 if (clock) {
14081                         LOGD("got clock of videosink");
14082                         now = gst_clock_get_time(clock);
14083                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
14084                         LOGD("at time %" GST_TIME_FORMAT ", base %"
14085                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
14086                 } else {
14087                         LOGE("failed to get clock of videosink after setting clock");
14088                         return MM_ERROR_PLAYER_INTERNAL;
14089                 }
14090         } else
14091                 LOGW("failed to get clock, maybe it is the time before first playing");
14092
14093         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
14094                 /* change state of videobin to PAUSED */
14095                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
14096                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
14097                 if (ret != GST_STATE_CHANGE_FAILURE) {
14098                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
14099                 } else {
14100                         LOGE("failed to change state of videobin to PLAYING");
14101                         return MM_ERROR_PLAYER_INTERNAL;
14102                 }
14103
14104                 /* release blocked and unref src pad of video decoder */
14105                 #if 0
14106                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
14107                         LOGE("failed to set pad blocked FALSE(video)");
14108                         return MM_ERROR_PLAYER_INTERNAL;
14109                 }
14110                 #endif
14111                 LOGW("pad is unblocked(video)");
14112         } else {
14113                 if (player->doing_seek)
14114                         LOGW("not completed seek(%d)", player->doing_seek);
14115                 /* change state of videobin to PAUSED */
14116                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
14117                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
14118                 if (ret != GST_STATE_CHANGE_FAILURE) {
14119                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
14120                 } else {
14121                         LOGE("failed to change state of videobin to PLAYING");
14122                         return MM_ERROR_PLAYER_INTERNAL;
14123                 }
14124
14125                 /* already skipped pad block */
14126                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14127         }
14128
14129         /* do get/set position for new videosink plugin */
14130         {
14131                 unsigned long position = 0;
14132                 gint64 pos_msec = 0;
14133
14134                 LOGD("do get/set position for new videosink plugin");
14135                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14136                         LOGE("failed to get position");
14137                         return MM_ERROR_PLAYER_INTERNAL;
14138                 }
14139 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14140                 /* accurate seek */
14141                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14142                         LOGE("failed to set position");
14143                         return MM_ERROR_PLAYER_INTERNAL;
14144                 }
14145 #else
14146                 /* key unit seek */
14147                 pos_msec = position * G_GINT64_CONSTANT(1000000);
14148                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14149                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14150                                                         GST_SEEK_TYPE_SET, pos_msec,
14151                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14152                 if (!ret) {
14153                         LOGE("failed to set position");
14154                         return MM_ERROR_PLAYER_INTERNAL;
14155                 }
14156 #endif
14157         }
14158
14159         if (src_pad_dec)
14160                 gst_object_unref(src_pad_dec);
14161         LOGD("success to change sink");
14162
14163         MMPLAYER_FLEAVE();
14164
14165         return MM_ERROR_NONE;
14166 }
14167
14168
14169 /* Note : if silent is true, then subtitle would not be displayed. :*/
14170 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14171 {
14172         mm_player_t* player = (mm_player_t*) hplayer;
14173
14174         MMPLAYER_FENTER();
14175
14176         /* check player handle */
14177         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14178
14179         player->set_mode.subtitle_off = silent;
14180
14181         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14182
14183         MMPLAYER_FLEAVE();
14184
14185         return MM_ERROR_NONE;
14186 }
14187
14188 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14189 {
14190         MMPlayerGstElement* mainbin = NULL;
14191         MMPlayerGstElement* textbin = NULL;
14192         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14193         GstState current_state = GST_STATE_VOID_PENDING;
14194         GstState element_state = GST_STATE_VOID_PENDING;
14195         GstState element_pending_state = GST_STATE_VOID_PENDING;
14196         gint64 time = 0;
14197         GstEvent *event = NULL;
14198         int result = MM_ERROR_NONE;
14199
14200         GstClock *curr_clock = NULL;
14201         GstClockTime base_time, start_time, curr_time;
14202
14203
14204         MMPLAYER_FENTER();
14205
14206         /* check player handle */
14207         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
14208                                                                 player->pipeline &&
14209                                                                 player->pipeline->mainbin &&
14210                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14211
14212         mainbin = player->pipeline->mainbin;
14213         textbin = player->pipeline->textbin;
14214
14215         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14216
14217         // sync clock with current pipeline
14218         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14219         curr_time = gst_clock_get_time(curr_clock);
14220
14221         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14222         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14223
14224         LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14225                 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14226
14227         if (current_state > GST_STATE_READY) {
14228                 // sync state with current pipeline
14229                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14230                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14231                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14232
14233                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14234                 if (GST_STATE_CHANGE_FAILURE == ret) {
14235                         LOGE("fail to state change.\n");
14236                         result = MM_ERROR_PLAYER_INTERNAL;
14237                         goto ERROR;
14238                 }
14239         }
14240
14241         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14242         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14243
14244         if (curr_clock) {
14245                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14246                 gst_object_unref(curr_clock);
14247         }
14248
14249         // seek to current position
14250         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14251                 result = MM_ERROR_PLAYER_INVALID_STATE;
14252                 LOGE("gst_element_query_position failed, invalid state\n");
14253                 goto ERROR;
14254         }
14255
14256         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14257         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);
14258         if (event) {
14259                 __gst_send_event_to_sink(player, event);
14260         } else {
14261                 result = MM_ERROR_PLAYER_INTERNAL;
14262                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
14263                 goto ERROR;
14264         }
14265
14266         /* sync state with current pipeline */
14267         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14268         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14269         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14270
14271         return MM_ERROR_NONE;
14272
14273 ERROR:
14274         /* release text pipeline resource */
14275         player->textsink_linked = 0;
14276
14277         /* release signal */
14278         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
14279
14280         /* release textbin with it's childs */
14281         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
14282         MMPLAYER_FREEIF(player->pipeline->textbin);
14283         player->pipeline->textbin = NULL;
14284
14285         /* release subtitle elem */
14286         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
14287         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
14288
14289         return result;
14290 }
14291
14292 static int
14293 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14294 {
14295         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14296         GstState current_state = GST_STATE_VOID_PENDING;
14297
14298         MMHandleType attrs = 0;
14299         MMPlayerGstElement* mainbin = NULL;
14300         MMPlayerGstElement* textbin = NULL;
14301
14302         gchar* subtitle_uri = NULL;
14303         int result = MM_ERROR_NONE;
14304         const gchar *charset = NULL;
14305
14306         MMPLAYER_FENTER();
14307
14308         /* check player handle */
14309         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
14310                                                                 player->pipeline &&
14311                                                                 player->pipeline->mainbin &&
14312                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14313         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14314
14315         mainbin = player->pipeline->mainbin;
14316         textbin = player->pipeline->textbin;
14317
14318         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14319         if (current_state < GST_STATE_READY) {
14320                 result = MM_ERROR_PLAYER_INVALID_STATE;
14321                 LOGE("Pipeline is not in proper state\n");
14322                 goto EXIT;
14323         }
14324
14325         attrs = MMPLAYER_GET_ATTRS(player);
14326         if (!attrs) {
14327                 LOGE("cannot get content attribute\n");
14328                 result = MM_ERROR_PLAYER_INTERNAL;
14329                 goto EXIT;
14330         }
14331
14332         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14333         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14334                 LOGE("subtitle uri is not proper filepath\n");
14335                 result = MM_ERROR_PLAYER_INVALID_URI;
14336                 goto EXIT;
14337         }
14338
14339         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
14340                 LOGE("failed to get storage info of subtitle path");
14341                 result = MM_ERROR_PLAYER_INVALID_URI;
14342                 goto EXIT;
14343         }
14344
14345         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14346         LOGD("new subtitle file path is [%s]\n", filepath);
14347
14348         if (!strcmp(filepath, subtitle_uri)) {
14349                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14350                 goto EXIT;
14351         } else {
14352                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14353                 if (mmf_attrs_commit(player->attrs)) {
14354                         LOGE("failed to commit.\n");
14355                         goto EXIT;
14356                 }
14357         }
14358
14359         //gst_pad_set_blocked_async(src-srcpad, TRUE)
14360
14361         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14362         if (ret != GST_STATE_CHANGE_SUCCESS) {
14363                 LOGE("failed to change state of textbin to READY");
14364                 result = MM_ERROR_PLAYER_INTERNAL;
14365                 goto EXIT;
14366         }
14367
14368         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14369         if (ret != GST_STATE_CHANGE_SUCCESS) {
14370                 LOGE("failed to change state of subparse to READY");
14371                 result = MM_ERROR_PLAYER_INTERNAL;
14372                 goto EXIT;
14373         }
14374
14375         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14376         if (ret != GST_STATE_CHANGE_SUCCESS) {
14377                 LOGE("failed to change state of filesrc to READY");
14378                 result = MM_ERROR_PLAYER_INTERNAL;
14379                 goto EXIT;
14380         }
14381
14382         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
14383
14384         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14385
14386         charset = util_get_charset(filepath);
14387         if (charset) {
14388                 LOGD("detected charset is %s\n", charset);
14389                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14390         }
14391
14392         result = _mmplayer_sync_subtitle_pipeline(player);
14393
14394 EXIT:
14395         MMPLAYER_FLEAVE();
14396         return result;
14397 }
14398
14399 /* API to switch between external subtitles */
14400 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14401 {
14402         int result = MM_ERROR_NONE;
14403         mm_player_t* player = (mm_player_t*)hplayer;
14404         char *path = NULL;
14405
14406         MMPLAYER_FENTER();
14407
14408         /* check player handle */
14409         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14410
14411         /* filepath can be null in idle state */
14412         if (filepath) {
14413                 /* check file path */
14414                 if ((path = strstr(filepath, "file://"))) {
14415                         result = util_exist_file_path(path + 7);
14416                 } else {
14417                         result = util_exist_file_path(filepath);
14418                 }
14419
14420                 if (result != MM_ERROR_NONE) {
14421                         LOGE("invalid subtitle path 0x%X", result);
14422                         return result; /* file not found or permission denied */
14423                 }
14424         }
14425
14426         if (!player->pipeline) {
14427                 /* IDLE state */
14428                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14429                 if (mmf_attrs_commit(player->attrs)) {
14430                         LOGE("failed to commit");       /* subtitle path will not be created */
14431                         return MM_ERROR_PLAYER_INTERNAL;
14432                 }
14433         } else {
14434                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
14435                 /* check filepath */
14436                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14437
14438                 if (!__mmplayer_check_subtitle(player)) {
14439                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14440                         if (mmf_attrs_commit(player->attrs)) {
14441                                 LOGE("failed to commit");
14442                                 return MM_ERROR_PLAYER_INTERNAL;
14443                         }
14444
14445                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
14446                                 LOGE("fail to create text pipeline");
14447                                 return MM_ERROR_PLAYER_INTERNAL;
14448                         }
14449
14450                         result = _mmplayer_sync_subtitle_pipeline(player);
14451                 } else {
14452                         result = __mmplayer_change_external_subtitle_language(player, filepath);
14453                 }
14454
14455                 player->is_external_subtitle_added_now = TRUE;
14456         }
14457
14458         MMPLAYER_FLEAVE();
14459         return result;
14460 }
14461
14462 static int
14463 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14464 {
14465         int result = MM_ERROR_NONE;
14466         gchar* change_pad_name = NULL;
14467         GstPad* sinkpad = NULL;
14468         MMPlayerGstElement* mainbin = NULL;
14469         enum MainElementID elemId = MMPLAYER_M_NUM;
14470         GstCaps* caps = NULL;
14471         gint total_track_num = 0;
14472
14473         MMPLAYER_FENTER();
14474
14475         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14476                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
14477
14478         LOGD("Change Track(%d) to %d\n", type, index);
14479
14480         mainbin = player->pipeline->mainbin;
14481
14482         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14483                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14484         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14485                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14486         } else {
14487                 /* Changing Video Track is not supported. */
14488                 LOGE("Track Type Error\n");
14489                 goto EXIT;
14490         }
14491
14492         if (mainbin[elemId].gst == NULL) {
14493                 result = MM_ERROR_PLAYER_NO_OP;
14494                 LOGD("Req track doesn't exist\n");
14495                 goto EXIT;
14496         }
14497
14498         total_track_num = player->selector[type].total_track_num;
14499         if (total_track_num <= 0) {
14500                 result = MM_ERROR_PLAYER_NO_OP;
14501                 LOGD("Language list is not available \n");
14502                 goto EXIT;
14503         }
14504
14505         if ((index < 0) || (index >= total_track_num)) {
14506                 result = MM_ERROR_INVALID_ARGUMENT;
14507                 LOGD("Not a proper index : %d \n", index);
14508                 goto EXIT;
14509         }
14510
14511         /*To get the new pad from the selector*/
14512         change_pad_name = g_strdup_printf("sink_%u", index);
14513         if (change_pad_name == NULL) {
14514                 result = MM_ERROR_PLAYER_INTERNAL;
14515                 LOGD("Pad does not exists\n");
14516                 goto EXIT;
14517         }
14518
14519         LOGD("new active pad name: %s\n", change_pad_name);
14520
14521         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14522         if (sinkpad == NULL) {
14523                 LOGD("sinkpad is NULL");
14524                 result = MM_ERROR_PLAYER_INTERNAL;
14525                 goto EXIT;
14526         }
14527
14528         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14529         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14530
14531         caps = gst_pad_get_current_caps(sinkpad);
14532         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14533
14534         if (sinkpad)
14535                 gst_object_unref(sinkpad);
14536
14537         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14538                 __mmplayer_set_audio_attrs(player, caps);
14539
14540 EXIT:
14541
14542         MMPLAYER_FREEIF(change_pad_name);
14543         return result;
14544 }
14545
14546 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14547 {
14548         int result = MM_ERROR_NONE;
14549         mm_player_t* player = NULL;
14550         MMPlayerGstElement* mainbin = NULL;
14551
14552         gint current_active_index = 0;
14553
14554         GstState current_state = GST_STATE_VOID_PENDING;
14555         GstEvent* event = NULL;
14556         gint64 time = 0;
14557
14558         MMPLAYER_FENTER();
14559
14560         player = (mm_player_t*)hplayer;
14561         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14562
14563         if (!player->pipeline) {
14564                 LOGE("Track %d pre setting -> %d\n", type, index);
14565
14566                 player->selector[type].active_pad_index = index;
14567                 goto EXIT;
14568         }
14569
14570         mainbin = player->pipeline->mainbin;
14571
14572         current_active_index = player->selector[type].active_pad_index;
14573
14574         /*If index is same as running index no need to change the pad*/
14575         if (current_active_index == index)
14576                 goto EXIT;
14577
14578         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14579                 result = MM_ERROR_PLAYER_INVALID_STATE;
14580                 goto EXIT;
14581         }
14582
14583         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14584         if (current_state < GST_STATE_PAUSED) {
14585                 result = MM_ERROR_PLAYER_INVALID_STATE;
14586                 LOGW("Pipeline not in porper state\n");
14587                 goto EXIT;
14588         }
14589
14590         result = __mmplayer_change_selector_pad(player, type, index);
14591         if (result != MM_ERROR_NONE) {
14592                 LOGE("change selector pad error\n");
14593                 goto EXIT;
14594         }
14595
14596         player->selector[type].active_pad_index = index;
14597
14598         if (current_state == GST_STATE_PLAYING) {
14599                 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);
14600                 if (event) {
14601                         __gst_send_event_to_sink(player, event);
14602                 } else {
14603                         result = MM_ERROR_PLAYER_INTERNAL;
14604                         goto EXIT;
14605                 }
14606         }
14607
14608 EXIT:
14609         return result;
14610 }
14611
14612 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14613 {
14614         mm_player_t* player = (mm_player_t*) hplayer;
14615
14616         MMPLAYER_FENTER();
14617
14618         /* check player handle */
14619         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14620
14621         *silent = player->set_mode.subtitle_off;
14622
14623         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14624
14625         MMPLAYER_FLEAVE();
14626
14627         return MM_ERROR_NONE;
14628 }
14629
14630 gboolean
14631 __is_ms_buff_src(mm_player_t* player)
14632 {
14633         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14634
14635         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14636 }
14637
14638 gboolean
14639 __has_suffix(mm_player_t* player, const gchar* suffix)
14640 {
14641         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14642         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14643
14644         gboolean ret = FALSE;
14645         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14646         gchar* t_suffix = g_ascii_strdown(suffix, -1);
14647
14648         if (g_str_has_suffix(player->profile.uri, suffix))
14649                 ret = TRUE;
14650
14651         MMPLAYER_FREEIF(t_url);
14652         MMPLAYER_FREEIF(t_suffix);
14653
14654         return ret;
14655 }
14656
14657 int
14658 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14659 {
14660         mm_player_t* player = (mm_player_t*) hplayer;
14661
14662         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14663
14664         MMPLAYER_VIDEO_SINK_CHECK(player);
14665
14666         LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14667
14668         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14669
14670         return MM_ERROR_NONE;
14671 }
14672 int
14673 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14674 {
14675
14676         mm_player_t* player = (mm_player_t*) hplayer;
14677         float _level = 0.0;
14678         int _x = 0;
14679         int _y = 0;
14680
14681         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14682
14683         MMPLAYER_VIDEO_SINK_CHECK(player);
14684
14685         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14686
14687         LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14688
14689         *level = _level;
14690         *x = _x;
14691         *y = _y;
14692
14693         return MM_ERROR_NONE;
14694 }
14695
14696 int
14697 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14698 {
14699         mm_player_t* player = (mm_player_t*) hplayer;
14700
14701         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14702
14703         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14704                 MMPLAYER_PRINT_STATE(player);
14705                 LOGE("wrong-state : can't set the download mode to parse");
14706                 return MM_ERROR_PLAYER_INVALID_STATE;
14707         }
14708
14709         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14710         player->video_hub_download_mode = mode;
14711
14712         return MM_ERROR_NONE;
14713 }
14714
14715 int
14716 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14717 {
14718         mm_player_t* player = (mm_player_t*) hplayer;
14719
14720         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14721
14722         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14723         player->sync_handler = enable;
14724
14725         return MM_ERROR_NONE;
14726 }
14727
14728 int
14729 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14730                                         long long clock,
14731                                         long long clock_delta,
14732                                         long long video_time,
14733                                         long long media_clock,
14734                                         long long audio_time)
14735 {
14736         mm_player_t* player = (mm_player_t*) hplayer;
14737         MMPlayerGstElement* mainbin = NULL;
14738         GstClockTime start_time_audio = 0, start_time_video = 0;
14739         GstClockTimeDiff base_time = 0, new_base_time = 0;
14740         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14741         gint64 api_delta = 0;
14742         gint64 position = 0, position_delta = 0;
14743         gint64 adj_base_time = 0;
14744         GstClock *curr_clock = NULL;
14745         GstClockTime curr_time = 0;
14746         gboolean query_ret = TRUE;
14747         int result = MM_ERROR_NONE;
14748
14749         MMPLAYER_FENTER();
14750
14751         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14752         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14753         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14754
14755         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14756
14757         if ((video_time < 0) || (player->doing_seek)) {
14758                 LOGD("skip setting master clock.  %lld", video_time);
14759                 goto EXIT;
14760         }
14761
14762         mainbin = player->pipeline->mainbin;
14763
14764         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14765         curr_time = gst_clock_get_time(curr_clock);
14766
14767         current_state = MMPLAYER_CURRENT_STATE(player);
14768
14769         if (current_state == MM_PLAYER_STATE_PLAYING)
14770                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14771
14772         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14773                 (!query_ret)) {
14774                 position = player->last_position;
14775                 LOGD("query fail. %lld", position);
14776         }
14777
14778         clock *= GST_USECOND;
14779         clock_delta *= GST_USECOND;
14780
14781         api_delta = clock - curr_time;
14782         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14783                 player->video_share_api_delta = api_delta;
14784         else
14785                 clock_delta += (api_delta - player->video_share_api_delta);
14786
14787         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14788                 player->video_share_clock_delta = (gint64)clock_delta;
14789
14790                 position_delta = (position/GST_USECOND) - video_time;
14791                 position_delta *= GST_USECOND;
14792
14793                 adj_base_time = position_delta;
14794                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14795
14796         } else {
14797                 gint64 new_play_time = 0;
14798                 gint64 network_delay = 0;
14799
14800                 video_time *= GST_USECOND;
14801
14802                 network_delay = clock_delta - player->video_share_clock_delta;
14803                 new_play_time = video_time + network_delay;
14804
14805                 adj_base_time = position - new_play_time;
14806
14807                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14808                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14809         }
14810
14811         /* Adjust Current Stream Time with base_time of sink
14812          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14813          * 2. Set new base time
14814          *    if adj_base_time is positive value, the stream time will be decreased.
14815          * 3. If seek event is occurred, the start time will be reset. */
14816         if ((player->pipeline->audiobin) &&
14817                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14818                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14819
14820                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14821                         LOGD("audio sink : gst_element_set_start_time -> NONE");
14822                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14823                 }
14824
14825                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14826         }
14827
14828         if ((player->pipeline->videobin) &&
14829                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14830                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14831
14832                 if (start_time_video != GST_CLOCK_TIME_NONE) {
14833                         LOGD("video sink : gst_element_set_start_time -> NONE");
14834                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14835                 }
14836
14837                 // if videobin exist, get base_time from videobin.
14838                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14839         }
14840
14841         new_base_time = base_time + adj_base_time;
14842
14843         if ((player->pipeline->audiobin) &&
14844                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14845                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14846
14847         if ((player->pipeline->videobin) &&
14848                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14849                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14850
14851 EXIT:
14852         MMPLAYER_FLEAVE();
14853
14854         return result;
14855 }
14856
14857 int
14858 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14859                                         long long *video_time,
14860                                         long long *media_clock,
14861                                         long long *audio_time)
14862 {
14863         mm_player_t* player = (mm_player_t*) hplayer;
14864         MMPlayerGstElement* mainbin = NULL;
14865         GstClock *curr_clock = NULL;
14866         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14867         gint64 position = 0;
14868         gboolean query_ret = TRUE;
14869
14870         MMPLAYER_FENTER();
14871
14872         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14873         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14874         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14875
14876         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14877         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14878         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14879
14880         mainbin = player->pipeline->mainbin;
14881
14882         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14883
14884         current_state = MMPLAYER_CURRENT_STATE(player);
14885
14886         if (current_state != MM_PLAYER_STATE_PAUSED)
14887                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14888
14889         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14890                 (!query_ret))
14891                 position = player->last_position;
14892
14893         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14894
14895         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14896
14897         if (curr_clock)
14898                 gst_object_unref(curr_clock);
14899
14900         MMPLAYER_FLEAVE();
14901
14902         return MM_ERROR_NONE;
14903 }
14904
14905 int
14906 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14907 {
14908         mm_player_t* player = (mm_player_t*) hplayer;
14909         int org_angle = 0;
14910
14911         MMPLAYER_FENTER();
14912
14913         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14914         MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14915
14916         if (player->v_stream_caps) {
14917                 GstStructure *str = NULL;
14918
14919                 str = gst_caps_get_structure(player->v_stream_caps, 0);
14920                 if (!gst_structure_get_int(str, "orientation", &org_angle))
14921                         LOGD("missing 'orientation' field in video caps");
14922         }
14923
14924         LOGD("orientation: %d", org_angle);
14925         *angle = org_angle;
14926
14927         MMPLAYER_FLEAVE();
14928         return MM_ERROR_NONE;
14929 }
14930
14931 static gboolean
14932 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14933 {
14934         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14935         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14936
14937         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14938         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14939
14940         int idx = 0;
14941
14942         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14943                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14944                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14945                         mm_player_dump_t *dump_s;
14946                         dump_s = g_malloc(sizeof(mm_player_dump_t));
14947
14948                         if (dump_s == NULL) {
14949                                 LOGE("malloc fail");
14950                                 return FALSE;
14951                         }
14952
14953                         dump_s->dump_element_file = NULL;
14954                         dump_s->dump_pad = NULL;
14955                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14956
14957                         if (dump_s->dump_pad) {
14958                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14959                                 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]);
14960                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14961                                 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);
14962                                 /* add list for removed buffer probe and close FILE */
14963                                 player->dump_list = g_list_append(player->dump_list, dump_s);
14964                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
14965                                 return TRUE;
14966                         } else {
14967                                 g_free(dump_s);
14968                                 dump_s = NULL;
14969                                 LOGE("failed to get %s sink pad added", factory_name);
14970                         }
14971
14972
14973                 }
14974         }
14975         return FALSE;
14976 }
14977
14978 static GstPadProbeReturn
14979 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
14980 {
14981         FILE *dump_data = (FILE *) u_data;
14982 //      int written = 0;
14983         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14984         GstMapInfo probe_info = GST_MAP_INFO_INIT;
14985
14986         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14987
14988         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14989
14990 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14991
14992         fwrite(probe_info.data, 1, probe_info.size , dump_data);
14993
14994         return GST_PAD_PROBE_OK;
14995 }
14996
14997 static void
14998 __mmplayer_release_dump_list(GList *dump_list)
14999 {
15000         if (dump_list) {
15001                 GList *d_list = dump_list;
15002                 for (; d_list; d_list = g_list_next(d_list)) {
15003                         mm_player_dump_t *dump_s = d_list->data;
15004                         if (dump_s->dump_pad) {
15005                                 if (dump_s->probe_handle_id)
15006                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
15007                         }
15008                         if (dump_s->dump_element_file) {
15009                                 fclose(dump_s->dump_element_file);
15010                                 dump_s->dump_element_file = NULL;
15011                         }
15012                         MMPLAYER_FREEIF(dump_s);
15013                 }
15014                 g_list_free(dump_list);
15015                 dump_list = NULL;
15016         }
15017 }
15018
15019 int
15020 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
15021 {
15022         mm_player_t* player = (mm_player_t*) hplayer;
15023
15024         MMPLAYER_FENTER();
15025
15026         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15027         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
15028
15029         *exist = player->has_closed_caption;
15030
15031         MMPLAYER_FLEAVE();
15032
15033         return MM_ERROR_NONE;
15034 }
15035
15036 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
15037 {
15038         void * ret = NULL
15039         MMPLAYER_FENTER();
15040         /* increase ref count of gst buffer */
15041         if (buffer)
15042                 ret = gst_buffer_ref((GstBuffer *)buffer);
15043
15044         MMPLAYER_FLEAVE();
15045         return ret;
15046 }
15047
15048 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
15049 {
15050         MMPLAYER_FENTER();
15051         if (buffer) {
15052                 gst_buffer_unref((GstBuffer *)buffer);
15053                 buffer = NULL;
15054         }
15055         MMPLAYER_FLEAVE();
15056 }
15057
15058 void
15059 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
15060 {
15061         mm_player_t *player  = (mm_player_t*)user_data;
15062         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15063         guint64 current_level_bytes = 0;
15064
15065         MMPLAYER_RETURN_IF_FAIL(player);
15066
15067         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15068
15069         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
15070         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15071
15072         if (player->media_stream_buffer_status_cb[type])
15073                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15074         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15075
15076 }
15077
15078 void
15079 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15080 {
15081         mm_player_t *player  = (mm_player_t*)user_data;
15082         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15083         guint64 current_level_bytes = 0;
15084
15085         MMPLAYER_RETURN_IF_FAIL(player);
15086
15087         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15088
15089         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15090
15091         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15092         if (player->media_stream_buffer_status_cb[type])
15093                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15094         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15095 }
15096
15097 void
15098 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15099 {
15100         mm_player_t *player  = (mm_player_t*)user_data;
15101         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15102         guint64 current_level_bytes = 0;
15103
15104         MMPLAYER_RETURN_IF_FAIL(player);
15105
15106         LOGI("app-src: feed subtitle\n");
15107
15108         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15109
15110         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15111         if (player->media_stream_buffer_status_cb[type])
15112                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
15113
15114         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15115 }
15116
15117 void
15118 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15119 {
15120         mm_player_t *player  = (mm_player_t*)user_data;
15121         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15122         guint64 current_level_bytes = 0;
15123
15124         MMPLAYER_RETURN_IF_FAIL(player);
15125
15126         LOGI("app-src: audio buffer is full.\n");
15127
15128         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15129
15130         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15131
15132         if (player->media_stream_buffer_status_cb[type])
15133                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
15134
15135         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15136 }
15137
15138 void
15139 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15140 {
15141         mm_player_t *player  = (mm_player_t*)user_data;
15142         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15143         guint64 current_level_bytes = 0;
15144
15145         MMPLAYER_RETURN_IF_FAIL(player);
15146
15147         LOGI("app-src: video buffer is full.\n");
15148
15149         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15150
15151         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15152         if (player->media_stream_buffer_status_cb[type])
15153                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
15154
15155         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15156 }
15157
15158 gboolean
15159 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15160 {
15161         mm_player_t *player  = (mm_player_t*)user_data;
15162         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15163
15164         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15165
15166         LOGD("app-src: seek audio data %llu\n", position);
15167         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15168
15169         if (player->media_stream_seek_data_cb[type])
15170                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15171         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15172
15173         return TRUE;
15174 }
15175
15176 gboolean
15177 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15178 {
15179         mm_player_t *player  = (mm_player_t*)user_data;
15180         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15181
15182         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15183
15184         LOGD("app-src: seek video data %llu\n", position);
15185         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15186         if (player->media_stream_seek_data_cb[type])
15187                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15188         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15189
15190         return TRUE;
15191 }
15192
15193 gboolean
15194 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15195 {
15196         mm_player_t *player  = (mm_player_t*)user_data;
15197         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15198
15199         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15200
15201         LOGD("app-src: seek subtitle data\n");
15202         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15203
15204         if (player->media_stream_seek_data_cb[type])
15205                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
15206         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15207
15208         return TRUE;
15209 }
15210
15211 int
15212 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15213 {
15214         mm_player_t* player = (mm_player_t*) hplayer;
15215
15216         MMPLAYER_FENTER();
15217
15218         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15219
15220         player->pcm_samplerate = samplerate;
15221         player->pcm_channel = channel;
15222
15223         MMPLAYER_FLEAVE();
15224         return MM_ERROR_NONE;
15225 }
15226
15227 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15228 {
15229         mm_player_t* player = (mm_player_t*) hplayer;
15230
15231         MMPLAYER_FENTER();
15232
15233         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15234         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15235
15236         if (MMPLAYER_IS_STREAMING(player))
15237                 *timeout = player->ini.live_state_change_timeout;
15238         else
15239                 *timeout = player->ini.localplayback_state_change_timeout;
15240
15241         LOGD("timeout = %d\n", *timeout);
15242
15243         MMPLAYER_FLEAVE();
15244         return MM_ERROR_NONE;
15245 }
15246
15247 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15248 {
15249         mm_player_t* player = (mm_player_t*) hplayer;
15250
15251         MMPLAYER_FENTER();
15252
15253         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15254         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15255
15256         *num = player->video_num_buffers;
15257         *extra_num = player->video_extra_num_buffers;
15258
15259         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15260
15261         MMPLAYER_FLEAVE();
15262         return MM_ERROR_NONE;
15263 }
15264
15265 static void
15266 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
15267 {
15268         int i = 0;
15269         MMPLAYER_FENTER();
15270         MMPLAYER_RETURN_IF_FAIL(player);
15271
15272         for (i=0; i<MMPLAYER_PATH_MAX; i++) {
15273
15274                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
15275                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
15276                         player->storage_info[i].state = STORAGE_STATE_MOUNTED;
15277                         player->storage_info[i].id = -1;
15278
15279                         if (path_type != MMPLAYER_PATH_MAX)
15280                                 break;
15281                 }
15282         }
15283
15284         MMPLAYER_FLEAVE();
15285 }
15286
15287 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int state)
15288 {
15289         int ret = MM_ERROR_NONE;
15290         mm_player_t* player = (mm_player_t*) hplayer;
15291         MMMessageParamType msg_param = {0, };
15292
15293         MMPLAYER_FENTER();
15294         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15295
15296         LOGD("storage state : %d", state);
15297
15298         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
15299                 return MM_ERROR_NONE;
15300
15301         if ((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) ||
15302                 (player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)) {
15303                 LOGW("external storage is removed.");
15304
15305                 if (player->msg_posted == FALSE) {
15306                         memset(&msg_param, 0, sizeof(MMMessageParamType));
15307                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
15308                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
15309                         player->msg_posted = TRUE;
15310                 }
15311
15312                 /* unrealize the player */
15313                 ret = _mmplayer_unrealize(hplayer);
15314                 if (ret != MM_ERROR_NONE)
15315                         LOGE("failed to unrealize");
15316         }
15317
15318         MMPLAYER_FLEAVE();
15319         return ret;
15320 }
15321
15322 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
15323 {
15324         int ret = MM_ERROR_NONE;
15325         mm_player_t* player = (mm_player_t*) hplayer;
15326         int idx = 0, total = 0;
15327         gchar *result = NULL, *tmp = NULL;
15328
15329         MMPLAYER_FENTER();
15330         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15331         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
15332
15333         total = *num = g_list_length(player->adaptive_info.var_list);
15334         if (total <= 0) {
15335                 LOGW("There is no stream variant info.");
15336                 return ret;
15337         }
15338
15339         result = g_strdup ("");
15340         for (idx = 0 ; idx < total ; idx++) {
15341                 VariantData *v_data = NULL;
15342                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
15343
15344                 if (v_data) {
15345                         gchar data[64]={0};
15346                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
15347
15348                         tmp = g_strconcat (result, data, NULL);
15349                         g_free (result);
15350                         result = tmp;
15351                 } else {
15352                         LOGW("There is no variant data in %d", idx);
15353                         (*num)--;
15354                 }
15355         }
15356
15357         *var_info = (char *)result;
15358
15359         LOGD("variant info %d:%s", *num, *var_info);
15360         MMPLAYER_FLEAVE();
15361         return ret;
15362 }
15363
15364 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
15365 {
15366         int ret = MM_ERROR_NONE;
15367         mm_player_t* player = (mm_player_t*) hplayer;
15368
15369         MMPLAYER_FENTER();
15370         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15371
15372         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
15373
15374         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(bandwidth):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15375         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(width):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15376         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE)?(height):(ADAPTIVE_VARIANT_DEFAULT_VALUE);
15377
15378         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
15379                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
15380                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
15381                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
15382
15383                 /* FIXME: seek to current position for applying new variant limitation */
15384         }
15385
15386         MMPLAYER_FLEAVE();
15387         return ret;
15388
15389 }
15390
15391 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
15392 {
15393         int ret = MM_ERROR_NONE;
15394         mm_player_t* player = (mm_player_t*) hplayer;
15395
15396         MMPLAYER_FENTER();
15397         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15398         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
15399
15400         *bandwidth = player->adaptive_info.limit.bandwidth;
15401         *width = player->adaptive_info.limit.width;
15402         *height = player->adaptive_info.limit.height;
15403
15404         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
15405
15406         MMPLAYER_FLEAVE();
15407         return ret;
15408 }