2403fdf920f93a3631be4f1175489c390cc846e0
[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/wayland/wayland.h>
33 #include <gst/audio/gstaudiobasesink.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <sys/time.h>
38 #include <stdlib.h>
39 #include <dlog.h>
40
41 #include <mm_error.h>
42 #include <mm_attrs.h>
43 #include <mm_attrs_private.h>
44 #include <mm_sound.h>
45 #include <mm_sound_focus.h>
46
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
53
54 #include <system_info.h>
55
56 /*===========================================================================================
57 |                                                                                                                                                                                       |
58 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
59 |                                                                                                                                                                                       |
60 ========================================================================================== */
61
62 /*---------------------------------------------------------------------------
63 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
64 ---------------------------------------------------------------------------*/
65
66 /*---------------------------------------------------------------------------
67 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
68 ---------------------------------------------------------------------------*/
69
70 /*---------------------------------------------------------------------------
71 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
72 ---------------------------------------------------------------------------*/
73
74 /*---------------------------------------------------------------------------
75 |    LOCAL #defines:                                                                                                            |
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
79
80 #define MM_VOLUME_FACTOR_DEFAULT                1.0
81 #define MM_VOLUME_FACTOR_MIN                    0
82 #define MM_VOLUME_FACTOR_MAX                    1.0
83
84 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  700000 // 700 msec
85
86 #define MM_PLAYER_MPEG_VNAME                    "mpegversion"
87 #define MM_PLAYER_DIVX_VNAME                    "divxversion"
88 #define MM_PLAYER_WMV_VNAME                             "wmvversion"
89 #define MM_PLAYER_WMA_VNAME                             "wmaversion"
90
91 #define DEFAULT_PLAYBACK_RATE                   1.0
92 #define PLAYBACK_RATE_EX_AUDIO_MIN              0.5
93 #define PLAYBACK_RATE_EX_AUDIO_MAX              2.0
94 #define PLAYBACK_RATE_EX_VIDEO_MIN              0.5
95 #define PLAYBACK_RATE_EX_VIDEO_MAX              1.5
96 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
97
98 #define GST_QUEUE_DEFAULT_TIME                  4
99 #define GST_QUEUE_HLS_TIME                              8
100
101 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
102         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
103         (player->ini.http_use_file_buffer) && \
104         (player->http_file_buffering_path) && \
105         (strlen(player->http_file_buffering_path) > 0))
106 #define MM_PLAYER_NAME  "mmplayer"
107
108 #define PLAYER_DISPLAY_MODE_DST_ROI             5
109
110 /*---------------------------------------------------------------------------
111 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
112 ---------------------------------------------------------------------------*/
113
114 /*---------------------------------------------------------------------------
115 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
116 ---------------------------------------------------------------------------*/
117
118 /*---------------------------------------------------------------------------
119 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
120 ---------------------------------------------------------------------------*/
121
122 /*---------------------------------------------------------------------------
123 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
124 ---------------------------------------------------------------------------*/
125
126 /*---------------------------------------------------------------------------
127 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
128 ---------------------------------------------------------------------------*/
129 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
131 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
132 static int              __mmplayer_gst_create_subtitle_src(mm_player_t* player);
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_element_link_bucket(GList* element_bucket);
136
137 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
138 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
139 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
140 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
141 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
142 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
143 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
144 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
148 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
149 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
150
151 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
152 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157 //static void   __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
158
159 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
160 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
161 static void             __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
162
163 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
164 //static void    __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
165 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
166 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
167 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168
169
170 static void             __mmplayer_init_factories(mm_player_t* player);
171 static void             __mmplayer_release_factories(mm_player_t* player);
172 static void             __mmplayer_release_misc(mm_player_t* player);
173 static void             __mmplayer_release_misc_post(mm_player_t* player);
174 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
175 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
176 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
177
178 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
179 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
180
181 int             __mmplayer_switch_audio_sink(mm_player_t* player);
182 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
183 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
184 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
185 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
186 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
187 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
188
189 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
190 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
191 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
192 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
193 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
194 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
195 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
196 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
197 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
198 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
199 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
200 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
201 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
202 static gpointer __mmplayer_next_play_thread(gpointer data);
203 static gpointer __mmplayer_repeat_thread(gpointer data);
204 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
205
206
207 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
208 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
209 static void __mmplayer_release_dump_list(GList *dump_list);
210
211 static int              __gst_realize(mm_player_t* player);
212 static int              __gst_unrealize(mm_player_t* player);
213 static int              __gst_start(mm_player_t* player);
214 static int              __gst_stop(mm_player_t* player);
215 static int              __gst_pause(mm_player_t* player, gboolean async);
216 static int              __gst_resume(mm_player_t* player, gboolean async);
217 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
218                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
219                                         gint64 cur, GstSeekType stop_type, gint64 stop);
220 static int __gst_pending_seek(mm_player_t* player);
221
222 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
223 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
224 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
225 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
226 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
227
228 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
229
230 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
231 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
232
233 /*fadeout */
234 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
235 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
236
237 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
238 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
239
240 /* util */
241 static gboolean __is_ms_buff_src(mm_player_t* player);
242 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
243
244 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
245 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
246 static int __mmplayer_start_streaming_ext(mm_player_t *player);
247 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
248 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
249
250 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
251 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
252 static void __mmplayer_check_pipeline(mm_player_t* player);
253 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
254 static void __mmplayer_deactivate_old_path(mm_player_t *player);
255 #if 0 // We'll need this in future.
256 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
257 #endif
258
259 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
260 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
261
262 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
263 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
264 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
265 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
266 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
267 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
268 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
269 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
270 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
271 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
272 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
273 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
274 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
275
276 /*===========================================================================================
277 |                                                                                                                                                                                       |
278 |  FUNCTION DEFINITIONS                                                                                                                                         |
279 |                                                                                                                                                                                       |
280 ========================================================================================== */
281
282 #if 0 //debug
283 static void
284 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
285 {
286         gint i, count;
287
288         count = gst_tag_list_get_tag_size(list, tag);
289
290         LOGD("count = %d", count);
291
292         for (i = 0; i < count; i++) {
293                 gchar *str;
294
295                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
296                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
297                                 g_assert_not_reached();
298                 } else
299                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
300
301                 if (i == 0)
302                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
303                 else
304                         g_print("                 : %s\n", str);
305
306                 g_free(str);
307         }
308 }
309 #endif
310
311 /* This function should be called after the pipeline goes PAUSED or higher
312 state. */
313 gboolean
314 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
315 {
316         static gboolean has_duration = FALSE;
317         static gboolean has_video_attrs = FALSE;
318         static gboolean has_audio_attrs = FALSE;
319         static gboolean has_bitrate = FALSE;
320         gboolean missing_only = FALSE;
321         gboolean all = FALSE;
322         gint64 dur_nsec = 0;
323         GstStructure* p = NULL;
324         MMHandleType attrs = 0;
325         gchar *path = NULL;
326         gint stream_service_type = STREAMING_SERVICE_NONE;
327         struct stat sb;
328
329         MMPLAYER_FENTER();
330
331         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
332
333         /* check player state here */
334         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
335                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
336                 /* give warning now only */
337                 LOGW("be careful. content attributes may not available in this state ");
338         }
339
340         /* get content attribute first */
341         attrs = MMPLAYER_GET_ATTRS(player);
342         if (!attrs) {
343                 LOGE("cannot get content attribute");
344                 return FALSE;
345         }
346
347         /* get update flag */
348
349         if (flag & ATTR_MISSING_ONLY) {
350                 missing_only = TRUE;
351                 LOGD("updating missed attr only");
352         }
353
354         if (flag & ATTR_ALL) {
355                 all = TRUE;
356                 has_duration = FALSE;
357                 has_video_attrs = FALSE;
358                 has_audio_attrs = FALSE;
359                 has_bitrate = FALSE;
360
361                 LOGD("updating all attrs");
362         }
363
364         if (missing_only && all) {
365                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
366                 missing_only = FALSE;
367         }
368
369         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
370                 LOGD("try to update duration");
371                 has_duration = FALSE;
372
373                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
374                         player->duration = dur_nsec;
375                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
376                 }
377
378                 if (player->duration < 0) {
379                         LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
380                         player->duration = 0;
381                 }
382
383                 /* try to get streaming service type */
384                 stream_service_type = __mmplayer_get_stream_service_type(player);
385                 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
386
387                 /* check duration is OK */
388                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
389                         /* FIXIT : find another way to get duration here. */
390                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
391                 } else {
392                         /*update duration */
393                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
394                         has_duration = TRUE;
395                 }
396         }
397
398         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
399                 /* update audio params
400                 NOTE : We need original audio params and it can be only obtained from src pad of audio
401                 decoder. Below code only valid when we are not using 'resampler' just before
402                 'audioconverter'. */
403
404                 LOGD("try to update audio attrs");
405                 has_audio_attrs = FALSE;
406
407                 if (player->pipeline->audiobin &&
408                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
409                         GstCaps *caps_a = NULL;
410                         GstPad* pad = NULL;
411                         gint samplerate = 0, channels = 0;
412
413                         pad = gst_element_get_static_pad(
414                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
415
416                         if (pad) {
417                                 caps_a = gst_pad_get_current_caps(pad);
418
419                                 if (caps_a) {
420                                         p = gst_caps_get_structure(caps_a, 0);
421
422                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
423
424                                         gst_structure_get_int(p, "rate", &samplerate);
425                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
426
427                                         gst_structure_get_int(p, "channels", &channels);
428                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
429
430                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
431
432                                         gst_caps_unref(caps_a);
433                                         caps_a = NULL;
434
435                                         has_audio_attrs = TRUE;
436                                 } else
437                                         LOGW("not ready to get audio caps");
438
439                                 gst_object_unref(pad);
440                         } else
441                                 LOGW("failed to get pad from audiosink");
442                 }
443         }
444
445         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
446                 LOGD("try to update video attrs");
447                 has_video_attrs = FALSE;
448
449                 if (player->pipeline->videobin &&
450                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
451                         GstCaps *caps_v = NULL;
452                         GstPad* pad = NULL;
453                         gint tmpNu, tmpDe;
454                         gint width, height;
455
456                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
457                         if (pad) {
458                                 caps_v = gst_pad_get_current_caps(pad);
459
460                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
461                                 if (!caps_v && player->v_stream_caps) {
462                                         caps_v = player->v_stream_caps;
463                                         gst_caps_ref(caps_v);
464                                 }
465
466                                 if (caps_v) {
467                                         p = gst_caps_get_structure(caps_v, 0);
468                                         gst_structure_get_int(p, "width", &width);
469                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
470
471                                         gst_structure_get_int(p, "height", &height);
472                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
473
474                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
475
476                                         SECURE_LOGD("width : %d     height : %d", width, height);
477
478                                         gst_caps_unref(caps_v);
479                                         caps_v = NULL;
480
481                                         if (tmpDe > 0) {
482                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
483                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
484                                         }
485
486                                         has_video_attrs = TRUE;
487                                 } else
488                                         LOGD("no negitiated caps from videosink");
489                                 gst_object_unref(pad);
490                                 pad = NULL;
491                         } else
492                                 LOGD("no videosink sink pad");
493                 }
494         }
495
496
497         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
498                 has_bitrate = FALSE;
499
500                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
501                 if (player->duration) {
502                         guint64 data_size = 0;
503
504                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
505                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
506
507                                 if (stat(path, &sb) == 0)
508                                         data_size = (guint64)sb.st_size;
509                         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
510                                 data_size = player->http_content_size;
511                         LOGD("try to update bitrate : data_size = %lld", data_size);
512
513                         if (data_size) {
514                                 guint64 bitrate = 0;
515                                 guint64 msec_dur = 0;
516
517                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
518                                 bitrate = data_size * 8 * 1000 / msec_dur;
519                                 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
520                                 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
521
522                                 has_bitrate = TRUE;
523                         }
524
525                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
526                                 if (player->total_bitrate) {
527                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
528                                         has_bitrate = TRUE;
529                                 }
530                         }
531                 }
532         }
533
534         /* validate all */
535         if (mmf_attrs_commit(attrs)) {
536                 LOGE("failed to update attributes\n");
537                 return FALSE;
538         }
539
540         MMPLAYER_FLEAVE();
541
542         return TRUE;
543 }
544
545 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
546 {
547         gint streaming_type = STREAMING_SERVICE_NONE;
548
549         MMPLAYER_FENTER();
550
551         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
552                         player->pipeline &&
553                         player->pipeline->mainbin &&
554                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
555                         FALSE);
556
557         /* streaming service type if streaming */
558         if (!MMPLAYER_IS_STREAMING(player))
559                 return STREAMING_SERVICE_NONE;
560
561         if (MMPLAYER_IS_HTTP_STREAMING(player))
562                 streaming_type = (player->duration == 0) ?
563                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
564
565         switch (streaming_type) {
566         case STREAMING_SERVICE_LIVE:
567                 LOGD("it's live streaming");
568                 break;
569         case STREAMING_SERVICE_VOD:
570                 LOGD("it's vod streaming");
571                 break;
572         default:
573                 LOGE("should not get here");
574         }
575
576         player->streaming_type = streaming_type;
577         MMPLAYER_FLEAVE();
578
579         return streaming_type;
580 }
581
582
583 /* this function sets the player state and also report
584  * it to applicaton by calling callback function
585  */
586 int
587 __mmplayer_set_state(mm_player_t* player, int state) // @
588 {
589         MMMessageParamType msg = {0, };
590         int sound_result = MM_ERROR_NONE;
591         gboolean post_bos = FALSE;
592         gboolean interrupted_by_focus = FALSE;
593         gboolean interrupted_by_resource = FALSE;
594         int ret = MM_ERROR_NONE;
595
596         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
597
598         if (MMPLAYER_CURRENT_STATE(player) == state) {
599                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
600                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
601                 return ret;
602         }
603
604         /* update player states */
605         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
606         MMPLAYER_CURRENT_STATE(player) = state;
607
608         /* FIXIT : it's better to do like below code
609         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
610                         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
611         and add more code to handling PENDING_STATE.
612         */
613         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
614                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
615
616         /* print state */
617         MMPLAYER_PRINT_STATE(player);
618
619         /* do some FSM stuffs before posting new state to application  */
620         interrupted_by_focus = player->sound_focus.by_asm_cb;
621         interrupted_by_resource = player->resource_manager.by_rm_cb;
622
623         switch (MMPLAYER_CURRENT_STATE(player)) {
624         case MM_PLAYER_STATE_NULL:
625         case MM_PLAYER_STATE_READY:
626                 {
627                         if (player->cmd == MMPLAYER_COMMAND_STOP) {
628                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
629                                 if (sound_result != MM_ERROR_NONE) {
630                                         LOGE("failed to release sound focus\n");
631                                         return MM_ERROR_POLICY_INTERNAL;
632                                 }
633                         }
634                 }
635                 break;
636
637         case MM_PLAYER_STATE_PAUSED:
638                 {
639                          if (!player->sent_bos) {
640                                 int found = 0;
641                                 #define MMPLAYER_MAX_SOUND_PRIORITY     3
642
643                                 /* rtsp case, get content attrs by GstMessage */
644                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
645                                         /* it's first time to update all content attrs. */
646                                         _mmplayer_update_content_attrs( player, ATTR_ALL );
647                                 }
648
649                                 /* set max sound priority to keep own sound and not to mute other's one */
650                                 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
651                                 if (found) {
652                                         mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
653                                         if (found) {
654                                                 LOGD("set max audio priority");
655                                                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
656                                         }
657                                 }
658
659                          }
660
661                         /* add audio callback probe if condition is satisfied */
662                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
663                                 __mmplayer_configure_audio_callback(player);
664                                 /* FIXIT : handle return value */
665
666                         if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
667                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
668                                 if (sound_result != MM_ERROR_NONE) {
669                                         LOGE("failed to release sound focus\n");
670                                         return MM_ERROR_POLICY_INTERNAL;
671                                 }
672                         }
673                 }
674                 break;
675
676         case MM_PLAYER_STATE_PLAYING:
677                 {
678                         /* try to get content metadata */
679                         if (!player->sent_bos) {
680                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
681                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
682                                  * legacy mmfw-player api */
683                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
684                         }
685
686                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
687                                 if (!player->sent_bos)
688                                         __mmplayer_handle_missed_plugin(player);
689                                 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
690                                 if (sound_result != MM_ERROR_NONE) {
691                                         // FIXME : need to check history
692                                         if (player->pipeline->videobin) {
693                                                 MMMessageParamType msg = {0, };
694
695                                                 LOGE("failed to go ahead because of video conflict\n");
696
697                                                 msg.union_type = MM_MSG_UNION_CODE;
698                                                 msg.code = MM_ERROR_POLICY_INTERRUPTED;
699                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
700
701                                                 _mmplayer_unrealize((MMHandleType)player);
702                                         } else {
703                                                 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
704                                                 _mmplayer_pause((MMHandleType)player);
705                                                 return sound_result;
706                                         }
707
708                                         return MM_ERROR_POLICY_INTERNAL;
709                                 }
710                         }
711
712                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
713                                 /* initialize because auto resume is done well. */
714                                 player->resumed_by_rewind = FALSE;
715                                 player->playback_rate = 1.0;
716                         }
717
718                         if (!player->sent_bos) {
719                                 /* check audio codec field is set or not
720                                  * we can get it from typefinder or codec's caps.
721                                  */
722                                 gchar *audio_codec = NULL;
723                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
724
725                                 /* The codec format can't be sent for audio only case like amr, mid etc.
726                                  * Because, parser don't make related TAG.
727                                  * So, if it's not set yet, fill it with found data.
728                                  */
729                                 if (!audio_codec) {
730                                         if (g_strrstr(player->type, "audio/midi"))
731                                                 audio_codec = g_strdup("MIDI");
732                                         else if (g_strrstr(player->type, "audio/x-amr"))
733                                                 audio_codec = g_strdup("AMR");
734                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
735                                                 audio_codec = g_strdup("AAC");
736                                         else
737                                                 audio_codec = g_strdup("unknown");
738                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
739
740                                         MMPLAYER_FREEIF(audio_codec);
741                                         mmf_attrs_commit(player->attrs);
742                                         LOGD("set audio codec type with caps\n");
743                                 }
744
745                                 post_bos = TRUE;
746                         }
747                 }
748                 break;
749
750         case MM_PLAYER_STATE_NONE:
751         default:
752                 LOGW("invalid target state, there is nothing to do.\n");
753                 break;
754         }
755
756
757         /* post message to application */
758         if (MMPLAYER_TARGET_STATE(player) == state) {
759                 /* fill the message with state of player */
760                 msg.state.previous = MMPLAYER_PREV_STATE(player);
761                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
762
763                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
764
765                 /* state changed by focus or resource callback */
766                 if (interrupted_by_focus || interrupted_by_resource) {
767                         msg.union_type = MM_MSG_UNION_CODE;
768                         if (interrupted_by_focus)
769                                 msg.code = player->sound_focus.focus_changed_msg;
770                         else if (interrupted_by_resource)
771                                 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
772                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
773                 } else /* state changed by usecase */
774                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
775         } else {
776                 LOGD("intermediate state, do nothing.\n");
777                 MMPLAYER_PRINT_STATE(player);
778                 return ret;
779         }
780
781         if (post_bos) {
782                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
783                 player->sent_bos = TRUE;
784         }
785
786         return ret;
787 }
788
789 static gpointer __mmplayer_next_play_thread(gpointer data)
790 {
791         mm_player_t* player = (mm_player_t*) data;
792         MMPlayerGstElement *mainbin = NULL;
793
794         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
795
796         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
797         while (!player->next_play_thread_exit) {
798                 LOGD("next play thread started. waiting for signal.\n");
799                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
800
801                 LOGD("reconfigure pipeline for gapless play.\n");
802
803                 if (player->next_play_thread_exit) {
804                         if (player->gapless.reconfigure) {
805                                 player->gapless.reconfigure = false;
806                                 MMPLAYER_PLAYBACK_UNLOCK(player);
807                         }
808                         LOGD("exiting gapless play thread\n");
809                         break;
810                 }
811
812                 mainbin = player->pipeline->mainbin;
813
814                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
815                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
816                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
817                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
818                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
819
820                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
821         }
822         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
823
824         return NULL;
825 }
826
827 static gpointer __mmplayer_repeat_thread(gpointer data)
828 {
829         mm_player_t* player = (mm_player_t*) data;
830         gboolean ret_value = FALSE;
831         MMHandleType attrs = 0;
832         gint count = 0;
833
834         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
835
836         MMPLAYER_REPEAT_THREAD_LOCK(player);
837         while (!player->repeat_thread_exit) {
838                 LOGD("repeat thread started. waiting for signal.\n");
839                 MMPLAYER_REPEAT_THREAD_WAIT(player);
840
841                 if (player->repeat_thread_exit) {
842                         LOGD("exiting repeat thread\n");
843                         break;
844                 }
845
846
847                 /* lock */
848                 MMPLAYER_CMD_LOCK(player);
849
850                 attrs = MMPLAYER_GET_ATTRS(player);
851
852                 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
853                         LOGE("can not get play count\n");
854                         MMPLAYER_CMD_UNLOCK(player);
855                         break;
856                 }
857
858                 if (player->section_repeat) {
859                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
860                 } else {
861                         if (player->playback_rate < 0.0) {
862                                 player->resumed_by_rewind = TRUE;
863                                 _mmplayer_set_mute((MMHandleType)player, 0);
864                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
865                         }
866
867                         ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
868                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
869                                 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
870
871                         /* initialize */
872                         player->sent_bos = FALSE;
873                 }
874
875                 if (!ret_value) {
876                         LOGE("failed to set position to zero for rewind\n");
877                         MMPLAYER_CMD_UNLOCK(player);
878                         continue;
879                 }
880
881                 /* decrease play count */
882                 if (count > 1) {
883                         /* we successeded to rewind. update play count and then wait for next EOS */
884                         count--;
885
886                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
887
888                         /* commit attribute */
889                         if (mmf_attrs_commit(attrs))
890                                 LOGE("failed to commit attribute\n");
891                 }
892
893                 /* unlock */
894                 MMPLAYER_CMD_UNLOCK(player);
895         }
896
897         MMPLAYER_REPEAT_THREAD_UNLOCK(player);
898         return NULL;
899 }
900
901 static void
902 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
903 {
904         MMHandleType attrs = 0;
905         guint64 data_size = 0;
906         gchar* path = NULL;
907         unsigned long pos_msec = 0;
908         struct stat sb;
909
910         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
911
912         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
913
914         attrs = MMPLAYER_GET_ATTRS(player);
915         if (!attrs) {
916                 LOGE("fail to get attributes.\n");
917                 return;
918         }
919
920         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
921                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
922
923                 if (stat(path, &sb) == 0)
924                         data_size = (guint64)sb.st_size;
925         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
926                 data_size = player->http_content_size;
927
928         __mm_player_streaming_buffering(player->streamer,
929                                                                                 buffering_msg,
930                                                                                 data_size,
931                                                                                 player->last_position,
932                                                                                 player->duration);
933
934         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
935
936         return;
937 }
938
939 static int
940 __mmplayer_handle_buffering_message(mm_player_t* player)
941 {
942         int ret = MM_ERROR_NONE;
943         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
944         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
945         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
946         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
947
948         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
949                 LOGW("do nothing for buffering msg\n");
950                 ret = MM_ERROR_PLAYER_INVALID_STATE;
951                 goto exit;
952         }
953
954         prev_state = MMPLAYER_PREV_STATE(player);
955         current_state = MMPLAYER_CURRENT_STATE(player);
956         target_state = MMPLAYER_TARGET_STATE(player);
957         pending_state = MMPLAYER_PENDING_STATE(player);
958
959         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
960                 MMPLAYER_STATE_GET_NAME(prev_state),
961                 MMPLAYER_STATE_GET_NAME(current_state),
962                 MMPLAYER_STATE_GET_NAME(pending_state),
963                 MMPLAYER_STATE_GET_NAME(target_state),
964                 player->streamer->is_buffering);
965
966         if (!player->streamer->is_buffering) {
967                 /* NOTE : if buffering has done, player has to go to target state. */
968                 switch (target_state) {
969                 case MM_PLAYER_STATE_PAUSED:
970                         {
971                                 switch (pending_state) {
972                                 case MM_PLAYER_STATE_PLAYING:
973                                         __gst_pause(player, TRUE);
974                                         break;
975
976                                 case MM_PLAYER_STATE_PAUSED:
977                                         LOGD("player is already going to paused state, there is nothing to do.\n");
978                                         break;
979
980                                 case MM_PLAYER_STATE_NONE:
981                                 case MM_PLAYER_STATE_NULL:
982                                 case MM_PLAYER_STATE_READY:
983                                 default:
984                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
985                                         break;
986                                 }
987                         }
988                         break;
989
990                 case MM_PLAYER_STATE_PLAYING:
991                         {
992                                 switch (pending_state) {
993                                 case MM_PLAYER_STATE_NONE:
994                                         {
995                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
996                                                         __gst_resume(player, TRUE);
997                                         }
998                                         break;
999
1000                                 case MM_PLAYER_STATE_PAUSED:
1001                                         /* NOTE: It should be worked as asynchronously.
1002                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1003                                          */
1004                                         __gst_resume(player, TRUE);
1005                                         break;
1006
1007                                 case MM_PLAYER_STATE_PLAYING:
1008                                         LOGD("player is already going to playing state, there is nothing to do.\n");
1009                                         break;
1010
1011                                 case MM_PLAYER_STATE_NULL:
1012                                 case MM_PLAYER_STATE_READY:
1013                                 default:
1014                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1015                                         break;
1016                                 }
1017                         }
1018                         break;
1019
1020                 case MM_PLAYER_STATE_NULL:
1021                 case MM_PLAYER_STATE_READY:
1022                 case MM_PLAYER_STATE_NONE:
1023                 default:
1024                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1025                         break;
1026                 }
1027         } else {
1028                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1029                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1030                  */
1031                 switch (pending_state) {
1032                 case MM_PLAYER_STATE_NONE:
1033                         {
1034                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1035                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1036                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1037                                                 LOGD("set pause state during buffering\n");
1038                                                 __gst_pause( player, TRUE );
1039                                         }
1040                                 }
1041                         }
1042                         break;
1043
1044                 case MM_PLAYER_STATE_PLAYING:
1045                         /* rtsp streaming pause makes rtsp server stop sending data. */
1046                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1047                                 __gst_pause ( player, TRUE );
1048                         }
1049                         break;
1050
1051                 case MM_PLAYER_STATE_PAUSED:
1052                         break;
1053
1054                 case MM_PLAYER_STATE_NULL:
1055                 case MM_PLAYER_STATE_READY:
1056                 default:
1057                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1058                         break;
1059                 }
1060         }
1061
1062 exit:
1063         return ret;
1064 }
1065
1066 static void
1067 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1068 {
1069         MMPlayerGstElement *textbin;
1070         MMPLAYER_FENTER();
1071
1072         MMPLAYER_RETURN_IF_FAIL(player &&
1073                                         player->pipeline &&
1074                                         player->pipeline->textbin);
1075
1076         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1077
1078         textbin = player->pipeline->textbin;
1079
1080         if (is_drop) {
1081                 LOGD("Drop subtitle text after getting EOS\n");
1082
1083                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1084                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1085
1086                 player->is_subtitle_force_drop = TRUE;
1087         } else {
1088                 if (player->is_subtitle_force_drop == TRUE) {
1089                         LOGD("Enable subtitle data path without drop\n");
1090
1091                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1092                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1093
1094                         LOGD("non-connected with external display");
1095
1096                         player->is_subtitle_force_drop = FALSE;
1097                 }
1098         }
1099 }
1100
1101 static gboolean
1102 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1103 {
1104         mm_player_t* player = (mm_player_t*) data;
1105         gboolean ret = TRUE;
1106         static gboolean async_done = FALSE;
1107
1108         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1109         MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1110
1111         switch (GST_MESSAGE_TYPE(msg)) {
1112         case GST_MESSAGE_UNKNOWN:
1113                 LOGD("unknown message received\n");
1114                 break;
1115
1116         case GST_MESSAGE_EOS:
1117                 {
1118                         MMHandleType attrs = 0;
1119                         gint count = 0;
1120
1121                         LOGD("GST_MESSAGE_EOS received\n");
1122
1123                         /* NOTE : EOS event is comming multiple time. watch out it */
1124                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1125                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1126                                 LOGD("EOS received on non-playing state. ignoring it\n");
1127                                 break;
1128                         }
1129
1130                         if (player->pipeline) {
1131                                 if (player->pipeline->textbin)
1132                                         __mmplayer_drop_subtitle(player, TRUE);
1133
1134                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1135                                         GstPad *pad = NULL;
1136
1137                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1138
1139                                         LOGD("release audio callback\n");
1140
1141                                         /* release audio callback */
1142                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1143                                         player->audio_cb_probe_id = 0;
1144                                         /* audio callback should be free because it can be called even though probe remove.*/
1145                                         player->audio_stream_cb = NULL;
1146                                         player->audio_stream_cb_user_param = NULL;
1147
1148                                 }
1149                         }
1150                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1151                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1152
1153                         /* rewind if repeat count is greater then zero */
1154                         /* get play count */
1155                         attrs = MMPLAYER_GET_ATTRS(player);
1156
1157                         if (attrs) {
1158                                 gboolean smooth_repeat = FALSE;
1159
1160                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1161                                 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1162
1163                                 player->play_count = count;
1164
1165                                 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1166
1167                                 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1168                                         if (smooth_repeat) {
1169                                                 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1170
1171                                                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1172
1173                                                 break;
1174                                         } else {
1175                                                 gint ret_value = 0;
1176
1177                                                 if (player->section_repeat) {
1178                                                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1179                                                 } else {
1180                                                         if (player->playback_rate < 0.0) {
1181                                                                 player->resumed_by_rewind = TRUE;
1182                                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1183                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1184                                                         }
1185
1186                                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1187
1188                                                         /* initialize */
1189                                                         player->sent_bos = FALSE;
1190                                                 }
1191
1192                                                 if (MM_ERROR_NONE != ret_value)
1193                                                         LOGE("failed to set position to zero for rewind\n");
1194
1195                                                 /* not posting eos when repeating */
1196                                                 break;
1197                                         }
1198                                 }
1199                         }
1200
1201                         if (player->pipeline)
1202                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1203
1204                         /* post eos message to application */
1205                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1206
1207                         /* reset last position */
1208                         player->last_position = 0;
1209                 }
1210                 break;
1211
1212         case GST_MESSAGE_ERROR:
1213                 {
1214                         GError *error = NULL;
1215                         gchar* debug = NULL;
1216
1217                         /* generating debug info before returning error */
1218                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1219
1220                         /* get error code */
1221                         gst_message_parse_error(msg, &error, &debug);
1222
1223                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1224                                 /* Note : the streaming error from the streaming source is handled
1225                                  *   using __mmplayer_handle_streaming_error.
1226                                  */
1227                                 __mmplayer_handle_streaming_error(player, msg);
1228
1229                                 /* dump state of all element */
1230                                 __mmplayer_dump_pipeline_state(player);
1231                         } else {
1232                                 /* traslate gst error code to msl error code. then post it
1233                                  * to application if needed
1234                                  */
1235                                 __mmplayer_handle_gst_error(player, msg, error);
1236
1237                                 if (debug)
1238                                         LOGE("error debug : %s", debug);
1239                         }
1240
1241                         if (MMPLAYER_IS_HTTP_PD(player))
1242                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1243
1244                         MMPLAYER_FREEIF(debug);
1245                         g_error_free(error);
1246                 }
1247                 break;
1248
1249         case GST_MESSAGE_WARNING:
1250                 {
1251                         char* debug = NULL;
1252                         GError* error = NULL;
1253
1254                         gst_message_parse_warning(msg, &error, &debug);
1255
1256                         LOGD("warning : %s\n", error->message);
1257                         LOGD("debug : %s\n", debug);
1258
1259                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1260
1261                         MMPLAYER_FREEIF(debug);
1262                         g_error_free(error);
1263                 }
1264                 break;
1265
1266         case GST_MESSAGE_TAG:
1267                 {
1268                         LOGD("GST_MESSAGE_TAG\n");
1269                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1270                                 LOGW("failed to extract tags from gstmessage\n");
1271                 }
1272                 break;
1273
1274         case GST_MESSAGE_BUFFERING:
1275                 {
1276                         MMMessageParamType msg_param = {0, };
1277                         int bRet = MM_ERROR_NONE;
1278
1279                         if (!MMPLAYER_IS_STREAMING(player))
1280                                 break;
1281
1282                         /* ignore the prev buffering message */
1283                         if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1284                                 gint buffer_percent = 0;
1285
1286                                 gst_message_parse_buffering(msg, &buffer_percent);
1287
1288                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1289                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1290                                         player->streamer->is_buffering_done = FALSE;
1291                                 }
1292
1293                                 break;
1294                         }
1295
1296                         MMPLAYER_CMD_LOCK(player);
1297                         __mmplayer_update_buffer_setting(player, msg);
1298
1299                         bRet = __mmplayer_handle_buffering_message(player);
1300
1301                         if (bRet == MM_ERROR_NONE) {
1302                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1303                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1304
1305                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1306                                         player->pending_resume &&
1307                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1308
1309                                         player->is_external_subtitle_added_now = FALSE;
1310                                         player->pending_resume = FALSE;
1311                                         _mmplayer_resume((MMHandleType)player);
1312                                 }
1313
1314                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1315                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1316
1317                                         if (player->doing_seek) {
1318                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1319                                                         player->doing_seek = FALSE;
1320                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1321                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1322                                                         async_done = TRUE;
1323                                                 }
1324                                         }
1325                                 }
1326                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1327                                 if (!player->streamer) {
1328                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1329                                         MMPLAYER_CMD_UNLOCK(player);
1330                                         break;
1331                                 }
1332
1333                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1334
1335                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1336                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1337
1338                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1339                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1340                                                 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1341                                         } else {
1342                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1343                                         }
1344                                 } else {
1345                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1346                                         MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1347                                 }
1348                         }
1349                         MMPLAYER_CMD_UNLOCK(player);
1350                 }
1351                 break;
1352
1353         case GST_MESSAGE_STATE_CHANGED:
1354                 {
1355                         MMPlayerGstElement *mainbin;
1356                         const GValue *voldstate, *vnewstate, *vpending;
1357                         GstState oldstate = GST_STATE_NULL;
1358                         GstState newstate = GST_STATE_NULL;
1359                         GstState pending = GST_STATE_NULL;
1360
1361                         if (!(player->pipeline && player->pipeline->mainbin)) {
1362                                 LOGE("player pipeline handle is null");
1363                                 break;
1364                         }
1365
1366                         mainbin = player->pipeline->mainbin;
1367
1368                         /* we only handle messages from pipeline */
1369                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1370                                 break;
1371
1372                         /* get state info from msg */
1373                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1374                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1375                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1376
1377                         if (!voldstate || !vnewstate) {
1378                                 LOGE("received msg has wrong format.");
1379                                 break;
1380                         }
1381
1382                         oldstate = (GstState)voldstate->data[0].v_int;
1383                         newstate = (GstState)vnewstate->data[0].v_int;
1384                         if (vpending)
1385                                 pending = (GstState)vpending->data[0].v_int;
1386
1387                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1388                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1389                                 gst_element_state_get_name((GstState)oldstate),
1390                                 gst_element_state_get_name((GstState)newstate),
1391                                 gst_element_state_get_name((GstState)pending));
1392
1393                         if (newstate == GST_STATE_PLAYING) {
1394                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1395
1396                                         int retVal = MM_ERROR_NONE;
1397                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1398
1399                                         retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1400
1401                                         if (MM_ERROR_NONE != retVal)
1402                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1403
1404                                         player->pending_seek.is_pending = FALSE;
1405                                 }
1406                         }
1407
1408                         if (oldstate == newstate) {
1409                                 LOGD("pipeline reports state transition to old state");
1410                                 break;
1411                         }
1412
1413                         switch (newstate) {
1414                         case GST_STATE_VOID_PENDING:
1415                                 break;
1416
1417                         case GST_STATE_NULL:
1418                                 break;
1419
1420                         case GST_STATE_READY:
1421                                 break;
1422
1423                         case GST_STATE_PAUSED:
1424                                 {
1425                                         gboolean prepare_async = FALSE;
1426
1427                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1428                                                 __mmplayer_configure_audio_callback(player);
1429
1430                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1431                                                 // managed prepare async case
1432                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1433                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1434                                         }
1435
1436                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1437                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1438
1439                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1440                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1441                                                                 player->total_maximum_bitrate, player->total_bitrate);
1442                                         }
1443                                 }
1444                                 break;
1445
1446                         case GST_STATE_PLAYING:
1447                                 {
1448                                         if (MMPLAYER_IS_STREAMING(player)) {
1449                                                 // managed prepare async case when buffering is completed
1450                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1451                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1452                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1453                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1454
1455                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1456
1457                                                         LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1458                                                         if (player->streamer->buffering_percent < 100) {
1459
1460                                                                 MMMessageParamType msg_param = {0, };
1461                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1462
1463                                                                 msg_param.connection.buffering = 100;
1464                                                                 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1465                                                         }
1466                                                 }
1467                                         }
1468
1469                                         if (player->gapless.stream_changed) {
1470                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1471                                                 player->gapless.stream_changed = FALSE;
1472                                         }
1473
1474                                         if (player->doing_seek && async_done) {
1475                                                 player->doing_seek = FALSE;
1476                                                 async_done = FALSE;
1477                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1478                                         }
1479                                 }
1480                                 break;
1481
1482                         default:
1483                                 break;
1484                         }
1485                 }
1486                 break;
1487
1488         case GST_MESSAGE_CLOCK_LOST:
1489                         {
1490                                 GstClock *clock = NULL;
1491                                 gboolean need_new_clock = FALSE;
1492
1493                                 gst_message_parse_clock_lost(msg, &clock);
1494                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1495
1496                                 if (!player->videodec_linked)
1497                                         need_new_clock = TRUE;
1498                                 else if (!player->ini.use_system_clock)
1499                                         need_new_clock = TRUE;
1500
1501                                 if (need_new_clock) {
1502                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1503                                         __gst_pause(player, FALSE);
1504                                         __gst_resume(player, FALSE);
1505                                 }
1506                         }
1507                         break;
1508
1509         case GST_MESSAGE_NEW_CLOCK:
1510                         {
1511                                 GstClock *clock = NULL;
1512                                 gst_message_parse_new_clock(msg, &clock);
1513                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1514                         }
1515                         break;
1516
1517         case GST_MESSAGE_ELEMENT:
1518                         {
1519                                 const gchar *structure_name;
1520                                 gint count = 0;
1521                                 MMHandleType attrs = 0;
1522
1523                                 attrs = MMPLAYER_GET_ATTRS(player);
1524                                 if (!attrs) {
1525                                         LOGE("cannot get content attribute");
1526                                         ret = FALSE;
1527                                         break;
1528                                 }
1529
1530                                 if (gst_message_get_structure(msg) == NULL)
1531                                         break;
1532
1533                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1534                                 if (!structure_name)
1535                                         break;
1536
1537                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1538                                         gint num_buffers = 0;
1539                                         gint extra_num_buffers = 0;
1540
1541                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1542                                                 player->video_num_buffers = num_buffers;
1543                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1544                                         }
1545
1546                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1547                                                 player->video_extra_num_buffers = extra_num_buffers;
1548                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1549                                         }
1550                                         break;
1551                                 }
1552
1553                                 if (!strcmp(structure_name, "Language_list")) {
1554                                         const GValue *lang_list = NULL;
1555                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1556                                         if (lang_list != NULL) {
1557                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1558                                                 if (count > 1)
1559                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1560                                         }
1561                                 }
1562
1563                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1564                                         const GValue *lang_list = NULL;
1565                                         MMPlayerLangStruct *temp = NULL;
1566
1567                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1568                                         if (lang_list != NULL) {
1569                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1570                                                 if (count) {
1571                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1572                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1573                                                         if (mmf_attrs_commit(attrs))
1574                                                           LOGE("failed to commit.\n");
1575                                                         LOGD("Total subtitle tracks = %d \n", count);
1576                                                 }
1577                                                 while (count) {
1578                                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1579                                                         if (temp)
1580                                                                 LOGD("value of lang_key is %s and lang_code is %s",
1581                                                                                         temp->language_key, temp->language_code);
1582                                                         count--;
1583                                                 }
1584                                         }
1585                                 }
1586
1587                                 /* custom message */
1588                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1589                                         MMMessageParamType msg_param = {0,};
1590                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1591                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1592                                 }
1593
1594                                 /* custom message for RTSP attribute :
1595                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1596                                     sdp which has contents info is received when rtsp connection is opened.
1597                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1598                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1599
1600                                         gchar           *audio_codec = NULL;
1601                                         gchar           *video_codec = NULL;
1602                                         gchar           *video_frame_size = NULL;
1603
1604                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1605                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1606                                         __mmplayer_get_stream_service_type(player);
1607                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1608
1609                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1610                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1611                                         if (audio_codec)
1612                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1613
1614                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1615                                         LOGD("rtsp_video_codec : %s", video_codec);
1616                                         if (video_codec)
1617                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1618
1619                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1620                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1621                                         if (video_frame_size) {
1622
1623                                                 char *seperator = strchr(video_frame_size, '-');
1624                                                 if (seperator) {
1625
1626                                                         char video_width[10]={0,};
1627                                                         int frame_size_len = strlen(video_frame_size);
1628                                                         int separtor_len = strlen(seperator);
1629
1630                                                         strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1631                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1632
1633                                                         seperator++;
1634                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1635                                                 }
1636                                         }
1637
1638                                         if (mmf_attrs_commit(attrs))
1639                                                 LOGE("failed to commit.\n");
1640                                 }
1641                         }
1642                         break;
1643
1644         case GST_MESSAGE_DURATION_CHANGED:
1645                 {
1646                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1647                         ret = __mmplayer_gst_handle_duration(player, msg);
1648                         if (!ret)
1649                                 LOGW("failed to update duration");
1650                 }
1651
1652                 break;
1653
1654         case GST_MESSAGE_ASYNC_START:
1655                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1656                 break;
1657
1658         case GST_MESSAGE_ASYNC_DONE:
1659                 {
1660                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1661
1662                         /* we only handle messages from pipeline */
1663                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1664                                 break;
1665
1666                         if (player->doing_seek) {
1667                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1668                                         player->doing_seek = FALSE;
1669                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1670                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1671                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1672                                                 (player->streamer) &&
1673                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1674                                                 (player->streamer->is_buffering == FALSE)) {
1675                                                 GstQuery *query = NULL;
1676                                                 gboolean busy = FALSE;
1677                                                 gint percent = 0;
1678
1679                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1680                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1681                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1682                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1683                                                         gst_query_unref(query);
1684
1685                                                         LOGD("buffered percent(%s): %d\n",
1686                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1687                                                 }
1688
1689                                                 if (percent >= 100) {
1690                                                         player->streamer->is_buffering = FALSE;
1691                                                         __mmplayer_handle_buffering_message(player);
1692                                                 }
1693                                         }
1694
1695                                         async_done = TRUE;
1696                                 }
1697                         }
1698                 }
1699                 break;
1700
1701         #if 0 /* delete unnecessary logs */
1702         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1703         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1704         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1705         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1706         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1707         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1708         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1709         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1710         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1711         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1712         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1713         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1714         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1715         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1716         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1717         #endif
1718
1719         default:
1720                 break;
1721         }
1722
1723         /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1724          * gst_element_post_message api takes ownership of the message.
1725          */
1726         //gst_message_unref(msg);
1727
1728         return ret;
1729 }
1730
1731 static gboolean
1732 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1733 {
1734         gint64 bytes = 0;
1735
1736         MMPLAYER_FENTER();
1737
1738         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1739         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1740
1741         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1742                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1743                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1744
1745                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1746                         LOGD("data total size of http content: %lld", bytes);
1747                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1748                 }
1749         } else
1750                 /* handling audio clip which has vbr. means duration is keep changing */
1751                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1752
1753         MMPLAYER_FLEAVE();
1754
1755         return TRUE;
1756 }
1757
1758
1759 static gboolean
1760 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1761 {
1762
1763 /* macro for better code readability */
1764 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1765 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1766         if (string != NULL) {\
1767                 SECURE_LOGD("update tag string : %s\n", string); \
1768                 mm_attrs_set_string_by_name(attribute, playertag, string); \
1769                 g_free(string);\
1770                 string = NULL;\
1771         } \
1772 }
1773
1774 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1775 GstSample *sample = NULL;\
1776 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1777         GstMapInfo info = GST_MAP_INFO_INIT;\
1778         buffer = gst_sample_get_buffer(sample);\
1779         if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1780                 LOGD("failed to get image data from tag");\
1781                 return FALSE;\
1782         } \
1783         SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1784         MMPLAYER_FREEIF(player->album_art);\
1785         player->album_art = (gchar *)g_malloc(info.size);\
1786         if (player->album_art) {\
1787                 memcpy(player->album_art, info.data, info.size);\
1788                 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1789                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1790                         msg_param.data = (void *)player->album_art;\
1791                         msg_param.size = info.size;\
1792                         MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1793                         SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1794                 } \
1795         } \
1796         gst_buffer_unmap(buffer, &info);\
1797 }
1798
1799 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1800 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1801         if (v_uint) {\
1802                 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1803                         if (player->updated_bitrate_count == 0) \
1804                                 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1805                         if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1806                                 player->bitrate[player->updated_bitrate_count] = v_uint;\
1807                                 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1808                                 player->updated_bitrate_count++; \
1809                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1810                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1811                         } \
1812                 } \
1813                 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1814                         if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1815                                 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1816                                 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1817                                 player->updated_maximum_bitrate_count++; \
1818                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1819                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1820                         } \
1821                 } else\
1822                         mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1823                 v_uint = 0;\
1824         } \
1825 }
1826
1827 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1828 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1829         if (date != NULL) {\
1830                 string = g_strdup_printf("%d", g_date_get_year(date));\
1831                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1832                 SECURE_LOGD("metainfo year : %s\n", string);\
1833                 MMPLAYER_FREEIF(string);\
1834                 g_date_free(date);\
1835         } \
1836 }
1837
1838 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1839 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1840         if (datetime != NULL) {\
1841                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1842                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1843                 SECURE_LOGD("metainfo year : %s\n", string);\
1844                 MMPLAYER_FREEIF(string);\
1845                 gst_date_time_unref(datetime);\
1846         } \
1847 }
1848
1849 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1850 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1851         if (v_uint64) {\
1852                 /* FIXIT : don't know how to store date */\
1853                 g_assert(1);\
1854                 v_uint64 = 0;\
1855         } \
1856 }
1857
1858 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1859 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1860         if (v_double) {\
1861                 /* FIXIT : don't know how to store date */\
1862                 g_assert(1);\
1863                 v_double = 0;\
1864         } \
1865 }
1866
1867         /* function start */
1868         GstTagList* tag_list = NULL;
1869
1870         MMHandleType attrs = 0;
1871
1872         char *string = NULL;
1873         guint v_uint = 0;
1874         GDate *date = NULL;
1875         GstDateTime *datetime = NULL;
1876         /* album cover */
1877         GstBuffer *buffer = NULL;
1878         gint index = 0;
1879         MMMessageParamType msg_param = {0, };
1880
1881         /* currently not used. but those are needed for above macro */
1882         //guint64 v_uint64 = 0;
1883         //gdouble v_double = 0;
1884
1885         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1886
1887         attrs = MMPLAYER_GET_ATTRS(player);
1888
1889         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1890
1891         /* get tag list from gst message */
1892         gst_message_parse_tag(msg, &tag_list);
1893
1894         /* store tags to player attributes */
1895         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1896         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1897         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1898         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1899         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1900         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1901         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1902         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1903         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1904         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1905         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1906         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1907         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1908         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1909         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1910         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1911         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1912         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1913         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1914         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1915         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1916         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1917         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1918         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1919         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1920         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1922         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1923         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1924         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1925         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1926         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1927         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1928         MMPLAYER_UPDATE_TAG_LOCK(player);
1929         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1930         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1931         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1932         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1933         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1934         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1937         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1938         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1939         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1940         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1941         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1942         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1943         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1944
1945         if (mmf_attrs_commit(attrs))
1946                 LOGE("failed to commit.\n");
1947
1948         gst_tag_list_free(tag_list);
1949
1950         return TRUE;
1951 }
1952
1953 static void
1954 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)  // @
1955 {
1956         mm_player_t* player = (mm_player_t*) data;
1957
1958         MMPLAYER_FENTER();
1959
1960         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1961           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1962           * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1963           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1964
1965           * [1] audio and video will be dumped with filesink.
1966           * [2] autoplugging is done by just using pad caps.
1967           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1968           * and the video will be dumped via filesink.
1969           */
1970         if (player->num_dynamic_pad == 0) {
1971                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1972
1973                 if (!__mmplayer_gst_remove_fakesink(player,
1974                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1975                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1976                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1977                          * source element are not same. To overcome this situation, this function will called
1978                          * several places and several times. Therefore, this is not an error case.
1979                          */
1980                         return;
1981         }
1982
1983         /* create dot before error-return. for debugging */
1984         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1985
1986         player->no_more_pad = TRUE;
1987
1988         MMPLAYER_FLEAVE();
1989 }
1990
1991 static gboolean
1992 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1993 {
1994         GstElement* parent = NULL;
1995
1996         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1997
1998         /* if we have no fakesink. this meas we are using decodebin which doesn'
1999         t need to add extra fakesink */
2000         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2001
2002         /* lock */
2003         MMPLAYER_FSINK_LOCK(player);
2004
2005         if (!fakesink->gst)
2006                 goto ERROR;
2007
2008         /* get parent of fakesink */
2009         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2010         if (!parent) {
2011                 LOGD("fakesink already removed\n");
2012                 goto ERROR;
2013         }
2014
2015         gst_element_set_locked_state(fakesink->gst, TRUE);
2016
2017         /* setting the state to NULL never returns async
2018          * so no need to wait for completion of state transiton
2019          */
2020         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2021                 LOGE("fakesink state change failure!\n");
2022                 /* FIXIT : should I return here? or try to proceed to next? */
2023                 /* return FALSE; */
2024
2025         /* remove fakesink from it's parent */
2026         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2027                 LOGE("failed to remove fakesink\n");
2028
2029                 gst_object_unref(parent);
2030
2031                 goto ERROR;
2032         }
2033
2034         gst_object_unref(parent);
2035
2036         LOGD("state-holder removed\n");
2037
2038         gst_element_set_locked_state(fakesink->gst, FALSE);
2039
2040         MMPLAYER_FSINK_UNLOCK(player);
2041         return TRUE;
2042
2043 ERROR:
2044         if (fakesink->gst)
2045                 gst_element_set_locked_state(fakesink->gst, FALSE);
2046
2047         MMPLAYER_FSINK_UNLOCK(player);
2048         return FALSE;
2049 }
2050
2051
2052 static void
2053 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2054 {
2055         GstPad *sinkpad = NULL;
2056         GstCaps* caps = NULL;
2057         GstElement* new_element = NULL;
2058         GstStructure* str = NULL;
2059         const gchar* name = NULL;
2060
2061         mm_player_t* player = (mm_player_t*) data;
2062
2063         MMPLAYER_FENTER();
2064
2065         MMPLAYER_RETURN_IF_FAIL(element && pad);
2066         MMPLAYER_RETURN_IF_FAIL(player &&
2067                                         player->pipeline &&
2068                                         player->pipeline->mainbin);
2069
2070
2071         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2072          * num_dynamic_pad will decreased after creating a sinkbin.
2073          */
2074         player->num_dynamic_pad++;
2075         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2076
2077         caps = gst_pad_query_caps(pad, NULL);
2078
2079         MMPLAYER_CHECK_NULL(caps);
2080
2081         /* clear  previous result*/
2082         player->have_dynamic_pad = FALSE;
2083
2084         str = gst_caps_get_structure(caps, 0);
2085
2086         if (!str) {
2087                 LOGE("cannot get structure from caps.\n");
2088                 goto ERROR;
2089         }
2090
2091         name = gst_structure_get_name(str);
2092         if (!name) {
2093                 LOGE("cannot get mimetype from structure.\n");
2094                 goto ERROR;
2095         }
2096
2097         if (strstr(name, "video")) {
2098                 gint stype = 0;
2099                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2100
2101                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2102                         if (player->v_stream_caps) {
2103                                 gst_caps_unref(player->v_stream_caps);
2104                                 player->v_stream_caps = NULL;
2105                         }
2106
2107                         new_element = gst_element_factory_make("fakesink", NULL);
2108                         player->num_dynamic_pad--;
2109                         goto NEW_ELEMENT;
2110                 }
2111         }
2112
2113         /* clear  previous result*/
2114         player->have_dynamic_pad = FALSE;
2115
2116         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2117                 LOGE("failed to autoplug for caps");
2118                 goto ERROR;
2119         }
2120
2121         /* check if there's dynamic pad*/
2122         if (player->have_dynamic_pad) {
2123                 LOGE("using pad caps assums there's no dynamic pad !\n");
2124                 goto ERROR;
2125         }
2126
2127         gst_caps_unref(caps);
2128         caps = NULL;
2129
2130 NEW_ELEMENT:
2131
2132         /* excute new_element if created*/
2133         if (new_element) {
2134                 LOGD("adding new element to pipeline\n");
2135
2136                 /* set state to READY before add to bin */
2137                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2138
2139                 /* add new element to the pipeline */
2140                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2141                         LOGE("failed to add autoplug element to bin\n");
2142                         goto ERROR;
2143                 }
2144
2145                 /* get pad from element */
2146                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2147                 if (!sinkpad) {
2148                         LOGE("failed to get sinkpad from autoplug element\n");
2149                         goto ERROR;
2150                 }
2151
2152                 /* link it */
2153                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2154                         LOGE("failed to link autoplug element\n");
2155                         goto ERROR;
2156                 }
2157
2158                 gst_object_unref(sinkpad);
2159                 sinkpad = NULL;
2160
2161                 /* run. setting PLAYING here since streamming source is live source */
2162                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2163         }
2164
2165         MMPLAYER_FLEAVE();
2166
2167         return;
2168
2169 STATE_CHANGE_FAILED:
2170 ERROR:
2171         /* FIXIT : take care if new_element has already added to pipeline */
2172         if (new_element)
2173                 gst_object_unref(GST_OBJECT(new_element));
2174
2175         if (sinkpad)
2176                 gst_object_unref(GST_OBJECT(sinkpad));
2177
2178         if (caps)
2179                 gst_object_unref(GST_OBJECT(caps));
2180
2181         /* FIXIT : how to inform this error to MSL ????? */
2182         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2183          * then post an error to application
2184          */
2185 }
2186
2187
2188
2189 /* FIXIT : check indent */
2190 #if 0
2191 static void
2192 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2193 {
2194         GstPad *sinkpad = NULL;
2195         GstCaps* caps = NULL;
2196         GstElement* new_element = NULL;
2197         enum MainElementID element_id = MMPLAYER_M_NUM;
2198
2199         mm_player_t* player = (mm_player_t*) data;
2200
2201         MMPLAYER_FENTER();
2202
2203         MMPLAYER_RETURN_IF_FAIL(element && pad);
2204         MMPLAYER_RETURN_IF_FAIL(player &&
2205                 player->pipeline &&
2206                 player->pipeline->mainbin);
2207
2208         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2209
2210         {
2211                 LOGD("using pad caps to autopluging instead of doing typefind\n");
2212                 caps = gst_pad_query_caps(pad);
2213                 MMPLAYER_CHECK_NULL(caps);
2214                 /* clear  previous result*/
2215                 player->have_dynamic_pad = FALSE;
2216                 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2217                 if (!new_element) {
2218                         LOGE("failed to create wfd rtp depay element\n");
2219                         goto ERROR;
2220                 }
2221                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2222                 /* add new element to the pipeline */
2223                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2224                         LOGD("failed to add autoplug element to bin\n");
2225                         goto ERROR;
2226                 }
2227                 /* get pad from element */
2228                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2229                 if (!sinkpad) {
2230                         LOGD("failed to get sinkpad from autoplug element\n");
2231                         goto ERROR;
2232                 }
2233                 /* link it */
2234                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2235                         LOGD("failed to link autoplug element\n");
2236                         goto ERROR;
2237                 }
2238                 gst_object_unref(sinkpad);
2239                 sinkpad = NULL;
2240                 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2241                 caps = gst_pad_query_caps(pad);
2242                 MMPLAYER_CHECK_NULL(caps);
2243                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2244                 /* create typefind */
2245                 new_element = gst_element_factory_make("typefind", NULL);
2246                 if (!new_element) {
2247                         LOGD("failed to create typefind\n");
2248                         goto ERROR;
2249                 }
2250
2251                 MMPLAYER_SIGNAL_CONNECT(player,
2252                         G_OBJECT(new_element),
2253                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2254                         "have-type",
2255                         G_CALLBACK(__mmplayer_typefind_have_type),
2256                         (gpointer)player);
2257
2258                 player->have_dynamic_pad = FALSE;
2259         }
2260
2261         /* excute new_element if created*/
2262         if (new_element) {
2263                 LOGD("adding new element to pipeline\n");
2264
2265                 /* set state to READY before add to bin */
2266                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2267
2268                 /* add new element to the pipeline */
2269                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2270                         LOGD("failed to add autoplug element to bin\n");
2271                         goto ERROR;
2272                 }
2273
2274                 /* get pad from element */
2275                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2276                 if (!sinkpad) {
2277                         LOGD("failed to get sinkpad from autoplug element\n");
2278                         goto ERROR;
2279                 }
2280
2281                 /* link it */
2282                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2283                         LOGD("failed to link autoplug element\n");
2284                         goto ERROR;
2285                 }
2286
2287                 gst_object_unref(sinkpad);
2288                 sinkpad = NULL;
2289
2290                 /* run. setting PLAYING here since streamming source is live source */
2291                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2292         }
2293
2294         /* store handle to futher manipulation */
2295         player->pipeline->mainbin[element_id].id = element_id;
2296         player->pipeline->mainbin[element_id].gst = new_element;
2297
2298         MMPLAYER_FLEAVE();
2299
2300         return;
2301
2302 STATE_CHANGE_FAILED:
2303 ERROR:
2304         /* FIXIT : take care if new_element has already added to pipeline */
2305         if (new_element)
2306                 gst_object_unref(GST_OBJECT(new_element));
2307
2308         if (sinkpad)
2309                 gst_object_unref(GST_OBJECT(sinkpad));
2310
2311         if (caps)
2312                 gst_object_unref(GST_OBJECT(caps));
2313
2314         /* FIXIT : how to inform this error to MSL ????? */
2315         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2316          * then post an error to application
2317          */
2318 }
2319 #endif
2320
2321 static GstPadProbeReturn
2322 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2323 {
2324         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2325         return GST_PAD_PROBE_OK;
2326 }
2327
2328 static GstPadProbeReturn
2329 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2330 {
2331         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2332         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2333         mm_player_t* player = (mm_player_t*)data;
2334         GstCaps* caps = NULL;
2335         GstStructure* str = NULL;
2336         const gchar* name = NULL;
2337         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2338
2339
2340         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2341                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2342                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2343                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2344                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2345                         return ret;
2346         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2347                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2348                         return ret;
2349         }
2350
2351         caps = gst_pad_query_caps(pad, NULL);
2352         if (!caps) {
2353                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2354                 goto ERROR;
2355         }
2356
2357         str = gst_caps_get_structure(caps, 0);
2358         if (!str) {
2359                 LOGE("failed to get structure from caps");
2360                 goto ERROR;
2361         }
2362
2363         name = gst_structure_get_name(str);
2364         if (!name) {
2365                 LOGE("failed to get name from str");
2366                 goto ERROR;
2367         }
2368
2369         if (strstr(name, "audio")) {
2370                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2371         } else if (strstr(name, "video")) {
2372                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2373         } else {
2374                 /* text track is not supportable */
2375                 LOGE("invalid name %s", name);
2376                 goto ERROR;
2377         }
2378
2379         switch (GST_EVENT_TYPE(event)) {
2380         case GST_EVENT_EOS:
2381                 {
2382                         /* in case of gapless, drop eos event not to send it to sink */
2383                         if (player->gapless.reconfigure && !player->msg_posted) {
2384                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2385                                 ret = GST_PAD_PROBE_DROP;
2386                         }
2387                         break;
2388                 }
2389         case GST_EVENT_STREAM_START:
2390                 {
2391                         gint64 stop_running_time = 0;
2392                         gint64 position_running_time = 0;
2393                         gint64 position = 0;
2394                         gint idx = 0;
2395
2396                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2397                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2398                                         !(player->selector[idx].event_probe_id)) {
2399                                         /* LOGW("[%d] skip", idx); */
2400                                         continue;
2401                                 }
2402
2403                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2404                                         stop_running_time =
2405                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2406                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2407                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2408                                         stop_running_time =
2409                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2410                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2411                                 } else {
2412                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2413                                         stop_running_time =
2414                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2415                                                                 GST_FORMAT_TIME, player->duration);
2416                                 }
2417
2418                                 position_running_time =
2419                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2420                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2421
2422                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2423                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2424                                         idx,
2425                                         GST_TIME_ARGS(stop_running_time),
2426                                         GST_TIME_ARGS(position_running_time),
2427                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2428                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2429
2430                                 position_running_time = MAX(position_running_time, stop_running_time);
2431                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2432                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2433                                 position_running_time = MAX(0, position_running_time);
2434                                 position = MAX(position, position_running_time);
2435                         }
2436
2437                         if (position != 0) {
2438                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2439                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2440                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2441
2442                                 player->gapless.start_time[stream_type] += position;
2443                         }
2444                         break;
2445                 }
2446         case GST_EVENT_FLUSH_STOP:
2447                 {
2448                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2449                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2450                         player->gapless.start_time[stream_type] = 0;
2451                         break;
2452                 }
2453         case GST_EVENT_SEGMENT:
2454                 {
2455                         GstSegment segment;
2456                         GstEvent *tmpev;
2457
2458                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2459                         gst_event_copy_segment(event, &segment);
2460
2461                         if (segment.format == GST_FORMAT_TIME) {
2462                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2463                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2464                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2465                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2466                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2467                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2468
2469                                 /* keep the all the segment ev to cover the seeking */
2470                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2471                                 player->gapless.update_segment[stream_type] = TRUE;
2472
2473                                 if (!player->gapless.running)
2474                                         break;
2475
2476                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2477
2478                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2479
2480                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2481                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2482                                 gst_event_unref(event);
2483                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2484                         }
2485                         break;
2486                 }
2487         case GST_EVENT_QOS:
2488                 {
2489                         gdouble proportion = 0.0;
2490                         GstClockTimeDiff diff = 0;
2491                         GstClockTime timestamp = 0;
2492                         gint64 running_time_diff = -1;
2493                         GstQOSType type = 0;
2494                         GstEvent *tmpev = NULL;
2495
2496                         running_time_diff = player->gapless.segment[stream_type].base;
2497
2498                         if (running_time_diff <= 0) /* don't need to adjust */
2499                                 break;
2500
2501                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2502                         gst_event_unref(event);
2503
2504                         if (timestamp < running_time_diff) {
2505                                 LOGW("QOS event from previous group");
2506                                 ret = GST_PAD_PROBE_DROP;
2507                                 break;
2508                         }
2509
2510                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2511                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2512                                                 stream_type, GST_TIME_ARGS(timestamp),
2513                                                 GST_TIME_ARGS(running_time_diff),
2514                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2515
2516                         timestamp -= running_time_diff;
2517
2518                         /* That case is invalid for QoS events */
2519                         if (diff < 0 && -diff > timestamp) {
2520                                 LOGW("QOS event from previous group");
2521                                 ret = GST_PAD_PROBE_DROP;
2522                                 break;
2523                         }
2524
2525                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2526                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2527
2528                         break;
2529                 }
2530         default:
2531                 break;
2532         }
2533
2534 ERROR:
2535         if (caps)
2536                 gst_caps_unref(caps);
2537         return ret;
2538 }
2539
2540 static void
2541 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2542 {
2543         mm_player_t* player = NULL;
2544         GstElement* pipeline = NULL;
2545         GstElement* selector = NULL;
2546         GstElement* fakesink = NULL;
2547         GstCaps* caps = NULL;
2548         GstStructure* str = NULL;
2549         const gchar* name = NULL;
2550         GstPad* sinkpad = NULL;
2551         GstPad* srcpad = NULL;
2552         gboolean first_track = FALSE;
2553
2554         enum MainElementID elemId = MMPLAYER_M_NUM;
2555         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2556
2557         /* check handles */
2558         player = (mm_player_t*)data;
2559
2560         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2561         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2562
2563         //LOGD("pad-added signal handling\n");
2564
2565         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2566
2567         /* get mimetype from caps */
2568         caps = gst_pad_query_caps(pad, NULL);
2569         if (!caps) {
2570                 LOGE("cannot get caps from pad.\n");
2571                 goto ERROR;
2572         }
2573
2574         str = gst_caps_get_structure(caps, 0);
2575         if (!str) {
2576                 LOGE("cannot get structure from caps.\n");
2577                 goto ERROR;
2578         }
2579
2580         name = gst_structure_get_name(str);
2581         if (!name) {
2582                 LOGE("cannot get mimetype from structure.\n");
2583                 goto ERROR;
2584         }
2585
2586         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2587         //LOGD("detected mimetype : %s\n", name);
2588
2589         if (strstr(name, "video")) {
2590                 gint stype = 0;
2591                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2592
2593                 /* don't make video because of not required, and not support multiple track */
2594                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2595                         LOGD("no video sink by null surface");
2596                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2597                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2598                                         == MM_ERROR_NONE) {
2599                                 /* acquire resources for video playing */
2600                                 if (resource_state == RESOURCE_STATE_PREPARED) {
2601                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2602                                                         != MM_ERROR_NONE) {
2603                                                 LOGE("could not acquire resources for video playing\n");
2604                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2605                                                 goto ERROR;
2606                                         }
2607                                 }
2608                         }
2609
2610                         gchar *caps_str = gst_caps_to_string(caps);
2611                         if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2612                                 player->set_mode.video_zc = TRUE;
2613
2614                         MMPLAYER_FREEIF(caps_str);
2615
2616                         if (player->v_stream_caps) {
2617                                 gst_caps_unref(player->v_stream_caps);
2618                                 player->v_stream_caps = NULL;
2619                         }
2620
2621                         LOGD("create fakesink instead of videobin");
2622
2623                         /* fake sink */
2624                         fakesink = gst_element_factory_make("fakesink", NULL);
2625                         if (fakesink == NULL) {
2626                                 LOGE("ERROR : fakesink create error\n");
2627                                 goto ERROR;
2628                         }
2629
2630                         if (player->ini.set_dump_element_flag)
2631                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2632
2633                         player->video_fakesink = fakesink;
2634
2635                         /* store it as it's sink element */
2636                         __mmplayer_add_sink(player, player->video_fakesink);
2637
2638                         gst_bin_add(GST_BIN(pipeline), fakesink);
2639
2640                         // link
2641                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2642
2643                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2644                                 LOGW("failed to link fakesink\n");
2645                                 gst_object_unref(GST_OBJECT(fakesink));
2646                                 goto ERROR;
2647                         }
2648
2649                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2650                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2651                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2652                         }
2653
2654                         if (player->set_mode.media_packet_video_stream) {
2655                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2656
2657                                 MMPLAYER_SIGNAL_CONNECT(player,
2658                                                                                 G_OBJECT(fakesink),
2659                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2660                                                                                 "handoff",
2661                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2662                                                                                 (gpointer)player);
2663
2664                                 MMPLAYER_SIGNAL_CONNECT(player,
2665                                                                                 G_OBJECT(fakesink),
2666                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2667                                                                                 "preroll-handoff",
2668                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2669                                                                                 (gpointer)player);
2670                         }
2671
2672                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2673                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2674                         goto DONE;
2675                 }
2676
2677                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2678                         __mmplayer_gst_decode_callback(elem, pad, player);
2679                         return;
2680                 }
2681
2682                 LOGD("video selector \n");
2683                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2684                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2685         } else {
2686                 if (strstr(name, "audio")) {
2687                         gint samplerate = 0;
2688                         gint channels = 0;
2689
2690                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2691                                 __mmplayer_gst_decode_callback(elem, pad, player);
2692                                 return;
2693                         }
2694
2695                         LOGD("audio selector \n");
2696                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2697                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2698
2699                         gst_structure_get_int(str, "rate", &samplerate);
2700                         gst_structure_get_int(str, "channels", &channels);
2701
2702                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2703                                 /* fake sink */
2704                                 fakesink = gst_element_factory_make("fakesink", NULL);
2705                                 if (fakesink == NULL) {
2706                                         LOGE("ERROR : fakesink create error\n");
2707                                         goto ERROR;
2708                                 }
2709
2710                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2711
2712                                 /* link */
2713                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2714
2715                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2716                                         LOGW("failed to link fakesink\n");
2717                                         gst_object_unref(GST_OBJECT(fakesink));
2718                                         goto ERROR;
2719                                 }
2720
2721                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2722                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2723                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2724
2725                                 goto DONE;
2726                         }
2727                 } else if (strstr(name, "text")) {
2728                         LOGD("text selector \n");
2729                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2730                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2731                 } else {
2732                         LOGE("wrong elem id \n");
2733                         goto ERROR;
2734                 }
2735         }
2736
2737         selector = player->pipeline->mainbin[elemId].gst;
2738         if (selector == NULL) {
2739                 selector = gst_element_factory_make("input-selector", NULL);
2740                 LOGD("Creating input-selector\n");
2741                 if (selector == NULL) {
2742                         LOGE("ERROR : input-selector create error\n");
2743                         goto ERROR;
2744                 }
2745                 g_object_set(selector, "sync-streams", TRUE, NULL);
2746
2747                 player->pipeline->mainbin[elemId].id = elemId;
2748                 player->pipeline->mainbin[elemId].gst = selector;
2749
2750                 first_track = TRUE;
2751                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2752
2753                 srcpad = gst_element_get_static_pad(selector, "src");
2754
2755                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2756                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2757                         __mmplayer_gst_selector_blocked, NULL, NULL);
2758                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2759                         __mmplayer_gst_selector_event_probe, player, NULL);
2760
2761                 gst_element_set_state(selector, GST_STATE_PAUSED);
2762                 gst_bin_add(GST_BIN(pipeline), selector);
2763         } else
2764                 LOGD("input-selector is already created.\n");
2765
2766         // link
2767         LOGD("Calling request pad with selector %p \n", selector);
2768         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2769
2770         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2771
2772         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2773                 LOGW("failed to link selector\n");
2774                 gst_object_unref(GST_OBJECT(selector));
2775                 goto ERROR;
2776         }
2777
2778         if (first_track) {
2779                 LOGD("this is first track --> active track \n");
2780                 g_object_set(selector, "active-pad", sinkpad, NULL);
2781         }
2782
2783         _mmplayer_track_update_info(player, stream_type, sinkpad);
2784
2785
2786 DONE:
2787 ERROR:
2788
2789         if (caps)
2790                 gst_caps_unref(caps);
2791
2792         if (sinkpad) {
2793                 gst_object_unref(GST_OBJECT(sinkpad));
2794                 sinkpad = NULL;
2795         }
2796
2797         if (srcpad) {
2798                 gst_object_unref(GST_OBJECT(srcpad));
2799                 srcpad = NULL;
2800         }
2801
2802         return;
2803 }
2804
2805 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2806 {
2807         GstPad* srcpad = NULL;
2808         MMHandleType attrs = 0;
2809         gint active_index = 0;
2810
2811         // [link] input-selector :: textbin
2812         srcpad = gst_element_get_static_pad(text_selector, "src");
2813         if (!srcpad) {
2814                 LOGE("failed to get srcpad from selector\n");
2815                 return;
2816         }
2817
2818         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2819
2820         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2821         if ((active_index != DEFAULT_TRACK) &&
2822                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2823                 LOGW("failed to change text track\n");
2824                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2825         }
2826
2827         player->no_more_pad = TRUE;
2828         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2829
2830         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2831         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2832                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2833                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2834         }
2835
2836         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2837
2838         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2839                 player->has_closed_caption = TRUE;
2840
2841         attrs = MMPLAYER_GET_ATTRS(player);
2842         if (attrs) {
2843                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2844                 if (mmf_attrs_commit(attrs))
2845                         LOGE("failed to commit.\n");
2846         } else
2847                 LOGE("cannot get content attribute");
2848
2849         if (srcpad) {
2850                 gst_object_unref(GST_OBJECT(srcpad));
2851                 srcpad = NULL;
2852         }
2853 }
2854
2855 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2856 {
2857         int result = MM_ERROR_NONE;
2858
2859         mm_player_t* player = (mm_player_t*)hplayer;
2860         MMPlayerGstElement* mainbin = NULL;
2861         gchar* change_pad_name = NULL;
2862         GstPad* sinkpad = NULL;
2863         GstCaps* caps = NULL;
2864
2865         MMPLAYER_FENTER();
2866
2867         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2868
2869         LOGD("Change Audio mode to %d\n", ch_idx);
2870         player->use_deinterleave = TRUE;
2871
2872         if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2873                 LOGD("pre setting : %d\n", ch_idx);
2874
2875                 player->audio_mode.active_pad_index = ch_idx;
2876                 return result;
2877         }
2878
2879         mainbin = player->pipeline->mainbin;
2880
2881         if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2882                 if (player->max_audio_channels < 2) {
2883                         LOGD("mono channel track only\n");
2884                         return result;
2885                 }
2886
2887                 LOGW("selector doesn't exist\n");
2888                 return result;  /* keep playing */
2889         }
2890
2891         LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2892
2893         if (player->audio_mode.total_track_num < 2) {
2894                 LOGW("there is no another audio path\n");
2895                 return result;  /* keep playing */
2896         }
2897
2898         if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2899                 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2900                 return result;  /* keep playing */
2901         }
2902
2903         /*To get the new pad from the selector*/
2904         change_pad_name = g_strdup_printf("sink%d", ch_idx);
2905         if (change_pad_name == NULL) {
2906                 LOGW("Pad does not exists\n");
2907                 goto ERROR;     /* keep playing */
2908         }
2909
2910         LOGD("new active pad name: %s\n", change_pad_name);
2911
2912         sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2913         if (sinkpad == NULL)
2914                 //result = MM_ERROR_PLAYER_INTERNAL;
2915                 goto ERROR;     /* keep playing */
2916
2917         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2918         g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2919
2920         caps = gst_pad_get_current_caps(sinkpad);
2921         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2922
2923         __mmplayer_set_audio_attrs(player, caps);
2924         player->audio_mode.active_pad_index = ch_idx;
2925
2926 ERROR:
2927
2928         if (sinkpad)
2929                 gst_object_unref(sinkpad);
2930
2931         MMPLAYER_FREEIF(change_pad_name);
2932
2933         MMPLAYER_FLEAVE();
2934         return result;
2935 }
2936
2937
2938
2939 static void
2940 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2941 {
2942         mm_player_t* player = (mm_player_t*)data;
2943         GstElement* selector = NULL;
2944         GstElement* queue = NULL;
2945
2946         GstPad* srcpad = NULL;
2947         GstPad* sinkpad = NULL;
2948         gchar* caps_str = NULL;
2949
2950         MMPLAYER_FENTER();
2951         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2952
2953         caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2954         LOGD("deinterleave new caps : %s\n", caps_str);
2955         MMPLAYER_FREEIF(caps_str);
2956
2957         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2958                 LOGE("ERROR : queue create error\n");
2959                 goto ERROR;
2960         }
2961
2962         g_object_set(G_OBJECT(queue),
2963                                 "max-size-buffers", 10,
2964                                 "max-size-bytes", 0,
2965                                 "max-size-time", (guint64)0,
2966                                 NULL);
2967
2968         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2969
2970         if (!selector) {
2971                 LOGE("there is no audio channel selector.\n");
2972                 goto ERROR;
2973         }
2974
2975         srcpad = gst_element_get_static_pad(queue, "src");
2976         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2977
2978         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2979
2980         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2981                 LOGW("failed to link deinterleave - selector\n");
2982                 goto ERROR;
2983         }
2984
2985         gst_element_set_state(queue, GST_STATE_PAUSED);
2986         player->audio_mode.total_track_num++;
2987
2988 ERROR:
2989
2990         if (srcpad) {
2991                 gst_object_unref(GST_OBJECT(srcpad));
2992                 srcpad = NULL;
2993         }
2994
2995         if (sinkpad) {
2996                 gst_object_unref(GST_OBJECT(sinkpad));
2997                 sinkpad = NULL;
2998         }
2999
3000         MMPLAYER_FLEAVE();
3001         return;
3002 }
3003
3004 static void
3005 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
3006 {
3007         mm_player_t* player = NULL;
3008         GstElement* selector = NULL;
3009         GstPad* sinkpad = NULL;
3010         gint active_index = 0;
3011         gchar* change_pad_name = NULL;
3012         GstCaps* caps = NULL;   // no need to unref
3013         gint default_audio_ch = 0;
3014
3015         MMPLAYER_FENTER();
3016         player = (mm_player_t*) data;
3017
3018         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3019
3020         if (!selector) {
3021                 LOGE("there is no audio channel selector.\n");
3022                 goto ERROR;
3023         }
3024
3025         active_index = player->audio_mode.active_pad_index;
3026
3027         if (active_index != default_audio_ch) {
3028                 gint audio_ch = default_audio_ch;
3029
3030                 /*To get the new pad from the selector*/
3031                 change_pad_name = g_strdup_printf("sink%d", active_index);
3032                 if (change_pad_name != NULL) {
3033                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3034                         if (sinkpad != NULL) {
3035                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3036                                 g_object_set(selector, "active-pad", sinkpad, NULL);
3037
3038                                 audio_ch = active_index;
3039
3040                                 caps = gst_pad_get_current_caps(sinkpad);
3041                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3042
3043                                 __mmplayer_set_audio_attrs(player, caps);
3044                         }
3045                         MMPLAYER_FREEIF(change_pad_name);
3046                 }
3047
3048                 player->audio_mode.active_pad_index = audio_ch;
3049                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3050         }
3051
3052 ERROR:
3053
3054         if (sinkpad)
3055                 gst_object_unref(sinkpad);
3056
3057         MMPLAYER_FLEAVE();
3058         return;
3059 }
3060
3061 static void
3062 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3063 {
3064         mm_player_t* player = NULL;
3065         MMPlayerGstElement *mainbin = NULL;
3066
3067         GstElement* tee = NULL;
3068         GstElement* stereo_queue = NULL;
3069         GstElement* mono_queue = NULL;
3070         GstElement* conv = NULL;
3071         GstElement* filter = NULL;
3072         GstElement* deinterleave = NULL;
3073         GstElement* selector = NULL;
3074
3075         GstPad* srcpad = NULL;
3076         GstPad* selector_srcpad = NULL;
3077         GstPad* sinkpad = NULL;
3078         GstCaps* caps = NULL;
3079         gulong block_id = 0;
3080
3081         MMPLAYER_FENTER();
3082
3083         /* check handles */
3084         player = (mm_player_t*) data;
3085
3086         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3087         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3088
3089         mainbin = player->pipeline->mainbin;
3090
3091         /* tee */
3092         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3093                 LOGE("ERROR : tee create error\n");
3094                 goto ERROR;
3095         }
3096
3097         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3098         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3099
3100         gst_element_set_state(tee, GST_STATE_PAUSED);
3101
3102         /* queue */
3103         srcpad = gst_element_get_request_pad(tee, "src_%u");
3104         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3105                 LOGE("ERROR : stereo queue create error\n");
3106                 goto ERROR;
3107         }
3108
3109         g_object_set(G_OBJECT(stereo_queue),
3110                                 "max-size-buffers", 10,
3111                                 "max-size-bytes", 0,
3112                                 "max-size-time", (guint64)0,
3113                                 NULL);
3114
3115         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3116         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3117
3118         if (srcpad) {
3119                 gst_object_unref(GST_OBJECT(srcpad));
3120                 srcpad = NULL;
3121         }
3122
3123         srcpad = gst_element_get_request_pad(tee, "src_%u");
3124
3125         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3126                 LOGE("ERROR : mono queue create error\n");
3127                 goto ERROR;
3128         }
3129
3130         g_object_set(G_OBJECT(mono_queue),
3131                                 "max-size-buffers", 10,
3132                                 "max-size-bytes", 0,
3133                                 "max-size-time", (guint64)0,
3134                                 NULL);
3135
3136         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3137         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3138
3139         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3140         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3141
3142         /* audioconvert */
3143         srcpad = gst_element_get_static_pad(mono_queue, "src");
3144         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3145                 LOGE("ERROR : audioconvert create error\n");
3146                 goto ERROR;
3147         }
3148
3149         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3150         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3151
3152         /* caps filter */
3153         if (srcpad) {
3154                 gst_object_unref(GST_OBJECT(srcpad));
3155                 srcpad = NULL;
3156         }
3157         srcpad = gst_element_get_static_pad(conv, "src");
3158
3159         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3160                 LOGE("ERROR : capsfilter create error\n");
3161                 goto ERROR;
3162         }
3163
3164         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3165         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3166
3167         caps = gst_caps_from_string("audio/x-raw-int, "
3168                                 "width = (int) 16, "
3169                                 "depth = (int) 16, "
3170                                 "channels = (int) 2");
3171
3172         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3173         gst_caps_unref(caps);
3174
3175         gst_element_set_state(conv, GST_STATE_PAUSED);
3176         gst_element_set_state(filter, GST_STATE_PAUSED);
3177
3178         /* deinterleave */
3179         if (srcpad) {
3180                 gst_object_unref(GST_OBJECT(srcpad));
3181                 srcpad = NULL;
3182         }
3183         srcpad = gst_element_get_static_pad(filter, "src");
3184
3185         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3186                 LOGE("ERROR : deinterleave create error\n");
3187                 goto ERROR;
3188         }
3189
3190         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3191
3192         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3193                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3194
3195         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3196                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3197
3198         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3199         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3200
3201         /* selector */
3202         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3203         if (selector == NULL) {
3204                 LOGE("ERROR : audio-selector create error\n");
3205                 goto ERROR;
3206         }
3207
3208         g_object_set(selector, "sync-streams", TRUE, NULL);
3209         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3210
3211         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3212         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3213
3214         selector_srcpad = gst_element_get_static_pad(selector, "src");
3215
3216         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3217         block_id =
3218                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3219                         __mmplayer_gst_selector_blocked, NULL, NULL);
3220
3221         if (srcpad) {
3222                 gst_object_unref(GST_OBJECT(srcpad));
3223                 srcpad = NULL;
3224         }
3225
3226         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3227         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3228
3229         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3230                 LOGW("failed to link queue_stereo - selector\n");
3231                 goto ERROR;
3232         }
3233
3234         player->audio_mode.total_track_num++;
3235
3236         g_object_set(selector, "active-pad", sinkpad, NULL);
3237         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3238         gst_element_set_state(selector, GST_STATE_PAUSED);
3239
3240         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3241
3242 ERROR:
3243
3244         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3245         if (block_id != 0) {
3246                 gst_pad_remove_probe(selector_srcpad, block_id);
3247                 block_id = 0;
3248         }
3249
3250         if (sinkpad) {
3251                 gst_object_unref(GST_OBJECT(sinkpad));
3252                 sinkpad = NULL;
3253         }
3254
3255         if (srcpad) {
3256                 gst_object_unref(GST_OBJECT(srcpad));
3257                 srcpad = NULL;
3258         }
3259
3260         if (selector_srcpad) {
3261                 gst_object_unref(GST_OBJECT(selector_srcpad));
3262                 selector_srcpad = NULL;
3263         }
3264
3265         MMPLAYER_FLEAVE();
3266         return;
3267 }
3268
3269 static void
3270 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3271 {
3272         mm_player_t* player = NULL;
3273         GstPad* srcpad = NULL;
3274         GstElement* video_selector = NULL;
3275         GstElement* audio_selector = NULL;
3276         GstElement* text_selector = NULL;
3277         MMHandleType attrs = 0;
3278         gint active_index = 0;
3279         gint64 dur_bytes = 0L;
3280
3281         player = (mm_player_t*) data;
3282
3283         LOGD("no-more-pad signal handling\n");
3284
3285         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3286                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3287                 LOGW("no need to go more");
3288
3289                 if (player->gapless.reconfigure) {
3290                         player->gapless.reconfigure = FALSE;
3291                         MMPLAYER_PLAYBACK_UNLOCK(player);
3292                 }
3293
3294                 return;
3295         }
3296
3297         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3298                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3299                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3300                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3301                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3302
3303                 if (NULL == player->streamer) {
3304                         LOGW("invalid state for buffering");
3305                         goto ERROR;
3306                 }
3307
3308                 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3309                 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3310
3311                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3312                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3313
3314                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3315
3316                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3317                         LOGE("fail to get duration.\n");
3318
3319                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3320                 // use file information was already set on Q2 when it was created.
3321                 __mm_player_streaming_set_queue2(player->streamer,
3322                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3323                                                 TRUE,                                                           // use_buffering
3324                                                 buffer_bytes,
3325                                                 init_buffering_time,
3326                                                 1.0,                                                            // low percent
3327                                                 player->ini.http_buffering_limit,       // high percent
3328                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3329                                                 NULL,
3330                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3331         }
3332
3333         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3334         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3335         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3336         if (video_selector) {
3337                 // [link] input-selector :: videobin
3338                 srcpad = gst_element_get_static_pad(video_selector, "src");
3339                 if (!srcpad) {
3340                         LOGE("failed to get srcpad from video selector\n");
3341                         goto ERROR;
3342                 }
3343
3344                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3345                 if (!text_selector && !audio_selector)
3346                         player->no_more_pad = TRUE;
3347
3348                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3349
3350                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3351                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3352                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3353                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3354                 }
3355         }
3356
3357         if (audio_selector) {
3358                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3359                 if ((active_index != DEFAULT_TRACK) &&
3360                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3361                         LOGW("failed to change audio track\n");
3362                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3363                 }
3364
3365                 // [link] input-selector :: audiobin
3366                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3367                 if (!srcpad) {
3368                         LOGE("failed to get srcpad from selector\n");
3369                         goto ERROR;
3370                 }
3371
3372                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3373                 if (!text_selector)
3374                         player->no_more_pad = TRUE;
3375
3376                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3377                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3378                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3379                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3380                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3381                         }
3382
3383                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3384                 } else {
3385                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3386
3387                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3388                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3389                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3390                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3391                         }
3392                 }
3393
3394                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3395
3396                 attrs = MMPLAYER_GET_ATTRS(player);
3397                 if (attrs) {
3398                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3399                         if (mmf_attrs_commit(attrs))
3400                                 LOGE("failed to commit.\n");
3401                 } else
3402                         LOGE("cannot get content attribute");
3403         } else {
3404                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3405                         LOGD("There is no audio track : remove audiobin");
3406
3407                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3408                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3409
3410                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3411                         MMPLAYER_FREEIF(player->pipeline->audiobin)
3412                 }
3413
3414                 if (player->num_dynamic_pad == 0)
3415                         __mmplayer_pipeline_complete(NULL, player);
3416         }
3417
3418         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3419                 if (text_selector)
3420                         __mmplayer_handle_text_decode_path(player, text_selector);
3421         }
3422
3423         MMPLAYER_FLEAVE();
3424
3425 ERROR:
3426         if (srcpad) {
3427                 gst_object_unref(GST_OBJECT(srcpad));
3428                 srcpad = NULL;
3429         }
3430
3431         if (player->gapless.reconfigure) {
3432                 player->gapless.reconfigure = FALSE;
3433                 MMPLAYER_PLAYBACK_UNLOCK(player);
3434         }
3435 }
3436
3437 static void
3438 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3439 {
3440         mm_player_t* player = NULL;
3441         MMHandleType attrs = 0;
3442         GstElement* pipeline = NULL;
3443         GstCaps* caps = NULL;
3444         gchar* caps_str = NULL;
3445         GstStructure* str = NULL;
3446         const gchar* name = NULL;
3447         GstPad* sinkpad = NULL;
3448         GstElement* sinkbin = NULL;
3449         gboolean reusing = FALSE;
3450         GstElement *text_selector = NULL;
3451         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3452
3453         /* check handles */
3454         player = (mm_player_t*) data;
3455
3456         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3457         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3458
3459         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3460
3461         attrs = MMPLAYER_GET_ATTRS(player);
3462         if (!attrs) {
3463                 LOGE("cannot get content attribute\n");
3464                 goto ERROR;
3465         }
3466
3467         /* get mimetype from caps */
3468         caps = gst_pad_query_caps(pad, NULL);
3469         if (!caps) {
3470                 LOGE("cannot get caps from pad.\n");
3471                 goto ERROR;
3472         }
3473         caps_str = gst_caps_to_string(caps);
3474
3475         str = gst_caps_get_structure(caps, 0);
3476         if (!str) {
3477                 LOGE("cannot get structure from caps.\n");
3478                 goto ERROR;
3479         }
3480
3481         name = gst_structure_get_name(str);
3482         if (!name) {
3483                 LOGE("cannot get mimetype from structure.\n");
3484                 goto ERROR;
3485         }
3486
3487         //LOGD("detected mimetype : %s\n", name);
3488
3489         if (strstr(name, "audio")) {
3490                 if (player->pipeline->audiobin == NULL) {
3491                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3492                                 LOGE("failed to create audiobin. continuing without audio\n");
3493                                 goto ERROR;
3494                         }
3495
3496                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3497                         LOGD("creating audiosink bin success\n");
3498                 } else {
3499                         reusing = TRUE;
3500                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3501                         LOGD("reusing audiobin\n");
3502                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3503                 }
3504
3505                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3506                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3507
3508                 player->audiosink_linked  = 1;
3509
3510                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3511                 if (!sinkpad) {
3512                         LOGE("failed to get pad from sinkbin\n");
3513                         goto ERROR;
3514                 }
3515         } else if (strstr(name, "video")) {
3516                 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3517                         player->set_mode.video_zc = TRUE;
3518
3519                 if (player->pipeline->videobin == NULL) {
3520                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3521                         /* get video surface type */
3522                         int surface_type = 0;
3523                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3524                         LOGD("display_surface_type(%d)\n", surface_type);
3525
3526                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3527                                 LOGD("not make videobin because it dose not want\n");
3528                                 goto ERROR;
3529                         }
3530
3531                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3532                                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3533                                         /* prepare resource manager for video overlay */
3534                                         if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3535                                                 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3536                                                         != MM_ERROR_NONE) {
3537                                                         LOGE("could not prepare for video_overlay resource\n");
3538                                                         goto ERROR;
3539                                                 }
3540                                         }
3541                                 }
3542                         }
3543
3544                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3545                                 == MM_ERROR_NONE) {
3546                                 /* acquire resources for video playing */
3547                                 if (resource_state == RESOURCE_STATE_PREPARED) {
3548                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3549                                                 != MM_ERROR_NONE) {
3550                                                 LOGE("could not acquire resources for video playing\n");
3551                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3552                                                 goto ERROR;
3553                                         }
3554                                 }
3555                         }
3556
3557                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3558                                 LOGE("failed to create videobin. continuing without video\n");
3559                                 goto ERROR;
3560                         }
3561
3562                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3563                         LOGD("creating videosink bin success\n");
3564                 } else {
3565                         reusing = TRUE;
3566                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3567                         LOGD("re-using videobin\n");
3568                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3569                 }
3570
3571                 /* FIXIT : track number shouldn't be hardcoded */
3572                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3573                 player->videosink_linked  = 1;
3574
3575                 /* NOTE : intermediate code before doing H/W subtitle compositon */
3576                 if (player->use_textoverlay && player->play_subtitle) {
3577                         LOGD("using textoverlay for external subtitle");
3578                         /* check text bin has created well */
3579                         if (player->pipeline && player->pipeline->textbin) {
3580                                 /* get sinkpad from textoverlay */
3581                                 sinkpad = gst_element_get_static_pad(
3582                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3583                                         "video_sink");
3584                                 if (!sinkpad) {
3585                                         LOGE("failed to get sink pad from textoverlay");
3586                                         goto ERROR;
3587                                 }
3588
3589                                 /* link new pad with textoverlay first */
3590                                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3591                                         LOGE("failed to get pad from sinkbin\n");
3592                                         goto ERROR;
3593                                 }
3594
3595                                 gst_object_unref(sinkpad);
3596                                 sinkpad = NULL;
3597
3598                                 /* alright, override pad to textbin.src for futher link */
3599                                 pad = gst_element_get_static_pad(
3600                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3601                                         "src");
3602                                 if (!pad) {
3603                                         LOGE("failed to get sink pad from textoverlay");
3604                                         goto ERROR;
3605                                 }
3606                         } else {
3607                                 LOGE("should not reach here.");
3608                                 goto ERROR;
3609                         }
3610                 }
3611
3612                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3613                 if (!sinkpad) {
3614                         LOGE("failed to get pad from sinkbin\n");
3615                         goto ERROR;
3616                 }
3617         } else if (strstr(name, "text")) {
3618                 if (player->pipeline->textbin == NULL) {
3619                         MMPlayerGstElement* mainbin = NULL;
3620
3621                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
3622                                 LOGE("failed to create textbin. continuing without text\n");
3623                                 goto ERROR;
3624                         }
3625
3626                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3627                         LOGD("creating textsink bin success\n");
3628
3629                         /* FIXIT : track number shouldn't be hardcoded */
3630                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3631
3632                         player->textsink_linked  = 1;
3633                         LOGI("player->textsink_linked set to 1\n");
3634
3635                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3636                         if (!sinkpad) {
3637                                 LOGE("failed to get pad from sinkbin\n");
3638                                 goto ERROR;
3639                         }
3640
3641                         mainbin = player->pipeline->mainbin;
3642
3643                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3644                                 /* input selector */
3645                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3646                                 if (!text_selector) {
3647                                         LOGE("failed to create subtitle input selector element\n");
3648                                         goto ERROR;
3649                                 }
3650                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3651
3652                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3653                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3654
3655                                 /* warm up */
3656                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3657                                         LOGE("failed to set state(READY) to sinkbin\n");
3658                                         goto ERROR;
3659                                 }
3660
3661                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3662                                         LOGW("failed to add subtitle input selector\n");
3663                                         goto ERROR;
3664                                 }
3665
3666                                 LOGD("created element input-selector");
3667
3668                         } else {
3669                                 LOGD("already having subtitle input selector");
3670                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3671                         }
3672                 } else {
3673                         if (!player->textsink_linked) {
3674                                 LOGD("re-using textbin\n");
3675
3676                                 reusing = TRUE;
3677                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3678
3679                                 player->textsink_linked  = 1;
3680                                 LOGI("player->textsink_linked set to 1\n");
3681                         } else
3682                                 LOGD("ignoring internal subtutle since external subtitle is available");
3683                 }
3684         } else {
3685                 LOGW("unknown type of elementary stream!ignoring it...\n");
3686                 goto ERROR;
3687         }
3688
3689         if (sinkbin) {
3690                 if (!reusing) {
3691                         /* warm up */
3692                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3693                                 LOGE("failed to set state(READY) to sinkbin\n");
3694                                 goto ERROR;
3695                         }
3696
3697                         /* Added for multi audio support to avoid adding audio bin again*/
3698                         /* add */
3699                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3700                                 LOGE("failed to add sinkbin to pipeline\n");
3701                                 goto ERROR;
3702                         }
3703                 }
3704
3705                 /* link */
3706                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3707                         LOGE("failed to get pad from sinkbin\n");
3708                         goto ERROR;
3709                 }
3710
3711                 if (!reusing) {
3712                         /* run */
3713                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3714                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3715                                 goto ERROR;
3716                         }
3717
3718                         if (text_selector) {
3719                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3720                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3721                                         goto ERROR;
3722                                 }
3723                         }
3724                 }
3725
3726                 gst_object_unref(sinkpad);
3727                 sinkpad = NULL;
3728         }
3729
3730         LOGD("linking sink bin success\n");
3731
3732         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3733          * streaming task. if the task blocked, then buffer will not flow to the next element
3734          *(autoplugging element). so this is special hack for streaming. please try to remove it
3735          */
3736         /* dec stream count. we can remove fakesink if it's zero */
3737         if (player->num_dynamic_pad)
3738                 player->num_dynamic_pad--;
3739
3740         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3741
3742         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3743                 __mmplayer_pipeline_complete(NULL, player);
3744
3745         /* FIXIT : please leave a note why this code is needed */
3746         if (MMPLAYER_IS_WFD_STREAMING(player))
3747                 player->no_more_pad = TRUE;
3748
3749 ERROR:
3750
3751         MMPLAYER_FREEIF(caps_str);
3752
3753         if (caps)
3754                 gst_caps_unref(caps);
3755
3756         if (sinkpad)
3757                 gst_object_unref(GST_OBJECT(sinkpad));
3758
3759         /* flusing out new attributes */
3760         if (mmf_attrs_commit(attrs))
3761                 LOGE("failed to comit attributes\n");
3762
3763         return;
3764 }
3765
3766 static gboolean
3767 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3768 {
3769         int pro_value = 0; // in the case of expection, default will be returned.
3770         int dest_angle = rotation_angle;
3771         int rotation_type = -1;
3772
3773         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3774         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3775         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3776
3777         if (rotation_angle >= 360)
3778                 dest_angle = rotation_angle - 360;
3779
3780         /* chech if supported or not */
3781         if (dest_angle % 90) {
3782                 LOGD("not supported rotation angle = %d", rotation_angle);
3783                 return FALSE;
3784         }
3785
3786         /*
3787           * waylandsink (A)
3788           * custom_convert - none (B)
3789           * videoflip - none (C)
3790           */
3791         if (player->set_mode.video_zc) {
3792                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3793                         rotation_type = ROTATION_USING_CUSTOM;
3794                 else // A
3795                         rotation_type = ROTATION_USING_SINK;
3796         } else {
3797                 int surface_type = 0;
3798                 rotation_type = ROTATION_USING_FLIP;
3799
3800                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3801                 LOGD("check display surface type attribute: %d", surface_type);
3802
3803                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3804                         rotation_type = ROTATION_USING_SINK;
3805                 else
3806                         rotation_type = ROTATION_USING_FLIP; //C
3807
3808                 LOGD("using %d type for rotation", rotation_type);
3809         }
3810
3811         /* get property value for setting */
3812         switch (rotation_type) {
3813         case ROTATION_USING_SINK: // waylandsink
3814                 {
3815                         switch (dest_angle) {
3816                         case 0:
3817                                 break;
3818                         case 90:
3819                                 pro_value = 3; // clockwise 90
3820                                 break;
3821                         case 180:
3822                                 pro_value = 2;
3823                                 break;
3824                         case 270:
3825                                 pro_value = 1; // counter-clockwise 90
3826                                 break;
3827                         }
3828                 }
3829                 break;
3830         case ROTATION_USING_CUSTOM:
3831                 {
3832                         gchar *ename = NULL;
3833                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3834
3835                         if (g_strrstr(ename, "fimcconvert")) {
3836                                 switch (dest_angle) {
3837                                 case 0:
3838                                         break;
3839                                 case 90:
3840                                         pro_value = 90; // clockwise 90
3841                                         break;
3842                                 case 180:
3843                                         pro_value = 180;
3844                                         break;
3845                                 case 270:
3846                                         pro_value = 270; // counter-clockwise 90
3847                                         break;
3848                                 }
3849                         }
3850                 }
3851                 break;
3852         case ROTATION_USING_FLIP: // videoflip
3853                 {
3854                                 switch (dest_angle) {
3855                                 case 0:
3856                                         break;
3857                                 case 90:
3858                                         pro_value = 1; // clockwise 90
3859                                         break;
3860                                 case 180:
3861                                         pro_value = 2;
3862                                         break;
3863                                 case 270:
3864                                         pro_value = 3; // counter-clockwise 90
3865                                         break;
3866                                 }
3867                 }
3868                 break;
3869         }
3870
3871         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3872
3873         *value = pro_value;
3874
3875         return TRUE;
3876 }
3877
3878 int
3879 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3880 {
3881         /* check video sinkbin is created */
3882         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3883                 player->pipeline &&
3884                 player->pipeline->videobin &&
3885                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3886                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3887                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3888
3889         return MM_ERROR_NONE;
3890 }
3891
3892 void
3893 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3894 {
3895         int rotation_value = 0;
3896         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3897         int user_angle = 0;
3898         MMPLAYER_FENTER();
3899
3900         /* check video sinkbin is created */
3901         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3902                 return;
3903
3904         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3905
3906         /* get rotation value to set */
3907         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3908         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3909         LOGD("set video param : rotate %d", rotation_value);
3910 }
3911
3912 void
3913 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3914 {
3915         MMHandleType attrs = 0;
3916         int visible = 0;
3917         MMPLAYER_FENTER();
3918
3919         /* check video sinkbin is created */
3920         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3921                 return;
3922
3923         attrs = MMPLAYER_GET_ATTRS(player);
3924         MMPLAYER_RETURN_IF_FAIL(attrs);
3925
3926         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3927         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3928         LOGD("set video param : visible %d", visible);
3929 }
3930
3931 void
3932 __mmplayer_video_param_set_display_method(mm_player_t* player)
3933 {
3934         MMHandleType attrs = 0;
3935         int display_method = 0;
3936         MMPLAYER_FENTER();
3937
3938         /* check video sinkbin is created */
3939         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3940                 return;
3941
3942         attrs = MMPLAYER_GET_ATTRS(player);
3943         MMPLAYER_RETURN_IF_FAIL(attrs);
3944
3945         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3946         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3947         LOGD("set video param : method %d", display_method);
3948 }
3949
3950 void
3951 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3952 {
3953         MMHandleType attrs = 0;
3954         int display_method = 0;
3955         void *handle = NULL;
3956         /*set wl_display*/
3957         int wl_window_x = 0;
3958         int wl_window_y = 0;
3959         int wl_window_width = 0;
3960         int wl_window_height = 0;
3961         MMPLAYER_FENTER();
3962
3963         /* check video sinkbin is created */
3964         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3965                 return;
3966
3967         attrs = MMPLAYER_GET_ATTRS(player);
3968         MMPLAYER_RETURN_IF_FAIL(attrs);
3969
3970         /* check roi mode is set */
3971         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3972         if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3973                 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3974                 return;
3975         }
3976         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3977
3978         if (handle) {
3979                 /*It should be set after setting window*/
3980                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3981                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3982                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3983                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3984
3985                 /* After setting window handle, set render      rectangle */
3986                 gst_video_overlay_set_render_rectangle(
3987                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3988                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3989                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3990                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3991
3992         }
3993 }
3994 void
3995 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3996 {
3997         MMHandleType attrs = 0;
3998         void *handle = NULL;
3999         /*use wl_surface*/
4000         gboolean use_wl_surface = 0;
4001         void * wl_display = NULL;
4002         GstContext *context = NULL;
4003
4004         /* check video sinkbin is created */
4005         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4006                 return;
4007
4008         attrs = MMPLAYER_GET_ATTRS(player);
4009         MMPLAYER_RETURN_IF_FAIL(attrs);
4010
4011         /* common case if using overlay surface */
4012         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
4013         mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
4014
4015         if (handle && !use_wl_surface) {
4016                 /* default is using wl_surface_id */
4017                 unsigned int wl_surface_id      = 0;
4018                 wl_surface_id = *(int*)handle;
4019                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
4020                 gst_video_overlay_set_wl_window_wl_surface_id(
4021                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4022                                 *(int*)handle);
4023         } else if (handle && use_wl_surface) {
4024                 /* use wl_surface for legacy_player_test */
4025                 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
4026                 if (wl_display)
4027                         context = gst_wayland_display_handle_context_new(wl_display);
4028                 if (context)
4029                         gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
4030
4031                 guintptr wl_surface = (guintptr)handle;
4032                 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
4033                 gst_video_overlay_set_window_handle(
4034                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4035                                 wl_surface);
4036         } else
4037                 /* FIXIT : is it error case? */
4038                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
4039 }
4040
4041
4042 int
4043 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
4044 {
4045         bool update_all_param = FALSE;
4046         MMPLAYER_FENTER();
4047
4048         /* check video sinkbin is created */
4049         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4050                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4051
4052         if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
4053                 LOGE("can not find waylandsink");
4054                 return MM_ERROR_PLAYER_INTERNAL;
4055         }
4056
4057         LOGD("param_name : %s", param_name);
4058         if (!g_strcmp0(param_name, "update_all_param"))
4059                 update_all_param = TRUE;
4060
4061         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
4062                 __mmplayer_video_param_set_display_overlay(player);
4063         if (update_all_param || !g_strcmp0(param_name, "display_method"))
4064                 __mmplayer_video_param_set_display_method(player);
4065         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
4066                 __mmplayer_video_param_set_render_rectangle(player);
4067         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
4068                 __mmplayer_video_param_set_display_visible(player);
4069         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4070                 __mmplayer_video_param_set_display_rotation(player);
4071
4072         return MM_ERROR_NONE;
4073 }
4074
4075 int
4076 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
4077 {
4078         MMHandleType attrs = 0;
4079         int surface_type = 0;
4080         int ret = MM_ERROR_NONE;
4081
4082         MMPLAYER_FENTER();
4083
4084         /* check video sinkbin is created */
4085         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4086                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4087
4088         attrs = MMPLAYER_GET_ATTRS(player);
4089         if (!attrs) {
4090                 LOGE("cannot get content attribute");
4091                 return MM_ERROR_PLAYER_INTERNAL;
4092         }
4093         LOGD("param_name : %s", param_name);
4094
4095         /* update display surface */
4096         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4097         LOGD("check display surface type attribute: %d", surface_type);
4098
4099         /* configuring display */
4100         switch (surface_type) {
4101         case MM_DISPLAY_SURFACE_OVERLAY:
4102                 {
4103                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4104                         if (ret != MM_ERROR_NONE)
4105                                 return ret;
4106                 }
4107                 break;
4108         }
4109
4110         MMPLAYER_FLEAVE();
4111
4112         return MM_ERROR_NONE;
4113 }
4114
4115 static int
4116 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4117 {
4118         GList* bucket = element_bucket;
4119         MMPlayerGstElement* element = NULL;
4120         MMPlayerGstElement* prv_element = NULL;
4121         gint successful_link_count = 0;
4122
4123         MMPLAYER_FENTER();
4124
4125         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4126
4127         prv_element = (MMPlayerGstElement*)bucket->data;
4128         bucket = bucket->next;
4129
4130         for (; bucket; bucket = bucket->next) {
4131                 element = (MMPlayerGstElement*)bucket->data;
4132
4133                 if (element && element->gst) {
4134                         /* If next element is audio appsrc then make a separate audio pipeline */
4135                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4136                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4137                                 prv_element = element;
4138                                 continue;
4139                         }
4140
4141                         if (prv_element && prv_element->gst) {
4142                                 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4143                                         LOGD("linking [%s] to [%s] success\n",
4144                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4145                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4146                                         successful_link_count++;
4147                                 } else {
4148                                         LOGD("linking [%s] to [%s] failed\n",
4149                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4150                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4151                                         return -1;
4152                                 }
4153                         }
4154                 }
4155
4156                 prv_element = element;
4157         }
4158
4159         MMPLAYER_FLEAVE();
4160
4161         return successful_link_count;
4162 }
4163
4164 static int
4165 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4166 {
4167         GList* bucket = element_bucket;
4168         MMPlayerGstElement* element = NULL;
4169         int successful_add_count = 0;
4170
4171         MMPLAYER_FENTER();
4172
4173         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4174         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4175
4176         for (; bucket; bucket = bucket->next) {
4177                 element = (MMPlayerGstElement*)bucket->data;
4178
4179                 if (element && element->gst) {
4180                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4181                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4182                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4183                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4184                                 return 0;
4185                         }
4186                         successful_add_count++;
4187                 }
4188         }
4189
4190         MMPLAYER_FLEAVE();
4191
4192         return successful_add_count;
4193 }
4194
4195 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4196 {
4197         mm_player_t* player = (mm_player_t*) data;
4198         GstCaps *caps = NULL;
4199         GstStructure *str = NULL;
4200         const char *name;
4201
4202         MMPLAYER_FENTER();
4203
4204         MMPLAYER_RETURN_IF_FAIL(pad)
4205         MMPLAYER_RETURN_IF_FAIL(unused)
4206         MMPLAYER_RETURN_IF_FAIL(data)
4207
4208         caps = gst_pad_get_current_caps(pad);
4209         if (!caps)
4210                 return;
4211
4212         str = gst_caps_get_structure(caps, 0);
4213         if (!str)
4214                 goto ERROR;
4215
4216         name = gst_structure_get_name(str);
4217         if (!name)
4218                 goto ERROR;
4219
4220         LOGD("name = %s\n", name);
4221
4222         if (strstr(name, "audio")) {
4223                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4224
4225                 if (player->audio_stream_changed_cb) {
4226                         LOGE("call the audio stream changed cb\n");
4227                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4228                 }
4229         } else if (strstr(name, "video")) {
4230                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4231
4232                 if (player->video_stream_changed_cb) {
4233                         LOGE("call the video stream changed cb\n");
4234                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4235                 }
4236         } else
4237                 goto ERROR;
4238
4239 ERROR:
4240
4241         gst_caps_unref(caps);
4242
4243         MMPLAYER_FLEAVE();
4244
4245         return;
4246 }
4247
4248
4249
4250 /**
4251  * This function is to create audio pipeline for playing.
4252  *
4253  * @param       player          [in]    handle of player
4254  *
4255  * @return      This function returns zero on success.
4256  * @remark
4257  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4258  */
4259 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4260 x_bin[x_id].id = x_id;\
4261 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4262 if (!x_bin[x_id].gst) {\
4263         LOGE("failed to create %s \n", x_factory);\
4264         goto ERROR;\
4265 } \
4266
4267 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4268 x_bin[x_id].id = x_id;\
4269 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4270 if (!x_bin[x_id].gst) {\
4271         LOGE("failed to create %s \n", x_factory);\
4272         goto ERROR;\
4273 } else {\
4274         if (x_player->ini.set_dump_element_flag)\
4275                 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4276 } \
4277 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4278         LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",\
4279                 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4280                 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4281         goto ERROR;\
4282 } \
4283
4284 /* macro for code readability. just for sinkbin-creation functions */
4285 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4286 do {\
4287         x_bin[x_id].id = x_id;\
4288         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4289         if (!x_bin[x_id].gst) {\
4290                 LOGE("failed to create %s \n", x_factory);\
4291                 goto ERROR;\
4292         } else {\
4293                 if (x_player->ini.set_dump_element_flag)\
4294                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4295         } \
4296         if (x_add_bucket)\
4297                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4298 } while (0);
4299
4300 static void
4301 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4302 {
4303         GList *l = NULL;
4304
4305         MMPLAYER_FENTER();
4306         MMPLAYER_RETURN_IF_FAIL(player);
4307
4308         if (player->audio_stream_buff_list) {
4309                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4310                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4311                         if (tmp) {
4312                                 if (send_all) {
4313                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4314                                         __mmplayer_audio_stream_send_data(player, tmp);
4315                                 }
4316                                 if (tmp->pcm_data)
4317                                         g_free(tmp->pcm_data);
4318                                 g_free(tmp);
4319                         }
4320                 }
4321                 g_list_free(player->audio_stream_buff_list);
4322                 player->audio_stream_buff_list = NULL;
4323         }
4324
4325         MMPLAYER_FLEAVE();
4326 }
4327
4328 static void
4329 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4330 {
4331         MMPlayerAudioStreamDataType audio_stream = { 0, };
4332
4333         MMPLAYER_FENTER();
4334         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4335
4336         audio_stream.bitrate = a_buffer->bitrate;
4337         audio_stream.channel = a_buffer->channel;
4338         audio_stream.depth = a_buffer->depth;
4339         audio_stream.is_little_endian = a_buffer->is_little_endian;
4340         audio_stream.channel_mask = a_buffer->channel_mask;
4341         audio_stream.data_size = a_buffer->data_size;
4342         audio_stream.data = a_buffer->pcm_data;
4343
4344         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4345         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4346
4347         MMPLAYER_FLEAVE();
4348 }
4349
4350 static void
4351 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4352 {
4353         mm_player_t* player = (mm_player_t*) data;
4354
4355         gint channel = 0;
4356         gint rate = 0;
4357         gint depth = 0;
4358         gint endianness = 0;
4359         guint64 channel_mask = 0;
4360         void *a_data = NULL;
4361         gint a_size = 0;
4362         mm_player_audio_stream_buff_t *a_buffer = NULL;
4363         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4364         GList *l = NULL;
4365
4366         MMPLAYER_FENTER();
4367         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4368
4369         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4370         a_data = mapinfo.data;
4371         a_size = mapinfo.size;
4372
4373         GstCaps *caps = gst_pad_get_current_caps(pad);
4374         GstStructure *structure = gst_caps_get_structure(caps, 0);
4375
4376         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4377         gst_structure_get_int(structure, "rate", &rate);
4378         gst_structure_get_int(structure, "channels", &channel);
4379         gst_structure_get_int(structure, "depth", &depth);
4380         gst_structure_get_int(structure, "endianness", &endianness);
4381         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4382         gst_caps_unref(GST_CAPS(caps));
4383
4384         /* In case of the sync is false, use buffer list.              *
4385          * The num of buffer list depends on the num of audio channels */
4386         if (player->audio_stream_buff_list) {
4387                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4388                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4389                         if (tmp) {
4390                                 if (channel_mask == tmp->channel_mask) {
4391                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4392                                         if (tmp->data_size + a_size < tmp->buff_size) {
4393                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4394                                                 tmp->data_size += a_size;
4395                                         } else {
4396                                                 /* send data to client */
4397                                                 __mmplayer_audio_stream_send_data(player, tmp);
4398
4399                                                 if (a_size > tmp->buff_size) {
4400                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4401                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4402                                                         if (tmp->pcm_data == NULL) {
4403                                                                 LOGE("failed to realloc data.");
4404                                                                 goto DONE;
4405                                                         }
4406                                                         tmp->buff_size = a_size;
4407                                                 }
4408                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4409                                                 memcpy(tmp->pcm_data, a_data, a_size);
4410                                                 tmp->data_size = a_size;
4411                                         }
4412                                         goto DONE;
4413                                 }
4414                         } else {
4415                                 LOGE("data is empty in list.");
4416                                 goto DONE;
4417                         }
4418                 }
4419         }
4420
4421         /* create new audio stream data */
4422         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4423         if (a_buffer == NULL) {
4424                 LOGE("failed to alloc data.");
4425                 goto DONE;
4426         }
4427         a_buffer->bitrate = rate;
4428         a_buffer->channel = channel;
4429         a_buffer->depth = depth;
4430         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4431         a_buffer->channel_mask = channel_mask;
4432         a_buffer->data_size = a_size;
4433
4434         if (!player->audio_stream_sink_sync) {
4435                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4436                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4437                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4438                 if (a_buffer->pcm_data == NULL) {
4439                         LOGE("failed to alloc data.");
4440                         g_free(a_buffer);
4441                         goto DONE;
4442                 }
4443                 memcpy(a_buffer->pcm_data, a_data, a_size);
4444                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4445                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4446         } else {
4447                 /* If sync is TRUE, send data directly. */
4448                 a_buffer->pcm_data = a_data;
4449                 __mmplayer_audio_stream_send_data(player, a_buffer);
4450                 g_free(a_buffer);
4451         }
4452
4453 DONE:
4454         gst_buffer_unmap(buffer, &mapinfo);
4455         MMPLAYER_FLEAVE();
4456 }
4457
4458 static void
4459 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4460 {
4461         mm_player_t* player = (mm_player_t*)data;
4462         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4463         GstPad* sinkpad = NULL;
4464         GstElement *queue = NULL, *sink = NULL;
4465
4466         MMPLAYER_FENTER();
4467         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4468
4469         queue = gst_element_factory_make("queue", NULL);
4470         if (queue == NULL) {
4471                 LOGD("fail make queue\n");
4472                 goto ERROR;
4473         }
4474
4475         sink = gst_element_factory_make("fakesink", NULL);
4476         if (sink == NULL) {
4477                 LOGD("fail make fakesink\n");
4478                 goto ERROR;
4479         }
4480
4481         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4482
4483         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4484                 LOGW("failed to link queue & sink\n");
4485                 goto ERROR;
4486         }
4487
4488         sinkpad = gst_element_get_static_pad(queue, "sink");
4489
4490         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4491                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4492                 goto ERROR;
4493         }
4494
4495         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4496
4497         gst_object_unref(sinkpad);
4498         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4499         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4500
4501         gst_element_set_state(sink, GST_STATE_PAUSED);
4502         gst_element_set_state(queue, GST_STATE_PAUSED);
4503
4504         MMPLAYER_SIGNAL_CONNECT(player,
4505                 G_OBJECT(sink),
4506                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4507                 "handoff",
4508                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4509                 (gpointer)player);
4510
4511         MMPLAYER_FLEAVE();
4512         return ;
4513
4514 ERROR:
4515         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4516         if (queue) {
4517                 gst_object_unref(GST_OBJECT(queue));
4518                 queue = NULL;
4519         }
4520         if (sink) {
4521                 gst_object_unref(GST_OBJECT(sink));
4522                 sink = NULL;
4523         }
4524         if (sinkpad) {
4525                 gst_object_unref(GST_OBJECT(sinkpad));
4526                 sinkpad = NULL;
4527         }
4528
4529         return;
4530 }
4531
4532 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4533 {
4534         #define MAX_PROPS_LEN 64
4535         gint latency_mode = 0;
4536         gchar *stream_type = NULL;
4537         gchar *latency = NULL;
4538         gint stream_id = 0;
4539         gchar stream_props[MAX_PROPS_LEN] = {0,};
4540         GstStructure *props = NULL;
4541
4542         /* set volume table
4543          * It should be set after player creation through attribute.
4544          * But, it can not be changed during playing.
4545          */
4546         MMPLAYER_FENTER();
4547         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4548         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4549
4550         if (!stream_type) {
4551                 LOGE("stream_type is null.\n");
4552         } else {
4553                 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4554                 props = gst_structure_from_string(stream_props, NULL);
4555                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4556                 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4557         }
4558
4559         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4560
4561         switch (latency_mode) {
4562         case AUDIO_LATENCY_MODE_LOW:
4563                 latency = g_strndup("low", 3);
4564                 break;
4565         case AUDIO_LATENCY_MODE_MID:
4566                 latency = g_strndup("mid", 3);
4567                 break;
4568         case AUDIO_LATENCY_MODE_HIGH:
4569                 latency = g_strndup("high", 4);
4570                 break;
4571         };
4572
4573 #if 0 //need to check
4574         if (player->sound_focus.user_route_policy != 0)
4575                 route_path = player->sound_focus.user_route_policy;
4576
4577         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4578                         "latency", latency_mode,
4579                         NULL);
4580
4581         LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4582                 volume_type, route_path, latency_mode);
4583         MMPLAYER_FLEAVE();
4584
4585 #endif
4586
4587         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4588                         "latency", latency,
4589                         NULL);
4590
4591         LOGD("audiosink property - latency=%s \n", latency);
4592
4593         g_free(latency);
4594
4595         MMPLAYER_FLEAVE();
4596 }
4597
4598 static int
4599 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4600 {
4601         MMPlayerGstElement* first_element = NULL;
4602         MMPlayerGstElement* audiobin = NULL;
4603         MMHandleType attrs = 0;
4604         GstPad *pad = NULL;
4605         GstPad *ghostpad = NULL;
4606         GList* element_bucket = NULL;
4607         gboolean link_audio_sink_now = TRUE;
4608         int i = 0;
4609
4610         MMPLAYER_FENTER();
4611
4612         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4613
4614         /* alloc handles */
4615         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4616         if (!audiobin) {
4617                 LOGE("failed to allocate memory for audiobin\n");
4618                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4619         }
4620
4621         attrs = MMPLAYER_GET_ATTRS(player);
4622
4623         /* create bin */
4624         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4625         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4626         if (!audiobin[MMPLAYER_A_BIN].gst) {
4627                 LOGE("failed to create audiobin\n");
4628                 goto ERROR;
4629         }
4630
4631         /* take it */
4632         player->pipeline->audiobin = audiobin;
4633
4634         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4635
4636         /* Adding audiotp plugin for reverse trickplay feature */
4637 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4638
4639         /* converter */
4640         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4641
4642         /* resampler */
4643         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4644
4645         if (player->set_mode.pcm_extraction) {
4646                 // pcm extraction only and no sound output
4647                 if (player->audio_stream_render_cb_ex) {
4648                         char *caps_str = NULL;
4649                         GstCaps* caps = NULL;
4650                         gchar *format = NULL;
4651
4652                         /* capsfilter */
4653                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4654
4655                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4656
4657                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4658
4659                         caps = gst_caps_new_simple("audio/x-raw",
4660                                         "format", G_TYPE_STRING, format,
4661                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4662                                         "channels", G_TYPE_INT, player->pcm_channel,
4663                                         NULL);
4664                         caps_str = gst_caps_to_string(caps);
4665                         LOGD("new caps : %s\n", caps_str);
4666
4667                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4668
4669                         /* clean */
4670                         gst_caps_unref(caps);
4671                         MMPLAYER_FREEIF(caps_str);
4672
4673                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4674
4675                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4676                         /* raw pad handling signal */
4677                         MMPLAYER_SIGNAL_CONNECT(player,
4678                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4679                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4680                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4681                 } else {
4682                         int dst_samplerate = 0;
4683                         int dst_channels = 0;
4684                         int dst_depth = 0;
4685                         char *caps_str = NULL;
4686                         GstCaps* caps = NULL;
4687
4688                         /* get conf. values */
4689                         mm_attrs_multiple_get(player->attrs,
4690                                                 NULL,
4691                                                 "pcm_extraction_samplerate", &dst_samplerate,
4692                                                 "pcm_extraction_channels", &dst_channels,
4693                                                 "pcm_extraction_depth", &dst_depth,
4694                                                 NULL);
4695
4696                         /* capsfilter */
4697                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4698                         caps = gst_caps_new_simple("audio/x-raw",
4699                                         "rate", G_TYPE_INT, dst_samplerate,
4700                                         "channels", G_TYPE_INT, dst_channels,
4701                                         "depth", G_TYPE_INT, dst_depth,
4702                                         NULL);
4703                         caps_str = gst_caps_to_string(caps);
4704                         LOGD("new caps : %s\n", caps_str);
4705
4706                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4707
4708                         /* clean */
4709                         gst_caps_unref(caps);
4710                         MMPLAYER_FREEIF(caps_str);
4711
4712                         /* fake sink */
4713                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4714
4715                         /* set sync */
4716                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4717                 }
4718         } else {
4719                 // normal playback
4720                 //GstCaps* caps = NULL;
4721                 gint channels = 0;
4722
4723                 /* for logical volume control */
4724                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4725                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4726
4727                 if (player->sound.mute) {
4728                         LOGD("mute enabled\n");
4729                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4730                 }
4731
4732 #if 0
4733                 /*capsfilter */
4734                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4735                 caps = gst_caps_from_string("audio/x-raw-int, "
4736                                         "endianness = (int) LITTLE_ENDIAN, "
4737                                         "signed = (boolean) true, "
4738                                         "width = (int) 16, "
4739                                         "depth = (int) 16");
4740                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4741                 gst_caps_unref(caps);
4742 #endif
4743
4744                 /* chech if multi-chennels */
4745                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4746                         GstPad *srcpad = NULL;
4747                         GstCaps *caps = NULL;
4748
4749                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4750                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4751                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4752                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4753                                         if (str)
4754                                                 gst_structure_get_int(str, "channels", &channels);
4755                                         gst_caps_unref(caps);
4756                                 }
4757                                 gst_object_unref(srcpad);
4758                         }
4759                 }
4760
4761                 /* audio effect element. if audio effect is enabled */
4762                 if ((strcmp(player->ini.audioeffect_element, ""))
4763                         && (channels <= 2)
4764                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4765                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4766
4767                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4768
4769                         if ((!player->bypass_audio_effect)
4770                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4771                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4772                                         if (!_mmplayer_audio_effect_custom_apply(player))
4773                                                 LOGI("apply audio effect(custom) setting success\n");
4774                                 }
4775                         }
4776
4777                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4778                                 && (player->set_mode.rich_audio))
4779                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4780                 }
4781                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4782                         if (player->set_mode.rich_audio && channels <= 2)
4783                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4784                 }
4785
4786                 /* create audio sink */
4787                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4788
4789                 /* qos on */
4790                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4791                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4792
4793
4794                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4795                         (player->videodec_linked && player->ini.use_system_clock)) {
4796                         LOGD("system clock will be used.\n");
4797                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4798                 }
4799
4800                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4801                         __mmplayer_gst_set_audiosink_property(player, attrs);
4802         }
4803
4804         if (audiobin[MMPLAYER_A_SINK].gst) {
4805                 GstPad *sink_pad = NULL;
4806                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4807                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4808                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4809                 gst_object_unref(GST_OBJECT(sink_pad));
4810         }
4811
4812         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4813
4814         /* adding created elements to bin */
4815         LOGD("adding created elements to bin\n");
4816         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4817                 LOGE("failed to add elements\n");
4818                 goto ERROR;
4819         }
4820
4821         /* linking elements in the bucket by added order. */
4822         LOGD("Linking elements in the bucket by added order.\n");
4823         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4824                 LOGE("failed to link elements\n");
4825                 goto ERROR;
4826         }
4827
4828         /* get first element's sinkpad for creating ghostpad */
4829         first_element = (MMPlayerGstElement *)element_bucket->data;
4830         if (!first_element) {
4831                 LOGE("failed to get first elem\n");
4832                 goto ERROR;
4833         }
4834
4835         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4836         if (!pad) {
4837                 LOGE("failed to get pad from first element of audiobin\n");
4838                 goto ERROR;
4839         }
4840
4841         ghostpad = gst_ghost_pad_new("sink", pad);
4842         if (!ghostpad) {
4843                 LOGE("failed to create ghostpad\n");
4844                 goto ERROR;
4845         }
4846
4847         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4848                 LOGE("failed to add ghostpad to audiobin\n");
4849                 goto ERROR;
4850         }
4851
4852         gst_object_unref(pad);
4853
4854         g_list_free(element_bucket);
4855
4856         mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4857
4858         MMPLAYER_FLEAVE();
4859
4860         return MM_ERROR_NONE;
4861
4862 ERROR:
4863
4864         LOGD("ERROR : releasing audiobin\n");
4865
4866         if (pad)
4867                 gst_object_unref(GST_OBJECT(pad));
4868
4869         if (ghostpad)
4870                 gst_object_unref(GST_OBJECT(ghostpad));
4871
4872         if (element_bucket)
4873                 g_list_free(element_bucket);
4874
4875         /* release element which are not added to bin */
4876         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4877                 /* NOTE : skip bin */
4878                 if (audiobin[i].gst) {
4879                         GstObject* parent = NULL;
4880                         parent = gst_element_get_parent(audiobin[i].gst);
4881
4882                         if (!parent) {
4883                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4884                                 audiobin[i].gst = NULL;
4885                         } else
4886                                 gst_object_unref(GST_OBJECT(parent));
4887                 }
4888         }
4889
4890         /* release audiobin with it's childs */
4891         if (audiobin[MMPLAYER_A_BIN].gst)
4892                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4893
4894         MMPLAYER_FREEIF(audiobin);
4895
4896         player->pipeline->audiobin = NULL;
4897
4898         return MM_ERROR_PLAYER_INTERNAL;
4899 }
4900
4901 static GstPadProbeReturn
4902 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4903 {
4904         mm_player_t* player = (mm_player_t*) u_data;
4905         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4906         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4907
4908         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4909
4910         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4911                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4912
4913         return GST_PAD_PROBE_OK;
4914 }
4915
4916 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4917 {
4918         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4919 }
4920
4921 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4922 {
4923         int ret = MM_ERROR_NONE;
4924         GList *l = NULL;
4925         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4926         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4927
4928         MMPLAYER_VIDEO_BO_LOCK(player);
4929
4930         if (player->video_bo_list) {
4931                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4932                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4933                         if (tmp && tmp->bo == bo) {
4934                                 tmp->using = FALSE;
4935                                 LOGD("release bo %p", bo);
4936                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4937                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4938                                 return ret;
4939                         }
4940                 }
4941         } else {
4942                 /* hw codec is running or the list was reset for DRC. */
4943                 LOGW("there is no bo list.");
4944         }
4945         MMPLAYER_VIDEO_BO_UNLOCK(player);
4946
4947         LOGW("failed to find bo %p", bo);
4948         return ret;
4949 }
4950
4951 static void
4952 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4953 {
4954         GList *l = NULL;
4955
4956         MMPLAYER_FENTER();
4957         MMPLAYER_RETURN_IF_FAIL(player);
4958
4959         MMPLAYER_VIDEO_BO_LOCK(player);
4960         if (player->video_bo_list) {
4961                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4962                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4963                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4964                         if (tmp) {
4965                                 if (tmp->bo)
4966                                         tbm_bo_unref(tmp->bo);
4967                                 g_free(tmp);
4968                         }
4969                 }
4970                 g_list_free(player->video_bo_list);
4971                 player->video_bo_list = NULL;
4972         }
4973         player->video_bo_size = 0;
4974         MMPLAYER_VIDEO_BO_UNLOCK(player);
4975
4976         MMPLAYER_FLEAVE();
4977         return;
4978 }
4979
4980 static void*
4981 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4982 {
4983         GList *l = NULL;
4984         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4985         gboolean ret = TRUE;
4986
4987         /* check DRC, if it is, destroy the prev bo list to create again */
4988         if (player->video_bo_size != size) {
4989                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4990                 __mmplayer_video_stream_destroy_bo_list(player);
4991                 player->video_bo_size = size;
4992         }
4993
4994         MMPLAYER_VIDEO_BO_LOCK(player);
4995
4996         if ((!player->video_bo_list) ||
4997                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4998
4999                 /* create bo list */
5000                 int idx = 0;
5001                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5002
5003                 if (player->video_bo_list) {
5004                         /* if bo list did not created all, try it again. */
5005                         idx = g_list_length(player->video_bo_list);
5006                         LOGD("bo list exist(len: %d)", idx);
5007                 }
5008
5009                 for (; idx < player->ini.num_of_video_bo; idx++) {
5010                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5011                         if (!bo_info) {
5012                                 LOGE("Fail to alloc bo_info.");
5013                                 break;
5014                         }
5015                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5016                         if (!bo_info->bo) {
5017                                 LOGE("Fail to tbm_bo_alloc.");
5018                                 g_free(bo_info);
5019                                 break;
5020                         }
5021                         bo_info->using = FALSE;
5022                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5023                 }
5024
5025                 /* update video num buffers */
5026                 player->video_num_buffers = idx;
5027                 if (idx == player->ini.num_of_video_bo)
5028                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5029
5030                 if (idx == 0) {
5031                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5032                         return NULL;
5033                 }
5034
5035                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5036         }
5037
5038         while (TRUE) {
5039                 /* get bo from list*/
5040                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5041                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5042                         if (tmp && (tmp->using == FALSE)) {
5043                                 LOGD("found bo %p to use", tmp->bo);
5044                                 tmp->using = TRUE;
5045                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5046                                 return tmp->bo;
5047                         }
5048                 }
5049                 if (!ret) {
5050                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5051                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5052                         return NULL;
5053                 }
5054
5055                 if (player->ini.video_bo_timeout <= 0) {
5056                         MMPLAYER_VIDEO_BO_WAIT(player);
5057                 } else {
5058                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5059                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5060                 }
5061                 continue;
5062         }
5063 }
5064
5065 static void
5066 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5067 {
5068         mm_player_t* player = (mm_player_t*)data;
5069         MMPLAYER_FENTER();
5070         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5071
5072         /* send prerolled pkt */
5073         player->video_stream_prerolled = FALSE;
5074
5075         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5076
5077         /* not to send prerolled pkt again */
5078         player->video_stream_prerolled = TRUE;
5079 }
5080
5081 static void
5082 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5083 {
5084         mm_player_t* player = (mm_player_t*)data;
5085         GstCaps *caps = NULL;
5086         MMPlayerVideoStreamDataType stream;
5087         MMVideoBuffer *video_buffer = NULL;
5088         GstMemory *dataBlock = NULL;
5089         GstMemory *metaBlock = NULL;
5090         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5091         GstStructure *structure = NULL;
5092         const gchar *string_format = NULL;
5093         unsigned int fourcc = 0;
5094
5095         MMPLAYER_FENTER();
5096         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5097
5098         if (player->video_stream_prerolled) {
5099                 player->video_stream_prerolled = FALSE;
5100                 LOGD("skip the prerolled pkt not to send it again");
5101                 return;
5102         }
5103
5104         caps = gst_pad_get_current_caps(pad);
5105         if (caps == NULL) {
5106                 LOGE("Caps is NULL.");
5107                 return;
5108         }
5109
5110         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5111
5112         /* clear stream data structure */
5113         memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5114
5115         structure = gst_caps_get_structure(caps, 0);
5116         gst_structure_get_int(structure, "width", & (stream.width));
5117         gst_structure_get_int(structure, "height", & (stream.height));
5118         string_format = gst_structure_get_string(structure, "format");
5119         if (string_format)
5120                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5121         stream.format = util_get_pixtype(fourcc);
5122         gst_caps_unref(caps);
5123         caps = NULL;
5124
5125     /*
5126         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5127                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5128     */
5129
5130         if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5131                 LOGE("Wrong condition!!");
5132                 return;
5133         }
5134
5135         /* set size and timestamp */
5136         dataBlock = gst_buffer_peek_memory(buffer, 0);
5137         stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5138         stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5139
5140         /* check zero-copy */
5141         if (player->set_mode.video_zc &&
5142                 player->set_mode.media_packet_video_stream &&
5143                 gst_buffer_n_memory(buffer) > 1) {
5144                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5145                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5146                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5147         }
5148
5149         if (video_buffer) { /* hw codec */
5150                 /* set tbm bo */
5151                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5152                         /* copy pointer of tbm bo, stride, elevation */
5153                         memcpy(stream.bo, video_buffer->handle.bo,
5154                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5155                 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5156                         /* FIXME: need to check this path */
5157                         memcpy(stream.data, video_buffer->data,
5158                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5159                 }
5160                 memcpy(stream.stride, video_buffer->stride_width,
5161                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5162                 memcpy(stream.elevation, video_buffer->stride_height,
5163                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5164                 /* set gst buffer */
5165                 stream.internal_buffer = buffer;
5166         } else { /* sw codec */
5167                 tbm_bo_handle thandle;
5168                 int stride = GST_ROUND_UP_4(stream.width);
5169                 int elevation = stream.height;
5170                 int size = 0;
5171
5172                 gboolean gst_ret;
5173                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5174                 if (!gst_ret) {
5175                         LOGE("fail to gst_memory_map");
5176                         return;
5177                 }
5178
5179                 stream.stride[0] = stride;
5180                 stream.elevation[0] = elevation;
5181                 if (stream.format == MM_PIXEL_FORMAT_I420) {
5182                         stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5183                         stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5184                         size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5185                 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5186                         stream.stride[0] = stream.width * 4;
5187                         size = stream.stride[0] * stream.height;
5188                 } else {
5189                         LOGE("Not support format %d", stream.format);
5190                         gst_memory_unmap(dataBlock, &mapinfo);
5191                         return;
5192                 }
5193                 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5194                 if (!stream.bo[0]) {
5195                         LOGE("Fail to tbm_bo_alloc!!");
5196                         gst_memory_unmap(dataBlock, &mapinfo);
5197                         return;
5198                 }
5199                 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5200                 if (thandle.ptr && mapinfo.data)
5201                         memcpy(thandle.ptr, mapinfo.data, size);
5202                 else
5203                         LOGE("data pointer is wrong. dest : %p, src : %p",
5204                                         thandle.ptr, mapinfo.data);
5205                 tbm_bo_unmap(stream.bo[0]);
5206         }
5207
5208         if (player->video_stream_cb)
5209                 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5210
5211         if (metaBlock)
5212                 gst_memory_unmap(metaBlock, &mapinfo);
5213         else
5214                 gst_memory_unmap(dataBlock, &mapinfo);
5215
5216         return;
5217 }
5218
5219 static int
5220 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5221 {
5222         MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5223         gchar* video_csc = "videoconvert"; // default colorspace converter
5224         GList* element_bucket = *bucket;
5225
5226         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227
5228         MMPLAYER_FENTER();
5229
5230         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5231
5232         if (player->set_mode.video_zc) {
5233                 video_csc = ""; /* videosinks don't use videoconvert normally */
5234         } else {
5235                 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5236                 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5237                         video_csc = "videoconvert";
5238         }
5239         if (video_csc && (strcmp(video_csc, ""))) {
5240                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5241                 LOGD("using video converter: %s", video_csc);
5242         }
5243
5244         /* set video rotator */
5245         if (!player->set_mode.video_zc)
5246                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5247
5248         *bucket = element_bucket;
5249         MMPLAYER_FLEAVE();
5250         return MM_ERROR_NONE;
5251
5252 ERROR:
5253         *bucket = NULL;
5254         MMPLAYER_FLEAVE();
5255         return MM_ERROR_PLAYER_INTERNAL;
5256 }
5257
5258 /**
5259  * This function is to create video pipeline.
5260  *
5261  * @param       player          [in]    handle of player
5262  *              caps            [in]    src caps of decoder
5263  *              surface_type    [in]    surface type for video rendering
5264  *
5265  * @return      This function returns zero on success.
5266  * @remark
5267  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5268  */
5269 /**
5270   * VIDEO PIPELINE
5271   * - video overlay surface(arm/x86) : waylandsink
5272   */
5273 static int
5274 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5275 {
5276         GstPad *pad = NULL;
5277         MMHandleType attrs;
5278         GList*element_bucket = NULL;
5279         MMPlayerGstElement* first_element = NULL;
5280         MMPlayerGstElement* videobin = NULL;
5281         gchar *videosink_element = NULL;
5282
5283         MMPLAYER_FENTER();
5284
5285         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5286
5287         /* alloc handles */
5288         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5289         if (!videobin)
5290                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5291
5292         player->pipeline->videobin = videobin;
5293
5294         attrs = MMPLAYER_GET_ATTRS(player);
5295         if (!attrs) {
5296                 LOGE("cannot get content attribute");
5297                 return MM_ERROR_PLAYER_INTERNAL;
5298         }
5299
5300         /* create bin */
5301         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5302         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5303         if (!videobin[MMPLAYER_V_BIN].gst) {
5304                 LOGE("failed to create videobin");
5305                 goto ERROR;
5306         }
5307
5308         int enable_video_decoded_cb = 0;
5309         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5310
5311         /* set video sink */
5312         switch (surface_type) {
5313         case MM_DISPLAY_SURFACE_OVERLAY:
5314                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5315                         goto ERROR;
5316                 if (strlen(player->ini.videosink_element_overlay) > 0)
5317                         videosink_element = player->ini.videosink_element_overlay;
5318                 else
5319                         goto ERROR;
5320                 break;
5321         case MM_DISPLAY_SURFACE_NULL:
5322                 if (strlen(player->ini.videosink_element_fake) > 0)
5323                         videosink_element = player->ini.videosink_element_fake;
5324                 else
5325                         goto ERROR;
5326                 break;
5327         case MM_DISPLAY_SURFACE_REMOTE:
5328                 if (strlen(player->ini.videosink_element_fake) > 0)
5329                         videosink_element = player->ini.videosink_element_fake;
5330                 else
5331                         goto ERROR;
5332                 break;
5333         default:
5334                 LOGE("unidentified surface type");
5335                 goto ERROR;
5336         }
5337         LOGD("selected videosink name: %s", videosink_element);
5338
5339         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5340
5341         /* additional setting for sink plug-in */
5342         switch (surface_type) {
5343         case MM_DISPLAY_SURFACE_OVERLAY:
5344         {
5345                 bool use_tbm = player->set_mode.video_zc;
5346                 if (!use_tbm) {
5347                         LOGD("selected videosink name: %s", videosink_element);
5348
5349                         /* support shard memory with S/W codec on HawkP */
5350                         if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5351                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5352                                         "use-tbm", use_tbm, NULL);
5353                         }
5354                 } else {
5355                         if (attrs) {
5356                                 int gapless = 0;
5357
5358                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5359
5360                                 if (gapless > 0) {
5361                                         LOGD("disable last-sample");
5362                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5363                                 }
5364                         }
5365                 }
5366                 if (player->set_mode.media_packet_video_stream) {
5367                         int enable = 0;
5368                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5369                         if (enable)
5370                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5371
5372                         MMPLAYER_SIGNAL_CONNECT(player,
5373                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5374                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5375                                                                         "handoff",
5376                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5377                                                                         (gpointer)player);
5378
5379                         MMPLAYER_SIGNAL_CONNECT(player,
5380                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5381                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5382                                                                         "preroll-handoff",
5383                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5384                                                                         (gpointer)player);
5385                 }
5386                 break;
5387         }
5388         case MM_DISPLAY_SURFACE_REMOTE:
5389         {
5390                 if (player->set_mode.media_packet_video_stream) {
5391                         LOGE("add data probe at videosink");
5392                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5394
5395                         MMPLAYER_SIGNAL_CONNECT(player,
5396                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5397                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5398                                                                         "handoff",
5399                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5400                                                                         (gpointer)player);
5401
5402                         MMPLAYER_SIGNAL_CONNECT(player,
5403                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5404                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5405                                                                         "preroll-handoff",
5406                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5407                                                                         (gpointer)player);
5408                         if (attrs) {
5409                                 int gapless = 0;
5410
5411                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5412
5413                                 if (gapless > 0) {
5414                                         LOGD("disable last-sample");
5415                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5416                                 }
5417                         }
5418                 }
5419                 break;
5420         }
5421         default:
5422                 break;
5423         }
5424
5425         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5426                 goto ERROR;
5427
5428         if (videobin[MMPLAYER_V_SINK].gst) {
5429                 GstPad *sink_pad = NULL;
5430                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5431                 if (sink_pad) {
5432                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5433                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5434                         gst_object_unref(GST_OBJECT(sink_pad));
5435                 } else
5436                         LOGW("failed to get sink pad from videosink\n");
5437         }
5438
5439         /* store it as it's sink element */
5440         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5441
5442         /* adding created elements to bin */
5443         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5444                 LOGE("failed to add elements\n");
5445                 goto ERROR;
5446         }
5447
5448         /* Linking elements in the bucket by added order */
5449         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5450                 LOGE("failed to link elements\n");
5451                 goto ERROR;
5452         }
5453
5454         /* get first element's sinkpad for creating ghostpad */
5455         if (element_bucket)
5456                 first_element = (MMPlayerGstElement *)element_bucket->data;
5457         if (!first_element) {
5458                 LOGE("failed to get first element from bucket\n");
5459                 goto ERROR;
5460         }
5461
5462         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5463         if (!pad) {
5464                 LOGE("failed to get pad from first element\n");
5465                 goto ERROR;
5466         }
5467
5468         /* create ghostpad */
5469         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5470         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5471                 LOGE("failed to add ghostpad to videobin\n");
5472                 goto ERROR;
5473         }
5474         gst_object_unref(pad);
5475
5476         /* done. free allocated variables */
5477         if (element_bucket)
5478                 g_list_free(element_bucket);
5479
5480         mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5481
5482         MMPLAYER_FLEAVE();
5483
5484         return MM_ERROR_NONE;
5485
5486 ERROR:
5487         LOGE("ERROR : releasing videobin\n");
5488
5489         g_list_free(element_bucket);
5490
5491         if (pad)
5492                 gst_object_unref(GST_OBJECT(pad));
5493
5494         /* release videobin with it's childs */
5495         if (videobin[MMPLAYER_V_BIN].gst)
5496                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5497
5498
5499         MMPLAYER_FREEIF(videobin);
5500
5501         player->pipeline->videobin = NULL;
5502
5503         return MM_ERROR_PLAYER_INTERNAL;
5504 }
5505
5506 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5507 {
5508         GList *element_bucket = NULL;
5509         MMPlayerGstElement *textbin = player->pipeline->textbin;
5510
5511         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5512         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5513         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5514                                                         "signal-handoffs", FALSE,
5515                                                         NULL);
5516
5517         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5518         MMPLAYER_SIGNAL_CONNECT(player,
5519                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5520                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5521                                                         "handoff",
5522                                                         G_CALLBACK(__mmplayer_update_subtitle),
5523                                                         (gpointer)player);
5524
5525         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5526         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5527         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5528
5529         if (!player->play_subtitle) {
5530                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5531                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5532         }
5533
5534         /* adding created elements to bin */
5535         LOGD("adding created elements to bin\n");
5536         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5537                 LOGE("failed to add elements\n");
5538                 goto ERROR;
5539         }
5540
5541         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5542         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5543         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5544
5545         /* linking elements in the bucket by added order. */
5546         LOGD("Linking elements in the bucket by added order.\n");
5547         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5548                 LOGE("failed to link elements\n");
5549                 goto ERROR;
5550         }
5551
5552         /* done. free allocated variables */
5553         g_list_free(element_bucket);
5554
5555         if (textbin[MMPLAYER_T_QUEUE].gst) {
5556                 GstPad *pad = NULL;
5557                 GstPad *ghostpad = NULL;
5558
5559                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5560                 if (!pad) {
5561                         LOGE("failed to get video pad of textbin\n");
5562                         return MM_ERROR_PLAYER_INTERNAL;
5563                 }
5564
5565                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5566                 gst_object_unref(pad);
5567
5568                 if (!ghostpad) {
5569                         LOGE("failed to create ghostpad of textbin\n");
5570                         goto ERROR;
5571                 }
5572
5573                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5574                         LOGE("failed to add ghostpad to textbin\n");
5575                         goto ERROR;
5576                 }
5577         }
5578
5579         return MM_ERROR_NONE;
5580
5581 ERROR:
5582         g_list_free(element_bucket);
5583
5584         return MM_ERROR_PLAYER_INTERNAL;
5585 }
5586
5587 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5588 {
5589         MMPlayerGstElement *textbin = NULL;
5590         GList *element_bucket = NULL;
5591         gint i = 0;
5592
5593         MMPLAYER_FENTER();
5594
5595         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5596
5597         /* alloc handles */
5598         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5599         if (!textbin) {
5600                 LOGE("failed to allocate memory for textbin\n");
5601                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5602         }
5603
5604         /* create bin */
5605         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5606         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5607         if (!textbin[MMPLAYER_T_BIN].gst) {
5608                 LOGE("failed to create textbin\n");
5609                 goto ERROR;
5610         }
5611
5612         /* take it */
5613         player->pipeline->textbin = textbin;
5614
5615         /* fakesink */
5616         if (player->use_textoverlay) {
5617                 LOGD("use textoverlay for displaying \n");
5618
5619                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5620
5621                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5622
5623                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5624
5625                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5626
5627                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5628                         LOGE("failed to link queue and converter\n");
5629                         goto ERROR;
5630                 }
5631
5632                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5633                         LOGE("failed to link queue and textoverlay\n");
5634                         goto ERROR;
5635                 }
5636
5637                 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5638                         LOGE("failed to link queue and textoverlay\n");
5639                         goto ERROR;
5640                 }
5641         } else {
5642                 int surface_type = 0;
5643
5644                 LOGD("use subtitle message for displaying \n");
5645
5646                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5647
5648                 switch (surface_type) {
5649                 case MM_DISPLAY_SURFACE_OVERLAY:
5650                 case MM_DISPLAY_SURFACE_NULL:
5651                 case MM_DISPLAY_SURFACE_REMOTE:
5652                         if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5653                                 LOGE("failed to make plain text elements\n");
5654                                 goto ERROR;
5655                         }
5656                         break;
5657
5658                 default:
5659                         break;
5660                 }
5661         }
5662
5663         MMPLAYER_FLEAVE();
5664
5665         return MM_ERROR_NONE;
5666
5667 ERROR:
5668
5669         LOGD("ERROR : releasing textbin\n");
5670
5671         g_list_free(element_bucket);
5672
5673         /* release element which are not added to bin */
5674         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5675                 /* NOTE : skip bin */
5676                 if (textbin[i].gst) {
5677                         GstObject* parent = NULL;
5678                         parent = gst_element_get_parent(textbin[i].gst);
5679
5680                         if (!parent) {
5681                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5682                                 textbin[i].gst = NULL;
5683                         } else
5684                                 gst_object_unref(GST_OBJECT(parent));
5685                 }
5686         }
5687
5688         /* release textbin with it's childs */
5689         if (textbin[MMPLAYER_T_BIN].gst)
5690                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5691
5692         MMPLAYER_FREEIF(textbin);
5693
5694         player->pipeline->textbin = NULL;
5695
5696         return MM_ERROR_PLAYER_INTERNAL;
5697 }
5698
5699
5700 static int
5701 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5702 {
5703         MMPlayerGstElement* mainbin = NULL;
5704         MMHandleType attrs = 0;
5705         GstElement *subsrc = NULL;
5706         GstElement *subparse = NULL;
5707         gchar *subtitle_uri = NULL;
5708         const gchar *charset = NULL;
5709         GstPad *pad = NULL;
5710
5711         MMPLAYER_FENTER();
5712
5713         /* get mainbin */
5714         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5715
5716         mainbin = player->pipeline->mainbin;
5717
5718         attrs = MMPLAYER_GET_ATTRS(player);
5719         if (!attrs) {
5720                 LOGE("cannot get content attribute\n");
5721                 return MM_ERROR_PLAYER_INTERNAL;
5722         }
5723
5724         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5725         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5726                 LOGE("subtitle uri is not proper filepath.\n");
5727                 return MM_ERROR_PLAYER_INVALID_URI;
5728         }
5729         LOGD("subtitle file path is [%s].\n", subtitle_uri);
5730
5731
5732         /* create the subtitle source */
5733         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5734         if (!subsrc) {
5735                 LOGE("failed to create filesrc element\n");
5736                 goto ERROR;
5737         }
5738         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5739
5740         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5741         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5742
5743         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5744                 LOGW("failed to add queue\n");
5745                 goto ERROR;
5746         }
5747
5748         /* subparse */
5749         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5750         if (!subparse) {
5751                 LOGE("failed to create subparse element\n");
5752                 goto ERROR;
5753         }
5754
5755         charset = util_get_charset(subtitle_uri);
5756         if (charset) {
5757                 LOGD("detected charset is %s\n", charset);
5758                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5759         }
5760
5761         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5762         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5763
5764         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5765                 LOGW("failed to add subparse\n");
5766                 goto ERROR;
5767         }
5768
5769         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5770                 LOGW("failed to link subsrc and subparse\n");
5771                 goto ERROR;
5772         }
5773
5774         player->play_subtitle = TRUE;
5775         player->adjust_subtitle_pos = 0;
5776
5777         LOGD("play subtitle using subtitle file\n");
5778
5779         if (player->pipeline->textbin == NULL) {
5780                 if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
5781                         LOGE("failed to create textbin. continuing without text\n");
5782                         goto ERROR;
5783                 }
5784
5785                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5786                         LOGW("failed to add textbin\n");
5787                         goto ERROR;
5788                 }
5789
5790                 LOGD("link text input selector and textbin ghost pad");
5791
5792                 player->textsink_linked = 1;
5793                 player->external_text_idx = 0;
5794                 LOGI("player->textsink_linked set to 1\n");
5795         } else {
5796                 LOGD("text bin has been created. reuse it.");
5797                 player->external_text_idx = 1;
5798         }
5799
5800         if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5801                 LOGW("failed to link subparse and textbin\n");
5802                 goto ERROR;
5803         }
5804
5805         pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5806
5807         if (!pad) {
5808                 LOGE("failed to get sink pad from textsink to probe data");
5809                 return MM_ERROR_PLAYER_INTERNAL;
5810         }
5811
5812         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5813                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5814
5815         gst_object_unref(pad);
5816         pad = NULL;
5817
5818         /* create dot. for debugging */
5819         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5820         MMPLAYER_FLEAVE();
5821
5822         return MM_ERROR_NONE;
5823
5824 ERROR:
5825         player->textsink_linked = 0;
5826         return MM_ERROR_PLAYER_INTERNAL;
5827 }
5828
5829 gboolean
5830 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5831 {
5832         mm_player_t* player = (mm_player_t*) data;
5833         MMMessageParamType msg = {0, };
5834         GstClockTime duration = 0;
5835         gpointer text = NULL;
5836         guint text_size = 0;
5837         gboolean ret = TRUE;
5838         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5839
5840         MMPLAYER_FENTER();
5841
5842         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5843         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5844
5845         if (player->is_subtitle_force_drop)
5846         {
5847                 LOGW("subtitle is dropped forcedly.");
5848                 return ret;
5849         }
5850
5851         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5852         text = mapinfo.data;
5853         text_size = mapinfo.size;
5854         duration = GST_BUFFER_DURATION(buffer);
5855
5856         if (player->set_mode.subtitle_off) {
5857                 LOGD("subtitle is OFF.\n");
5858                 return TRUE;
5859         }
5860
5861         if (!text || (text_size == 0)) {
5862                 LOGD("There is no subtitle to be displayed.\n");
5863                 return TRUE;
5864         }
5865
5866         msg.data = (void *) text;
5867         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5868
5869         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5870
5871         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5872         gst_buffer_unmap(buffer, &mapinfo);
5873
5874         MMPLAYER_FLEAVE();
5875
5876         return ret;
5877 }
5878
5879 static GstPadProbeReturn
5880 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5881
5882 {
5883         mm_player_t *player = (mm_player_t *) u_data;
5884         GstClockTime cur_timestamp = 0;
5885         gint64 adjusted_timestamp = 0;
5886         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5887
5888         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5889
5890         if (player->set_mode.subtitle_off) {
5891                 LOGD("subtitle is OFF.\n");
5892                 return TRUE;
5893         }
5894
5895         if (player->adjust_subtitle_pos == 0) {
5896                 LOGD("nothing to do");
5897                 return TRUE;
5898         }
5899
5900         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5901         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5902
5903         if (adjusted_timestamp < 0) {
5904                 LOGD("adjusted_timestamp under zero");
5905                 MMPLAYER_FLEAVE();
5906                 return FALSE;
5907         }
5908
5909         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5910         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5911                                 GST_TIME_ARGS(cur_timestamp),
5912                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5913
5914         return GST_PAD_PROBE_OK;
5915 }
5916 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5917 {
5918         MMPLAYER_FENTER();
5919
5920         /* check player and subtitlebin are created */
5921         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5922         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5923
5924         if (position == 0) {
5925                 LOGD("nothing to do\n");
5926                 MMPLAYER_FLEAVE();
5927                 return MM_ERROR_NONE;
5928         }
5929
5930         switch (format) {
5931         case MM_PLAYER_POS_FORMAT_TIME:
5932                 {
5933                         /* check current postion */
5934                         player->adjust_subtitle_pos = position;
5935
5936                         LOGD("save adjust_subtitle_pos in player") ;
5937                 }
5938                 break;
5939
5940         default:
5941                 {
5942                         LOGW("invalid format.\n");
5943                         MMPLAYER_FLEAVE();
5944                         return MM_ERROR_INVALID_ARGUMENT;
5945                 }
5946         }
5947
5948         MMPLAYER_FLEAVE();
5949
5950         return MM_ERROR_NONE;
5951 }
5952 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5953 {
5954         MMPLAYER_FENTER();
5955         LOGD("adjusting video_pos in player") ;
5956         int current_pos = 0;
5957         /* check player and videobin are created */
5958         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5959         if (!player->pipeline->videobin ||
5960                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5961                 LOGD("no video pipeline or sink is there");
5962                 return MM_ERROR_PLAYER_INVALID_STATE ;
5963         }
5964         if (offset == 0) {
5965                 LOGD("nothing to do\n");
5966                 MMPLAYER_FLEAVE();
5967                 return MM_ERROR_NONE;
5968         }
5969         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
5970                 LOGD("failed to get current position");
5971                 return MM_ERROR_PLAYER_INTERNAL;
5972         }
5973         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5974                 LOGD("enter video delay is valid");
5975         } else {
5976                 LOGD("enter video delay is crossing content boundary");
5977                 return MM_ERROR_INVALID_ARGUMENT ;
5978         }
5979         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5980         LOGD("video delay has been done");
5981         MMPLAYER_FLEAVE();
5982
5983         return MM_ERROR_NONE;
5984 }
5985
5986 static void
5987 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5988 {
5989         GstElement *appsrc = element;
5990         tBuffer *buf = (tBuffer *)user_data;
5991         GstBuffer *buffer = NULL;
5992         GstFlowReturn ret = GST_FLOW_OK;
5993         gint len = size;
5994
5995         MMPLAYER_RETURN_IF_FAIL(element);
5996         MMPLAYER_RETURN_IF_FAIL(buf);
5997
5998         buffer = gst_buffer_new();
5999
6000         if (buf->offset >= buf->len) {
6001                 LOGD("call eos appsrc\n");
6002                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6003                 return;
6004         }
6005
6006         if (buf->len - buf->offset < size)
6007                 len = buf->len - buf->offset + buf->offset;
6008
6009         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free));
6010         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6011         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6012
6013         //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6014         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6015
6016         buf->offset += len;
6017 }
6018
6019 static gboolean
6020 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6021 {
6022         tBuffer *buf = (tBuffer *)user_data;
6023
6024         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6025
6026         buf->offset  = (int)size;
6027
6028         return TRUE;
6029 }
6030
6031 static GstBusSyncReply
6032 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6033 {
6034         mm_player_t *player = (mm_player_t *)data;
6035         GstBusSyncReply reply = GST_BUS_DROP;
6036
6037         if (!(player->pipeline && player->pipeline->mainbin)) {
6038                 LOGE("player pipeline handle is null");
6039                 return GST_BUS_PASS;
6040         }
6041
6042         if (!__mmplayer_check_useful_message(player, message)) {
6043                 gst_message_unref(message);
6044                 return GST_BUS_DROP;
6045         }
6046
6047         switch (GST_MESSAGE_TYPE(message)) {
6048         case GST_MESSAGE_STATE_CHANGED:
6049                 /* post directly for fast launch */
6050                 if (player->sync_handler) {
6051                         __mmplayer_gst_callback(NULL, message, player);
6052                         reply = GST_BUS_DROP;
6053                 } else
6054                         reply = GST_BUS_PASS;
6055                 break;
6056         case GST_MESSAGE_TAG:
6057                 __mmplayer_gst_extract_tag_from_msg(player, message);
6058
6059                 #if 0 // debug
6060                 {
6061                         GstTagList *tags = NULL;
6062
6063                         gst_message_parse_tag(message, &tags);
6064                         if (tags) {
6065                                 LOGE("TAGS received from element \"%s\".\n",
6066                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6067
6068                                 gst_tag_list_foreach(tags, print_tag, NULL);
6069                                 gst_tag_list_free(tags);
6070                                 tags = NULL;
6071                         }
6072                         break;
6073                 }
6074                 #endif
6075                 break;
6076
6077         case GST_MESSAGE_DURATION_CHANGED:
6078                 __mmplayer_gst_handle_duration(player, message);
6079                 break;
6080         case GST_MESSAGE_ASYNC_DONE:
6081                 /* NOTE:Don't call gst_callback directly
6082                  * because previous frame can be showed even though this message is received for seek.
6083                  */
6084         default:
6085                 reply = GST_BUS_PASS;
6086                 break;
6087         }
6088
6089         if (reply == GST_BUS_DROP)
6090                 gst_message_unref(message);
6091
6092         return reply;
6093 }
6094
6095 static gboolean
6096 __mmplayer_gst_create_decoder(mm_player_t *player,
6097                                                                 MMPlayerTrackType track,
6098                                                                 GstPad* srcpad,
6099                                                                 enum MainElementID elemId,
6100                                                                 const gchar* name)
6101 {
6102         gboolean ret = TRUE;
6103         GstPad *sinkpad = NULL;
6104
6105         MMPLAYER_FENTER();
6106
6107         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6108                                                 player->pipeline &&
6109                                                 player->pipeline->mainbin, FALSE);
6110         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6111         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6112         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6113
6114         GstElement *decodebin = NULL;
6115         GstCaps *dec_caps = NULL;
6116
6117         /* create decodebin */
6118         decodebin = gst_element_factory_make("decodebin", name);
6119
6120         if (!decodebin) {
6121                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6122                 ret = FALSE;
6123                 goto ERROR;
6124         }
6125
6126         /* raw pad handling signal */
6127         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6128                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6129
6130         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6131         before looking for any elements that can handle that stream.*/
6132         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6133                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6134
6135         /* This signal is emitted when a element is added to the bin.*/
6136         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6137                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6138
6139         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6140                 LOGE("failed to add new decodebin\n");
6141                 ret = FALSE;
6142                 goto ERROR;
6143         }
6144
6145         dec_caps = gst_pad_query_caps(srcpad, NULL);
6146         if (dec_caps) {
6147                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6148                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6149                 gst_caps_unref(dec_caps);
6150         }
6151
6152         player->pipeline->mainbin[elemId].id = elemId;
6153         player->pipeline->mainbin[elemId].gst = decodebin;
6154
6155         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6156
6157         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6158                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6159                 gst_object_unref(GST_OBJECT(decodebin));
6160         }
6161
6162         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6163                 LOGE("failed to sync second level decodebin state with parent\n");
6164
6165         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6166
6167 ERROR:
6168         if (sinkpad) {
6169                 gst_object_unref(GST_OBJECT(sinkpad));
6170                 sinkpad = NULL;
6171         }
6172         MMPLAYER_FLEAVE();
6173
6174         return ret;
6175 }
6176
6177 /**
6178  * This function is to create  audio or video pipeline for playing.
6179  *
6180  * @param       player          [in]    handle of player
6181  *
6182  * @return      This function returns zero on success.
6183  * @remark
6184  * @see
6185  */
6186 static int
6187 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6188 {
6189         GstBus  *bus = NULL;
6190         MMPlayerGstElement *mainbin = NULL;
6191         MMHandleType attrs = 0;
6192         GstElement* element = NULL;
6193         GstElement* elem_src_audio = NULL;
6194         GstElement* elem_src_subtitle = NULL;
6195         GstElement* es_video_queue = NULL;
6196         GstElement* es_audio_queue = NULL;
6197         GstElement* es_subtitle_queue = NULL;
6198         GList* element_bucket = NULL;
6199         gboolean need_state_holder = TRUE;
6200         gint i = 0;
6201 #ifdef SW_CODEC_ONLY
6202         int surface_type = 0;
6203 #endif
6204         MMPLAYER_FENTER();
6205
6206         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6207
6208         /* get profile attribute */
6209         attrs = MMPLAYER_GET_ATTRS(player);
6210         if (!attrs) {
6211                 LOGE("cannot get content attribute\n");
6212                 goto INIT_ERROR;
6213         }
6214
6215         /* create pipeline handles */
6216         if (player->pipeline) {
6217                 LOGW("pipeline should be released before create new one\n");
6218                 goto INIT_ERROR;
6219         }
6220
6221         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6222         if (player->pipeline == NULL)
6223                 goto INIT_ERROR;
6224
6225         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6226
6227
6228         /* create mainbin */
6229         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6230         if (mainbin == NULL)
6231                 goto INIT_ERROR;
6232
6233         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6234
6235         /* create pipeline */
6236         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6237         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6238         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6239                 LOGE("failed to create pipeline\n");
6240                 goto INIT_ERROR;
6241         }
6242         player->demux_pad_index = 0;
6243         player->subtitle_language_list = NULL;
6244
6245         player->is_subtitle_force_drop = FALSE;
6246         player->last_multiwin_status = FALSE;
6247
6248         _mmplayer_track_initialize(player);
6249
6250         /* create source element */
6251         switch (player->profile.uri_type) {
6252         /* rtsp streamming */
6253         case MM_PLAYER_URI_TYPE_URL_RTSP:
6254                 {
6255                         gint network_bandwidth;
6256                         gchar *user_agent, *wap_profile;
6257
6258                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6259
6260                         if (!element) {
6261                                 LOGE("failed to create streaming source element\n");
6262                                 break;
6263                         }
6264
6265                         /* make it zero */
6266                         network_bandwidth = 0;
6267                         user_agent = wap_profile = NULL;
6268
6269                         /* get attribute */
6270                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6271                         mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6272                         mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6273
6274                         SECURE_LOGD("user_agent : %s\n", user_agent);
6275                         SECURE_LOGD("wap_profile : %s\n", wap_profile);
6276
6277                         /* setting property to streaming source */
6278                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6279                         if (user_agent)
6280                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6281                         if (wap_profile)
6282                                 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6283
6284                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6285                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6286                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6287                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6288
6289                         player->use_decodebin = FALSE;
6290                 }
6291                 break;
6292
6293         /* http streaming*/
6294         case MM_PLAYER_URI_TYPE_URL_HTTP:
6295                 {
6296                         gchar *user_agent, *proxy, *cookies, **cookie_list;
6297                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6298                         user_agent = proxy = cookies = NULL;
6299                         cookie_list = NULL;
6300                         gint mode = MM_PLAYER_PD_MODE_NONE;
6301
6302                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6303
6304                         player->pd_mode = mode;
6305
6306                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6307
6308                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6309                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6310                                 if (!element) {
6311                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6312                                         break;
6313                                 }
6314                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6315
6316                                 /* get attribute */
6317                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6318                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6319                                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6320                                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6321
6322                                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6323                                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6324                                         LOGD("get timeout from ini\n");
6325                                         http_timeout = player->ini.http_timeout;
6326                                 }
6327
6328                                 /* get attribute */
6329                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6330                                 SECURE_LOGD("cookies : %s\n", cookies);
6331                                 SECURE_LOGD("proxy : %s\n", proxy);
6332                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6333                                 LOGD("timeout : %d\n",  http_timeout);
6334
6335                                 /* setting property to streaming source */
6336                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6337                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6338                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6339
6340                                 /* check if prosy is vailid or not */
6341                                 if (util_check_valid_url(proxy))
6342                                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6343                                 /* parsing cookies */
6344                                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6345                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6346                                 if (user_agent)
6347                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6348
6349                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6350                                         LOGW("it's dash. and it's still experimental feature.");
6351                         } else {
6352                                 // progressive download
6353                                 gchar* location = NULL;
6354
6355                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6356                                         gchar *path = NULL;
6357
6358                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6359
6360                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6361
6362                                         LOGD("PD Location : %s\n", path);
6363
6364                                         if (path) {
6365                                                 player->pd_file_save_path = g_strdup(path);
6366                                         } else {
6367                                                 LOGE("can't find pd location so, it should be set \n");
6368                                                 break;
6369                                         }
6370                                 }
6371
6372                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6373                                 if (!element) {
6374                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6375                                         break;
6376                                 }
6377
6378                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6379                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6380                                 else
6381                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6382
6383                                 g_object_get(element, "location", &location, NULL);
6384                                 LOGD("PD_LOCATION [%s].\n", location);
6385                                 if (location)
6386                                         g_free(location);
6387                         }
6388                 }
6389                 break;
6390
6391         /* file source */
6392         case MM_PLAYER_URI_TYPE_FILE:
6393                 {
6394
6395                         LOGD("using filesrc for 'file://' handler.\n");
6396
6397                         element = gst_element_factory_make("filesrc", "source");
6398
6399                         if (!element) {
6400                                 LOGE("failed to create filesrc\n");
6401                                 break;
6402                         }
6403
6404                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6405                         //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6406                 }
6407                 break;
6408
6409         case MM_PLAYER_URI_TYPE_SS:
6410                 {
6411                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6412                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6413                         if (!element) {
6414                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6415                                 break;
6416                         }
6417
6418                         mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6419
6420                         if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6421                                 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6422                                 LOGD("get timeout from ini\n");
6423                                 http_timeout = player->ini.http_timeout;
6424                         }
6425
6426                         /* setting property to streaming source */
6427                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6428                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6429                 }
6430                 break;
6431         case MM_PLAYER_URI_TYPE_MS_BUFF:
6432                 {
6433                         LOGD("MS buff src is selected\n");
6434
6435                         if (player->v_stream_caps) {
6436                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6437                                 if (!element) {
6438                                         LOGF("failed to create video app source element[appsrc].\n");
6439                                         break;
6440                                 }
6441
6442                                 if (player->a_stream_caps) {
6443                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6444                                         if (!elem_src_audio) {
6445                                                 LOGF("failed to create audio app source element[appsrc].\n");
6446                                                 break;
6447                                         }
6448                                 }
6449                         } else if (player->a_stream_caps) {
6450                                 /* no video, only audio pipeline*/
6451                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6452                                 if (!element) {
6453                                         LOGF("failed to create audio app source element[appsrc].\n");
6454                                         break;
6455                                 }
6456                         }
6457
6458                         if (player->s_stream_caps) {
6459                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6460                                 if (!elem_src_subtitle) {
6461                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6462                                         break;
6463                                 }
6464                         }
6465
6466                         LOGD("setting app sources properties.\n");
6467                         LOGD("location : %s\n", player->profile.uri);
6468
6469                         if (player->v_stream_caps && element) {
6470                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6471                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6472                                                                                                 "caps", player->v_stream_caps, NULL);
6473
6474                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6475                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6476                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6477                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6478
6479                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6480                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6481                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6482                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6483
6484                                 if (player->a_stream_caps && elem_src_audio) {
6485                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6486                                                                                                                         "caps", player->a_stream_caps, NULL);
6487
6488                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6489                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6490                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6491                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6492
6493                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6494                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6495                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6496                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6497                                 }
6498                         } else if (player->a_stream_caps && element) {
6499                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6500                                                                                                 "caps", player->a_stream_caps, NULL);
6501
6502                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6503                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6504                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6505                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6506
6507                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6508                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6509                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6510                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6511                         }
6512
6513                         if (player->s_stream_caps && elem_src_subtitle) {
6514                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6515                                                                                                                  "caps", player->s_stream_caps, NULL);
6516
6517                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6518                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6519                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6520                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6521
6522                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6523
6524                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6525                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6526                         }
6527
6528                         if (player->v_stream_caps && element) {
6529                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6530                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6531                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6532                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6533
6534                                 if (player->a_stream_caps && elem_src_audio) {
6535                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6536                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6537                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6538                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6539                                 }
6540                         } else if (player->a_stream_caps && element) {
6541                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6542                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6543                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6544                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6545                         }
6546
6547                         if (player->s_stream_caps && elem_src_subtitle)
6548                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6549                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6550
6551                         need_state_holder = FALSE;
6552
6553                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6554                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6555                                 LOGE("failed to commit\n");
6556                 }
6557                 break;
6558         /* appsrc */
6559         case MM_PLAYER_URI_TYPE_MEM:
6560                 {
6561                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6562
6563                         LOGD("mem src is selected\n");
6564
6565                         element = gst_element_factory_make("appsrc", "mem-source");
6566                         if (!element) {
6567                                 LOGE("failed to create appsrc element\n");
6568                                 break;
6569                         }
6570
6571                         g_object_set(element, "stream-type", stream_type, NULL);
6572                         g_object_set(element, "size", player->mem_buf.len, NULL);
6573                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6574
6575                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6576                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6577                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6578                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6579                 }
6580                 break;
6581         case MM_PLAYER_URI_TYPE_URL:
6582                 break;
6583
6584         case MM_PLAYER_URI_TYPE_TEMP:
6585                 break;
6586
6587         case MM_PLAYER_URI_TYPE_NONE:
6588         default:
6589                 break;
6590         }
6591
6592         /* check source element is OK */
6593         if (!element) {
6594                 LOGE("no source element was created.\n");
6595                 goto INIT_ERROR;
6596         }
6597
6598         /* take source element */
6599         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6600         mainbin[MMPLAYER_M_SRC].gst = element;
6601         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6602
6603         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6604                 player->streamer = __mm_player_streaming_create();
6605                 __mm_player_streaming_initialize(player->streamer);
6606         }
6607
6608         if (MMPLAYER_IS_HTTP_PD(player)) {
6609                 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6610
6611                 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6612                 element = gst_element_factory_make("queue2", "queue2");
6613                 if (!element) {
6614                         LOGE("failed to create http streaming buffer element\n");
6615                         goto INIT_ERROR;
6616                 }
6617
6618                 /* take it */
6619                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6620                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6621                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6622
6623                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6624
6625                 __mm_player_streaming_set_queue2(player->streamer,
6626                                 element,
6627                                 TRUE,
6628                                 player->ini.http_max_size_bytes,
6629                                 pre_buffering_time,
6630                                 1.0,
6631                                 player->ini.http_buffering_limit,
6632                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6633                                 NULL,
6634                                 0);
6635         }
6636         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6637                 if (player->v_stream_caps) {
6638                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6639                         if (!es_video_queue) {
6640                                 LOGE("create es_video_queue for es player failed\n");
6641                                 goto INIT_ERROR;
6642                         }
6643                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6644                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6645                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6646                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6647
6648                         /* Adding audio appsrc to bucket */
6649                         if (player->a_stream_caps && elem_src_audio) {
6650                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6651                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6652                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6653
6654                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6655                                 if (!es_audio_queue) {
6656                                         LOGE("create es_audio_queue for es player failed\n");
6657                                         goto INIT_ERROR;
6658                                 }
6659                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6660
6661                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6662                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6663                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6664                         }
6665                 } else if (player->a_stream_caps) {
6666                         /* Only audio stream, no video */
6667                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6668                         if (!es_audio_queue) {
6669                                 LOGE("create es_audio_queue for es player failed\n");
6670                                 goto INIT_ERROR;
6671                         }
6672                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6673                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6674                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6675                 }
6676
6677                 if (player->s_stream_caps && elem_src_subtitle) {
6678                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6679                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6680                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6681
6682                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6683                         if (!es_subtitle_queue) {
6684                                 LOGE("create es_subtitle_queue for es player failed\n");
6685                                 goto INIT_ERROR;
6686                         }
6687                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6688                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6689                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6690                 }
6691         }
6692
6693         /* create autoplugging element if src element is not a rtsp src */
6694         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6695                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6696                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6697                 element = NULL;
6698                 enum MainElementID elemId = MMPLAYER_M_NUM;
6699
6700                 if ((player->use_decodebin) &&
6701                         ((MMPLAYER_IS_HTTP_PD(player)) ||
6702                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6703                         elemId = MMPLAYER_M_AUTOPLUG;
6704                         element = __mmplayer_create_decodebin(player);
6705                         if (element) {
6706                                 /* default size of mq in decodebin is 2M
6707                                  * but it can cause blocking issue during seeking depends on content. */
6708                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6709                         }
6710                         need_state_holder = FALSE;
6711                 } else {
6712                         elemId = MMPLAYER_M_TYPEFIND;
6713                         element = gst_element_factory_make("typefind", "typefinder");
6714                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6715                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6716                 }
6717
6718
6719                 /* check autoplug element is OK */
6720                 if (!element) {
6721                         LOGE("can not create element(%d)\n", elemId);
6722                         goto INIT_ERROR;
6723                 }
6724
6725                 mainbin[elemId].id = elemId;
6726                 mainbin[elemId].gst = element;
6727
6728                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6729         }
6730
6731         /* add elements to pipeline */
6732         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6733                 LOGE("Failed to add elements to pipeline\n");
6734                 goto INIT_ERROR;
6735         }
6736
6737
6738         /* linking elements in the bucket by added order. */
6739         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6740                 LOGE("Failed to link some elements\n");
6741                 goto INIT_ERROR;
6742         }
6743
6744
6745         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6746         if (need_state_holder) {
6747                 /* create */
6748                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6749                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6750
6751                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6752                         LOGE("fakesink element could not be created\n");
6753                         goto INIT_ERROR;
6754                 }
6755                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6756
6757                 /* take ownership of fakesink. we are reusing it */
6758                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6759
6760                 /* add */
6761                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6762                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6763                         LOGE("failed to add fakesink to bin\n");
6764                         goto INIT_ERROR;
6765                 }
6766         }
6767
6768         /* now we have completed mainbin. take it */
6769         player->pipeline->mainbin = mainbin;
6770
6771         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6772                 GstPad *srcpad = NULL;
6773
6774                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6775                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6776                         if (srcpad) {
6777                                 __mmplayer_gst_create_decoder(player,
6778                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6779                                                                                                 srcpad,
6780                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6781                                                                                                 "video_decodebin");
6782
6783                                 gst_object_unref(GST_OBJECT(srcpad));
6784                                 srcpad = NULL;
6785                         }
6786                 }
6787
6788                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6789                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6790                         if (srcpad) {
6791                                 __mmplayer_gst_create_decoder(player,
6792                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6793                                                                                                 srcpad,
6794                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6795                                                                                                 "audio_decodebin");
6796
6797                                 gst_object_unref(GST_OBJECT(srcpad));
6798                                 srcpad = NULL;
6799                         } // else error
6800                 } //  else error
6801
6802                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6803                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6804         }
6805
6806         /* connect bus callback */
6807         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6808         if (!bus) {
6809                 LOGE("cannot get bus from pipeline.\n");
6810                 goto INIT_ERROR;
6811         }
6812
6813         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6814
6815         player->context.thread_default = g_main_context_get_thread_default();
6816
6817         if (NULL == player->context.thread_default) {
6818                 player->context.thread_default = g_main_context_default();
6819                 LOGD("thread-default context is the global default context");
6820         }
6821         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6822
6823         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6824         if (__mmplayer_check_subtitle(player)) {
6825                 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6826                         LOGE("fail to create subtitle src\n");
6827         }
6828
6829         /* set sync handler to get tag synchronously */
6830         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6831
6832         /* finished */
6833         gst_object_unref(GST_OBJECT(bus));
6834         g_list_free(element_bucket);
6835
6836         MMPLAYER_FLEAVE();
6837
6838         return MM_ERROR_NONE;
6839
6840 INIT_ERROR:
6841
6842         __mmplayer_gst_destroy_pipeline(player);
6843         g_list_free(element_bucket);
6844
6845         if (mainbin) {
6846                 /* release element which are not added to bin */
6847                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6848                         /* NOTE : skip pipeline */
6849                         if (mainbin[i].gst) {
6850                                 GstObject* parent = NULL;
6851                                 parent = gst_element_get_parent(mainbin[i].gst);
6852
6853                                 if (!parent) {
6854                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6855                                         mainbin[i].gst = NULL;
6856                                 } else
6857                                         gst_object_unref(GST_OBJECT(parent));
6858                         }
6859                 }
6860
6861                 /* release pipeline with it's childs */
6862                 if (mainbin[MMPLAYER_M_PIPE].gst)
6863                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6864
6865                 MMPLAYER_FREEIF(mainbin);
6866         }
6867
6868         MMPLAYER_FREEIF(player->pipeline);
6869         return MM_ERROR_PLAYER_INTERNAL;
6870 }
6871
6872 static void
6873 __mmplayer_reset_gapless_state(mm_player_t* player)
6874 {
6875         MMPLAYER_FENTER();
6876         MMPLAYER_RETURN_IF_FAIL(player
6877                 && player->pipeline
6878                 && player->pipeline->audiobin
6879                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6880
6881         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6882
6883         MMPLAYER_FLEAVE();
6884         return;
6885 }
6886
6887 static int
6888 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6889 {
6890         gint timeout = 0;
6891         int ret = MM_ERROR_NONE;
6892
6893         MMPLAYER_FENTER();
6894
6895         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6896
6897         /* cleanup stuffs */
6898         MMPLAYER_FREEIF(player->type);
6899         player->have_dynamic_pad = FALSE;
6900         player->no_more_pad = FALSE;
6901         player->num_dynamic_pad = 0;
6902         player->demux_pad_index = 0;
6903         player->subtitle_language_list = NULL;
6904         player->use_deinterleave = FALSE;
6905         player->max_audio_channels = 0;
6906         player->video_share_api_delta = 0;
6907         player->video_share_clock_delta = 0;
6908         player->video_hub_download_mode = 0;
6909         __mmplayer_reset_gapless_state(player);
6910
6911         if (player->streamer) {
6912                 __mm_player_streaming_deinitialize(player->streamer);
6913                 __mm_player_streaming_destroy(player->streamer);
6914                 player->streamer = NULL;
6915         }
6916
6917         /* cleanup unlinked mime type */
6918         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6919         MMPLAYER_FREEIF(player->unlinked_video_mime);
6920         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6921
6922         /* cleanup running stuffs */
6923         __mmplayer_cancel_eos_timer(player);
6924
6925         /* cleanup gst stuffs */
6926         if (player->pipeline) {
6927                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6928                 GstTagList* tag_list = player->pipeline->tag_list;
6929
6930                 /* first we need to disconnect all signal hander */
6931                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6932
6933                 /* disconnecting bus watch */
6934                 if (player->bus_watcher)
6935                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6936                 player->bus_watcher = 0;
6937
6938                 if (mainbin) {
6939                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6940                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6941                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6942                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6943                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6944                         gst_object_unref(bus);
6945
6946                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6947                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6948                         if (ret != MM_ERROR_NONE) {
6949                                 LOGE("fail to change state to NULL\n");
6950                                 return MM_ERROR_PLAYER_INTERNAL;
6951                         }
6952
6953                         LOGW("succeeded in chaning state to NULL\n");
6954
6955                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6956
6957                         /* free fakesink */
6958                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6959                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6960
6961                         /* free avsysaudiosink
6962                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6963                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6964                         */
6965                         MMPLAYER_FREEIF(audiobin);
6966                         MMPLAYER_FREEIF(videobin);
6967                         MMPLAYER_FREEIF(textbin);
6968                         MMPLAYER_FREEIF(mainbin);
6969                 }
6970
6971                 if (tag_list)
6972                         gst_tag_list_free(tag_list);
6973
6974                 MMPLAYER_FREEIF(player->pipeline);
6975         }
6976         MMPLAYER_FREEIF(player->album_art);
6977
6978         if (player->v_stream_caps) {
6979                 gst_caps_unref(player->v_stream_caps);
6980                 player->v_stream_caps = NULL;
6981         }
6982         if (player->a_stream_caps) {
6983                 gst_caps_unref(player->a_stream_caps);
6984                 player->a_stream_caps = NULL;
6985         }
6986
6987         if (player->s_stream_caps) {
6988                 gst_caps_unref(player->s_stream_caps);
6989                 player->s_stream_caps = NULL;
6990         }
6991         _mmplayer_track_destroy(player);
6992
6993         if (player->sink_elements)
6994                 g_list_free(player->sink_elements);
6995         player->sink_elements = NULL;
6996
6997         if (player->bufmgr) {
6998                 tbm_bufmgr_deinit(player->bufmgr);
6999                 player->bufmgr = NULL;
7000         }
7001
7002         LOGW("finished destroy pipeline\n");
7003
7004         MMPLAYER_FLEAVE();
7005
7006         return ret;
7007 }
7008
7009 static int __gst_realize(mm_player_t* player) // @
7010 {
7011         gint timeout = 0;
7012         int ret = MM_ERROR_NONE;
7013
7014         MMPLAYER_FENTER();
7015
7016         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7017
7018         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7019
7020         ret = __mmplayer_gst_create_pipeline(player);
7021         if (ret) {
7022                 LOGE("failed to create pipeline\n");
7023                 return ret;
7024         }
7025
7026         /* set pipeline state to READY */
7027         /* NOTE : state change to READY must be performed sync. */
7028         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7029         ret = __mmplayer_gst_set_state(player,
7030                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7031
7032         if (ret != MM_ERROR_NONE) {
7033                 /* return error if failed to set state */
7034                 LOGE("failed to set READY state");
7035                 return ret;
7036         } else
7037                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7038
7039         /* create dot before error-return. for debugging */
7040         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7041
7042         MMPLAYER_FLEAVE();
7043
7044         return ret;
7045 }
7046
7047 static int __gst_unrealize(mm_player_t* player) // @
7048 {
7049         int ret = MM_ERROR_NONE;
7050
7051         MMPLAYER_FENTER();
7052
7053         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7054
7055         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7056         MMPLAYER_PRINT_STATE(player);
7057
7058         /* release miscellaneous information */
7059         __mmplayer_release_misc(player);
7060
7061         /* destroy pipeline */
7062         ret = __mmplayer_gst_destroy_pipeline(player);
7063         if (ret != MM_ERROR_NONE) {
7064                 LOGE("failed to destory pipeline\n");
7065                 return ret;
7066         }
7067
7068         /* release miscellaneous information.
7069            these info needs to be released after pipeline is destroyed. */
7070         __mmplayer_release_misc_post(player);
7071
7072         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7073
7074         MMPLAYER_FLEAVE();
7075
7076         return ret;
7077 }
7078
7079 static int __gst_pending_seek(mm_player_t* player)
7080 {
7081         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7082         int ret = MM_ERROR_NONE;
7083
7084         MMPLAYER_FENTER();
7085
7086         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7087
7088         if (!player->pending_seek.is_pending) {
7089                 LOGD("pending seek is not reserved. nothing to do.\n");
7090                 return ret;
7091         }
7092
7093         /* check player state if player could pending seek or not. */
7094         current_state = MMPLAYER_CURRENT_STATE(player);
7095
7096         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7097                 LOGW("try to pending seek in %s state, try next time. \n",
7098                         MMPLAYER_STATE_GET_NAME(current_state));
7099                 return ret;
7100         }
7101
7102         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7103
7104         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7105
7106         if (MM_ERROR_NONE != ret)
7107                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7108
7109         player->pending_seek.is_pending = FALSE;
7110
7111         MMPLAYER_FLEAVE();
7112
7113         return ret;
7114 }
7115
7116 static int __gst_start(mm_player_t* player) // @
7117 {
7118         gboolean sound_extraction = 0;
7119         int ret = MM_ERROR_NONE;
7120         gboolean async = FALSE;
7121
7122         MMPLAYER_FENTER();
7123
7124         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7125
7126         /* get sound_extraction property */
7127         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7128
7129         /* NOTE : if SetPosition was called before Start. do it now */
7130         /* streaming doesn't support it. so it should be always sync */
7131         /* !!create one more api to check if there is pending seek rather than checking variables */
7132         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7133                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7134                 ret = __gst_pause(player, FALSE);
7135                 if (ret != MM_ERROR_NONE) {
7136                         LOGE("failed to set state to PAUSED for pending seek\n");
7137                         return ret;
7138                 }
7139
7140                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7141
7142                 if (sound_extraction) {
7143                         LOGD("setting pcm extraction\n");
7144
7145                         ret = __mmplayer_set_pcm_extraction(player);
7146                         if (MM_ERROR_NONE != ret) {
7147                                 LOGW("failed to set pcm extraction\n");
7148                                 return ret;
7149                         }
7150                 } else {
7151                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7152                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7153                 }
7154         }
7155
7156         LOGD("current state before doing transition");
7157         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7158         MMPLAYER_PRINT_STATE(player);
7159
7160         /* set pipeline state to PLAYING  */
7161         if (player->es_player_push_mode)
7162                 async = TRUE;
7163         /* set pipeline state to PLAYING  */
7164         ret = __mmplayer_gst_set_state(player,
7165                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7166
7167         if (ret == MM_ERROR_NONE) {
7168                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7169         } else {
7170                 LOGE("failed to set state to PLAYING");
7171                 return ret;
7172         }
7173
7174         /* generating debug info before returning error */
7175         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7176
7177         MMPLAYER_FLEAVE();
7178
7179         return ret;
7180 }
7181
7182 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7183 {
7184         MMPLAYER_FENTER();
7185
7186         MMPLAYER_RETURN_IF_FAIL(player
7187                 && player->pipeline
7188                 && player->pipeline->audiobin
7189                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7190
7191         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7192
7193         usleep(time);
7194
7195         MMPLAYER_FLEAVE();
7196 }
7197
7198 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7199 {
7200         MMPLAYER_FENTER();
7201
7202         MMPLAYER_RETURN_IF_FAIL(player
7203                 && player->pipeline
7204                 && player->pipeline->audiobin
7205                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7206
7207         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
7208
7209         MMPLAYER_FLEAVE();
7210 }
7211
7212 static int __gst_stop(mm_player_t* player) // @
7213 {
7214         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7215         MMHandleType attrs = 0;
7216         gboolean fadedown = FALSE;
7217         gboolean rewind = FALSE;
7218         gint timeout = 0;
7219         int ret = MM_ERROR_NONE;
7220         gboolean async = FALSE;
7221
7222         MMPLAYER_FENTER();
7223
7224         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7225         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7226
7227         LOGD("current state before doing transition");
7228         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7229         MMPLAYER_PRINT_STATE(player);
7230
7231         attrs = MMPLAYER_GET_ATTRS(player);
7232         if (!attrs) {
7233                 LOGE("cannot get content attribute\n");
7234                 return MM_ERROR_PLAYER_INTERNAL;
7235         }
7236
7237         mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7238
7239         /* enable fadedown */
7240         if (fadedown || player->sound_focus.by_asm_cb)
7241                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7242
7243         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7244         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7245
7246         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7247                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7248                 rewind = TRUE;
7249
7250         if (player->es_player_push_mode)
7251                 async = TRUE;
7252         /* set gst state */
7253         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7254
7255         /* disable fadeout */
7256         if (fadedown || player->sound_focus.by_asm_cb)
7257                 __mmplayer_undo_sound_fadedown(player);
7258
7259         /* return if set_state has failed */
7260         if (ret != MM_ERROR_NONE) {
7261                 LOGE("failed to set state.\n");
7262                 return ret;
7263         }
7264
7265         /* rewind */
7266         if (rewind) {
7267                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7268                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7269                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7270                         LOGW("failed to rewind\n");
7271                         ret = MM_ERROR_PLAYER_SEEK;
7272                 }
7273         }
7274
7275         /* initialize */
7276         player->sent_bos = FALSE;
7277
7278         if (player->es_player_push_mode) //for cloudgame
7279                 timeout = 0;
7280
7281         /* wait for seek to complete */
7282         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7283         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7284                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7285         } else {
7286                 LOGE("fail to stop player.\n");
7287                 ret = MM_ERROR_PLAYER_INTERNAL;
7288                 __mmplayer_dump_pipeline_state(player);
7289         }
7290
7291         /* generate dot file if enabled */
7292         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7293
7294         MMPLAYER_FLEAVE();
7295
7296         return ret;
7297 }
7298
7299 int __gst_pause(mm_player_t* player, gboolean async) // @
7300 {
7301         int ret = MM_ERROR_NONE;
7302
7303         MMPLAYER_FENTER();
7304
7305         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7306         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7307
7308         LOGD("current state before doing transition");
7309         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7310         MMPLAYER_PRINT_STATE(player);
7311
7312         /* set pipeline status to PAUSED */
7313         player->ignore_asyncdone = TRUE;
7314
7315         ret = __mmplayer_gst_set_state(player,
7316                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7317
7318         player->ignore_asyncdone = FALSE;
7319
7320         if (FALSE == async) {
7321                 if (ret != MM_ERROR_NONE) {
7322                         GstMessage *msg = NULL;
7323                         GTimer *timer = NULL;
7324                         gdouble MAX_TIMEOUT_SEC = 3;
7325
7326                         LOGE("failed to set state to PAUSED");
7327
7328                         if (player->msg_posted) {
7329                                 LOGE("error msg is already posted.");
7330                                 return ret;
7331                         }
7332
7333                         timer = g_timer_new();
7334                         g_timer_start(timer);
7335
7336                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7337
7338                         do {
7339                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7340                                 if (msg) {
7341                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7342                                                 GError *error = NULL;
7343
7344                                                 /* parse error code */
7345                                                 gst_message_parse_error(msg, &error, NULL);
7346
7347                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7348                                                         /* Note : the streaming error from the streaming source is handled
7349                                                          *   using __mmplayer_handle_streaming_error.
7350                                                          */
7351                                                         __mmplayer_handle_streaming_error(player, msg);
7352
7353                                                 } else if (error) {
7354                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7355
7356                                                         if (error->domain == GST_STREAM_ERROR)
7357                                                                 ret = __gst_handle_stream_error(player, error, msg);
7358                                                         else if (error->domain == GST_RESOURCE_ERROR)
7359                                                                 ret = __gst_handle_resource_error(player, error->code);
7360                                                         else if (error->domain == GST_LIBRARY_ERROR)
7361                                                                 ret = __gst_handle_library_error(player, error->code);
7362                                                         else if (error->domain == GST_CORE_ERROR)
7363                                                                 ret = __gst_handle_core_error(player, error->code);
7364                                                 }
7365                                                 player->msg_posted = TRUE;
7366                                         }
7367                                         gst_message_unref(msg);
7368                                 }
7369                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7370                         /* clean */
7371                         gst_object_unref(bus);
7372                         g_timer_stop(timer);
7373                         g_timer_destroy(timer);
7374
7375                         return ret;
7376
7377                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7378                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7379
7380                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7381
7382                 } else if (ret == MM_ERROR_NONE) {
7383
7384                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7385                 }
7386         }
7387
7388         /* generate dot file before returning error */
7389         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7390
7391         MMPLAYER_FLEAVE();
7392
7393         return ret;
7394 }
7395
7396 int __gst_resume(mm_player_t* player, gboolean async) // @
7397 {
7398         int ret = MM_ERROR_NONE;
7399         gint timeout = 0;
7400
7401         MMPLAYER_FENTER();
7402
7403         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7404                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7405
7406         LOGD("current state before doing transition");
7407         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7408         MMPLAYER_PRINT_STATE(player);
7409
7410         /* generate dot file before returning error */
7411         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7412
7413         if (async)
7414                 LOGD("do async state transition to PLAYING.\n");
7415
7416         /* set pipeline state to PLAYING */
7417         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7418
7419         ret = __mmplayer_gst_set_state(player,
7420                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7421         if (ret != MM_ERROR_NONE) {
7422                 LOGE("failed to set state to PLAYING\n");
7423                 return ret;
7424         } else {
7425                 if (async == FALSE) {
7426                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7427                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7428                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7429                 }
7430         }
7431
7432         /* generate dot file before returning error */
7433         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7434
7435         MMPLAYER_FLEAVE();
7436
7437         return ret;
7438 }
7439
7440 static int
7441 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7442 {
7443         unsigned long dur_msec = 0;
7444         gint64 dur_nsec = 0;
7445         gint64 pos_nsec = 0;
7446         gboolean ret = TRUE;
7447         gboolean accurated = FALSE;
7448         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7449
7450         MMPLAYER_FENTER();
7451         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7452         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7453
7454         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7455                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7456                 goto PENDING;
7457
7458         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7459                 /* check duration */
7460                 /* NOTE : duration cannot be zero except live streaming.
7461                  *              Since some element could have some timing problemn with quering duration, try again.
7462                  */
7463                 if (!player->duration) {
7464                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7465                         {
7466                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7467                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7468                                 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7469                                         player->pending_seek.is_pending = TRUE;
7470                                         player->pending_seek.format = format;
7471                                         player->pending_seek.pos = position;
7472                                         player->doing_seek = FALSE;
7473                                         MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7474                                         return MM_ERROR_NONE;
7475                                 } else
7476                                 goto SEEK_ERROR;
7477                         }
7478                         player->duration = dur_nsec;
7479                 }
7480
7481                 if (player->duration) {
7482                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7483                 } else {
7484                         LOGE("could not get the duration. fail to seek.\n");
7485                         goto SEEK_ERROR;
7486                 }
7487         }
7488         LOGD("playback rate: %f\n", player->playback_rate);
7489
7490         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7491         if (accurated)
7492                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7493         else
7494                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7495
7496         /* do seek */
7497         switch (format) {
7498         case MM_PLAYER_POS_FORMAT_TIME:
7499         {
7500                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7501                         /* check position is valid or not */
7502                         if (position > dur_msec)
7503                                 goto INVALID_ARGS;
7504
7505                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7506
7507                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7508                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7509                            This causes problem is position calculation during normal pause resume scenarios also.
7510                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7511                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7512                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7513                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7514                                         LOGW("getting current position failed in seek\n");
7515
7516                                 player->last_position = pos_nsec;
7517                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7518                         }
7519
7520                         if (player->doing_seek) {
7521                                 LOGD("not completed seek");
7522                                 return MM_ERROR_PLAYER_DOING_SEEK;
7523                         }
7524                 }
7525
7526                 if (!internal_called)
7527                         player->doing_seek = TRUE;
7528
7529                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7530
7531                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7532                         gint64 cur_time = 0;
7533
7534                         /* get current position */
7535                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7536
7537                         /* flush */
7538                         GstEvent *event = gst_event_new_seek(1.0,
7539                                                         GST_FORMAT_TIME,
7540                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7541                                                         GST_SEEK_TYPE_SET, cur_time,
7542                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7543                         if (event)
7544                                 __gst_send_event_to_sink(player, event);
7545
7546                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7547                                 __gst_pause(player, FALSE);
7548                 }
7549
7550                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7551                         that's why set position through property. */
7552                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7553                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7554                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7555                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7556
7557                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7558                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7559                                         gst_element_get_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7560                         player->doing_seek = FALSE;
7561                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7562                 } else {
7563                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7564                                                         GST_FORMAT_TIME, seek_flags,
7565                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7566                 }
7567
7568                 if (!ret) {
7569                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7570                         goto SEEK_ERROR;
7571                 }
7572         }
7573         break;
7574
7575         case MM_PLAYER_POS_FORMAT_PERCENT:
7576         {
7577                 LOGD("seeking to(%lu)%% \n", position);
7578
7579                 if (player->doing_seek) {
7580                         LOGD("not completed seek");
7581                         return MM_ERROR_PLAYER_DOING_SEEK;
7582                 }
7583
7584                 if (!internal_called)
7585                         player->doing_seek = TRUE;
7586
7587                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7588                 pos_nsec = (gint64)((position * player->duration) / 100);
7589                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7590                                                 GST_FORMAT_TIME, seek_flags,
7591                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7592                 if (!ret) {
7593                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7594                         goto SEEK_ERROR;
7595                 }
7596         }
7597         break;
7598
7599         default:
7600                 goto INVALID_ARGS;
7601         }
7602
7603         /* NOTE : store last seeking point to overcome some bad operation
7604           *     (returning zero when getting current position) of some elements
7605           */
7606         player->last_position = pos_nsec;
7607
7608         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7609         if (player->playback_rate > 1.0)
7610                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7611
7612         MMPLAYER_FLEAVE();
7613         return MM_ERROR_NONE;
7614
7615 PENDING:
7616         player->pending_seek.is_pending = TRUE;
7617         player->pending_seek.format = format;
7618         player->pending_seek.pos = position;
7619
7620         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7621                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7622
7623         return MM_ERROR_NONE;
7624
7625 INVALID_ARGS:
7626         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7627         return MM_ERROR_INVALID_ARGUMENT;
7628
7629 SEEK_ERROR:
7630         player->doing_seek = FALSE;
7631         return MM_ERROR_PLAYER_SEEK;
7632 }
7633
7634 #define TRICKPLAY_OFFSET GST_MSECOND
7635
7636 static int
7637 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7638 {
7639         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7640         gint64 pos_msec = 0;
7641         gboolean ret = TRUE;
7642
7643         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7644                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7645
7646         current_state = MMPLAYER_CURRENT_STATE(player);
7647
7648         /* NOTE : query position except paused state to overcome some bad operation
7649          * please refer to below comments in details
7650          */
7651         if (current_state != MM_PLAYER_STATE_PAUSED)
7652                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7653
7654         /* NOTE : get last point to overcome some bad operation of some elements
7655          *(returning zero when getting current position in paused state
7656          * and when failed to get postion during seeking
7657          */
7658         if ((current_state == MM_PLAYER_STATE_PAUSED)
7659                 || (!ret)) {
7660                 //|| (player->last_position != 0 && pos_msec == 0))
7661                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7662
7663                 if (player->playback_rate < 0.0)
7664                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7665                 else
7666                         pos_msec = player->last_position;
7667
7668                 if (!ret)
7669                         pos_msec = player->last_position;
7670                 else
7671                         player->last_position = pos_msec;
7672
7673                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7674
7675         } else {
7676                 if (player->duration > 0 && pos_msec > player->duration)
7677                         pos_msec = player->duration;
7678
7679                 if (player->sound_focus.keep_last_pos) {
7680                         LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7681                         pos_msec = player->last_position;
7682                 } else
7683                         player->last_position = pos_msec;
7684         }
7685
7686         switch (format) {
7687         case MM_PLAYER_POS_FORMAT_TIME:
7688                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7689                 break;
7690
7691         case MM_PLAYER_POS_FORMAT_PERCENT:
7692         {
7693                 if (player->duration <= 0) {
7694                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7695                         *position = 0;
7696                 } else {
7697                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7698                         *position = pos_msec * 100 / player->duration;
7699                 }
7700                 break;
7701         }
7702         default:
7703                 return MM_ERROR_PLAYER_INTERNAL;
7704         }
7705
7706         return MM_ERROR_NONE;
7707 }
7708
7709
7710 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7711 {
7712 #define STREAMING_IS_FINISHED   0
7713 #define BUFFERING_MAX_PER       100
7714 #define DEFAULT_PER_VALUE       -1
7715 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7716
7717         MMPlayerGstElement *mainbin = NULL;
7718         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7719         gint64 buffered_total = 0;
7720         unsigned long position = 0;
7721         gint buffered_sec = -1;
7722         GstBufferingMode mode = GST_BUFFERING_STREAM;
7723         gint64 content_size_time = player->duration;
7724         guint64 content_size_bytes = player->http_content_size;
7725
7726         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7727                                                 player->pipeline &&
7728                                                 player->pipeline->mainbin,
7729                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7730
7731         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7732
7733         *start_pos = 0;
7734         *stop_pos = 0;
7735
7736         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7737                 /* and rtsp is not ready yet. */
7738                 LOGW("it's only used for http streaming case.\n");
7739                 return MM_ERROR_PLAYER_NO_OP;
7740         }
7741
7742         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7743                 LOGW("Time format is not supported yet.\n");
7744                 return MM_ERROR_INVALID_ARGUMENT;
7745         }
7746
7747         if (content_size_time <= 0 || content_size_bytes <= 0) {
7748                 LOGW("there is no content size.");
7749                 return MM_ERROR_NONE;
7750         }
7751
7752         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7753                 LOGW("fail to get current position.");
7754                 return MM_ERROR_NONE;
7755         }
7756
7757         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7758                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7759
7760         mainbin = player->pipeline->mainbin;
7761         start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7762
7763         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7764                 GstQuery *query = NULL;
7765                 gint byte_in_rate = 0, byte_out_rate = 0;
7766                 gint64 estimated_total = 0;
7767
7768                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7769                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7770                         LOGW("fail to get buffering query from queue2");
7771                         if (query)
7772                                 gst_query_unref(query);
7773                         return MM_ERROR_NONE;
7774                 }
7775
7776                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7777                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7778
7779                 if (mode == GST_BUFFERING_STREAM) {
7780                         /* using only queue in case of push mode(ts / mp3) */
7781                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7782                                 GST_FORMAT_BYTES, &buffered_total)) {
7783                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7784                                 stop_per = 100 * buffered_total / content_size_bytes;
7785                         }
7786                 } else {
7787                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7788                         guint idx = 0;
7789                         guint num_of_ranges = 0;
7790                         gint64 start_byte = 0, stop_byte = 0;
7791
7792                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7793                         if (estimated_total != STREAMING_IS_FINISHED) {
7794                                 /* buffered size info from queue2 */
7795                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7796                                 for (idx = 0; idx < num_of_ranges; idx++) {
7797                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7798                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7799
7800                                         buffered_total += (stop_byte - start_byte);
7801                                 }
7802                         } else
7803                                 stop_per = BUFFERING_MAX_PER;
7804                 }
7805                 gst_query_unref(query);
7806         }
7807
7808         if (stop_per == DEFAULT_PER_VALUE) {
7809                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7810                 if (dur_sec > 0) {
7811                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7812
7813                         /* buffered size info from multiqueue */
7814                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7815                                 guint curr_size_bytes = 0;
7816                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7817                                         "curr-size-bytes", &curr_size_bytes, NULL);
7818                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7819                                 buffered_total += curr_size_bytes;
7820                         }
7821
7822                         if (avg_byterate > 0)
7823                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7824                         else if (player->total_maximum_bitrate > 0)
7825                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7826                         else if (player->total_bitrate > 0)
7827                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7828
7829                         if (buffered_sec >= 0)
7830                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7831                 }
7832         }
7833
7834         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7835         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7836
7837         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7838                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7839
7840         return MM_ERROR_NONE;
7841 }
7842
7843 static int
7844 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7845 {
7846         MMPLAYER_FENTER();
7847
7848         if (!player) {
7849                 LOGW("set_message_callback is called with invalid player handle\n");
7850                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7851         }
7852
7853         player->msg_cb = callback;
7854         player->msg_cb_param = user_param;
7855
7856         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7857
7858         MMPLAYER_FLEAVE();
7859
7860         return MM_ERROR_NONE;
7861 }
7862
7863 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7864 {
7865         int ret = MM_ERROR_PLAYER_INVALID_URI;
7866         char *path = NULL;
7867
7868         MMPLAYER_FENTER();
7869
7870         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7871         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7872         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7873
7874         memset(data, 0, sizeof(MMPlayerParseProfile));
7875
7876         if ((path = strstr(uri, "es_buff://"))) {
7877                 if (strlen(path)) {
7878                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7879                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7880                         ret = MM_ERROR_NONE;
7881                 }
7882         } else if ((path = strstr(uri, "rtsp://"))) {
7883                 if (strlen(path)) {
7884                         if ((path = strstr(uri, "/wfd1.0/"))) {
7885                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7886                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7887                                 ret = MM_ERROR_NONE;
7888                                 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7889                         } else {
7890                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7891                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7892                                 ret = MM_ERROR_NONE;
7893                         }
7894                 }
7895         } else if ((path = strstr(uri, "http://"))) {
7896                 if (strlen(path)) {
7897                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7898
7899                         if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7900                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7901                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7902                         else
7903                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7904
7905                         ret = MM_ERROR_NONE;
7906                 }
7907         } else if ((path = strstr(uri, "https://"))) {
7908                 if (strlen(path)) {
7909                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7910
7911                 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7912                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7913                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7914
7915                         data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7916
7917                         ret = MM_ERROR_NONE;
7918                 }
7919         } else if ((path = strstr(uri, "rtspu://"))) {
7920                 if (strlen(path)) {
7921                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7922                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7923                         ret = MM_ERROR_NONE;
7924                 }
7925         } else if ((path = strstr(uri, "rtspr://"))) {
7926                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7927                 char *separater = strstr(path, "*");
7928
7929                 if (separater) {
7930                         int urgent_len = 0;
7931                         char *urgent = separater + strlen("*");
7932
7933                         if ((urgent_len = strlen(urgent))) {
7934                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7935                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7936                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7937                                 ret = MM_ERROR_NONE;
7938                         }
7939                 }
7940         } else if ((path = strstr(uri, "mms://"))) {
7941                 if (strlen(path)) {
7942                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7943                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7944                         ret = MM_ERROR_NONE;
7945                 }
7946         } else if ((path = strstr(uri, "mem://"))) {
7947                 if (strlen(path)) {
7948                         int mem_size = 0;
7949                         char *buffer = NULL;
7950                         char *seperator = strchr(path, ',');
7951                         char ext[100] = {0,}, size[100] = {0,};
7952
7953                         if (seperator) {
7954                                 if ((buffer = strstr(path, "ext="))) {
7955                                         buffer += strlen("ext=");
7956
7957                                         if (strlen(buffer)) {
7958                                                 strncpy(ext, buffer, 99);
7959
7960                                                 if ((seperator = strchr(ext, ','))
7961                                                         || (seperator = strchr(ext, ' '))
7962                                                         || (seperator = strchr(ext, '\0'))) {
7963                                                         seperator[0] = '\0';
7964                                                 }
7965                                         }
7966                                 }
7967
7968                                 if ((buffer = strstr(path, "size="))) {
7969                                         buffer += strlen("size=");
7970
7971                                         if (strlen(buffer) > 0) {
7972                                                 strncpy(size, buffer, 99);
7973
7974                                                 if ((seperator = strchr(size, ','))
7975                                                         || (seperator = strchr(size, ' '))
7976                                                         || (seperator = strchr(size, '\0'))) {
7977                                                         seperator[0] = '\0';
7978                                                 }
7979
7980                                                 mem_size = atoi(size);
7981                                         }
7982                                 }
7983                         }
7984
7985                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7986                         if (mem_size && param) {
7987                                 data->mem = param;
7988                                 data->mem_size = mem_size;
7989                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7990                                 ret = MM_ERROR_NONE;
7991                         }
7992                 }
7993         } else {
7994                 gchar *location = NULL;
7995                 GError *err = NULL;
7996
7997                 if ((path = strstr(uri, "file://"))) {
7998
7999                         location = g_filename_from_uri(uri, NULL, &err);
8000
8001                         if (!location || (err != NULL)) {
8002                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8003                                  (err != NULL) ? err->message : "unknown error");
8004
8005                           if (err) g_error_free(err);
8006                           if (location) g_free(location);
8007
8008                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8009                           goto exit;
8010                         }
8011
8012                         LOGD("path from uri: %s", location);
8013                 }
8014
8015                 path = (location != NULL) ? (location) : ((char*)uri);
8016                 int file_stat = MM_ERROR_NONE;
8017
8018                 file_stat = util_exist_file_path(path);
8019
8020                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8021                 if (file_stat == MM_ERROR_NONE) {
8022                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8023
8024                         if (util_is_sdp_file(path)) {
8025                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8026                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8027                         } else {
8028                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8029                         }
8030                         ret = MM_ERROR_NONE;
8031                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8032                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8033                 } else {
8034                         LOGE("invalid uri, could not play..\n");
8035                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8036                 }
8037
8038                 if (location) g_free(location);
8039         }
8040
8041 exit:
8042         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8043                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8044         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8045                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8046
8047         /* dump parse result */
8048         SECURE_LOGW("incomming uri : %s\n", uri);
8049         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8050                 data->uri_type, data->mem, data->mem_size, data->urgent);
8051
8052         MMPLAYER_FLEAVE();
8053
8054         return ret;
8055 }
8056
8057 gboolean _asm_postmsg(gpointer *data)
8058 {
8059         mm_player_t* player = (mm_player_t*)data;
8060         MMMessageParamType msg = {0, };
8061
8062         MMPLAYER_FENTER();
8063         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8064         LOGW("get notified");
8065
8066         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8067                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8068                 LOGW("dispatched");
8069                 return FALSE;
8070         }
8071
8072
8073         msg.union_type = MM_MSG_UNION_CODE;
8074         msg.code = player->sound_focus.focus_changed_msg;
8075
8076         MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8077         player->resume_event_id = 0;
8078
8079         LOGW("dispatched");
8080         return FALSE;
8081 }
8082
8083 gboolean _asm_lazy_pause(gpointer *data)
8084 {
8085         mm_player_t* player = (mm_player_t*)data;
8086         int ret = MM_ERROR_NONE;
8087
8088         MMPLAYER_FENTER();
8089
8090         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8091
8092         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8093                 LOGD("Ready to proceed lazy pause\n");
8094                 ret = _mmplayer_pause((MMHandleType)player);
8095                 if (MM_ERROR_NONE != ret)
8096                         LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8097         } else
8098                 LOGD("Invalid state to proceed lazy pause\n");
8099
8100         /* unset mute */
8101         if (player->pipeline && player->pipeline->audiobin)
8102                 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8103
8104         player->sound_focus.by_asm_cb = FALSE; //should be reset here
8105
8106         MMPLAYER_FLEAVE();
8107
8108         return FALSE;
8109 }
8110
8111 gboolean
8112 __mmplayer_can_do_interrupt(mm_player_t *player)
8113 {
8114         if (!player || !player->pipeline || !player->attrs) {
8115                 LOGW("not initialized");
8116                 goto FAILED;
8117         }
8118
8119         if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8120                 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8121                 goto FAILED;
8122         }
8123
8124         /* check if seeking */
8125         if (player->doing_seek) {
8126                 MMMessageParamType msg_param;
8127                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8128                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8129                 player->doing_seek = FALSE;
8130                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8131                 goto FAILED;
8132         }
8133
8134         /* check other thread */
8135         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8136                 LOGW("locked already, cmd state : %d", player->cmd);
8137
8138                 /* check application command */
8139                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8140                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8141
8142                         /* lock will be released at mrp_resource_release_cb() */
8143                         MMPLAYER_CMD_LOCK(player);
8144                         goto INTERRUPT;
8145                 }
8146                 LOGW("nothing to do");
8147                 goto FAILED;
8148         } else {
8149                 LOGW("can interrupt immediately");
8150                 goto INTERRUPT;
8151         }
8152
8153 FAILED:    /* with CMD UNLOCKED */
8154         return FALSE;
8155
8156 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8157         return TRUE;
8158 }
8159
8160 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8161 static int
8162 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8163 {
8164         int ret = MM_ERROR_NONE;
8165         MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8166
8167         if (strstr(reason_for_change, "alarm")) {
8168                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8169
8170         } else if (strstr(reason_for_change, "notification")) {
8171                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8172
8173         } else if (strstr(reason_for_change, "emergency")) {
8174                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8175
8176         } else if (strstr(reason_for_change, "call-voice") ||
8177                                 strstr(reason_for_change, "call-video") ||
8178                                 strstr(reason_for_change, "voip") ||
8179                                 strstr(reason_for_change, "ringtone-voip") ||
8180                                 strstr(reason_for_change, "ringtone-call")) {
8181                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8182
8183         } else if (strstr(reason_for_change, "media") ||
8184                                 strstr(reason_for_change, "radio") ||
8185                                 strstr(reason_for_change, "loopback") ||
8186                                 strstr(reason_for_change, "system") ||
8187                                 strstr(reason_for_change, "voice-information") ||
8188                                 strstr(reason_for_change, "voice-recognition")) {
8189                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8190
8191         } else {
8192                 ret = MM_ERROR_INVALID_ARGUMENT;
8193                 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8194                 goto DONE;
8195         }
8196
8197         if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8198                 /* can acqurie */
8199                 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8200
8201         LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8202         *msg = focus_msg;
8203
8204 DONE:
8205         return ret;
8206 }
8207
8208 /* FIXME: will be updated with new funct */
8209 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8210                                        const char *reason_for_change, const char *additional_info, void *user_data)
8211 {
8212         mm_player_t* player = (mm_player_t*) user_data;
8213         int result = MM_ERROR_NONE;
8214         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8215
8216         LOGW("focus watch notified");
8217
8218         if (!__mmplayer_can_do_interrupt(player)) {
8219                 LOGW("no need to interrupt, so leave");
8220                 goto EXIT_WITHOUT_UNLOCK;
8221         }
8222
8223         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8224                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8225                 goto EXIT;
8226         }
8227
8228         LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8229                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8230
8231         player->sound_focus.cb_pending = TRUE;
8232         player->sound_focus.by_asm_cb = TRUE;
8233
8234         if (focus_state == FOCUS_IS_ACQUIRED) {
8235                 LOGW("watch: FOCUS_IS_ACQUIRED");
8236                 player->sound_focus.acquired = TRUE;
8237
8238                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8239                         player->sound_focus.focus_changed_msg = (int)msg;
8240
8241                 if (strstr(reason_for_change, "call") ||
8242                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8243                         strstr(reason_for_change, "alarm") ||
8244                         strstr(reason_for_change, "media")) {
8245                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8246                                 // hold 0.7 second to excute "fadedown mute" effect
8247                                 LOGW("do fade down->pause->undo fade down");
8248
8249                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8250
8251                                 result = _mmplayer_pause((MMHandleType)player);
8252                                 if (result != MM_ERROR_NONE) {
8253                                         LOGW("fail to set Pause state by asm");
8254                                         goto EXIT;
8255                                 }
8256                                 __mmplayer_undo_sound_fadedown(player);
8257                         } else
8258                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8259                                 _mmplayer_unrealize((MMHandleType)player);
8260                 } else {
8261                         LOGW("pause immediately");
8262                         result = _mmplayer_pause((MMHandleType)player);
8263                         if (result != MM_ERROR_NONE) {
8264                                 LOGW("fail to set Pause state by asm");
8265                                 goto EXIT;
8266                         }
8267                 }
8268         } else if (focus_state == FOCUS_IS_RELEASED) {
8269                 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8270                 player->sound_focus.acquired = FALSE;
8271                 player->sound_focus.antishock = TRUE;
8272                 player->sound_focus.by_asm_cb = FALSE;
8273
8274                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8275                         player->sound_focus.focus_changed_msg = (int)msg;
8276
8277                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8278                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8279                 goto DONE;
8280         } else
8281                 LOGW("unknown focus state %d", focus_state);
8282
8283 DONE:
8284         player->sound_focus.by_asm_cb = FALSE;
8285         player->sound_focus.cb_pending = FALSE;
8286
8287 EXIT:
8288         MMPLAYER_CMD_UNLOCK(player);
8289         LOGW("dispatched");
8290         return;
8291
8292 EXIT_WITHOUT_UNLOCK:
8293         LOGW("dispatched");
8294         return;
8295 }
8296
8297 void
8298 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8299         const char *reason_for_change, int option, const char *additional_info, void *user_data)
8300 {
8301         mm_player_t* player = (mm_player_t*) user_data;
8302         int result = MM_ERROR_NONE;
8303         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8304
8305         LOGW("get focus notified");
8306
8307         if (!__mmplayer_can_do_interrupt(player)) {
8308                 LOGW("no need to interrupt, so leave");
8309                 goto EXIT_WITHOUT_UNLOCK;
8310         }
8311
8312         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8313                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8314                 goto EXIT;
8315         }
8316
8317         LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8318                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8319
8320         player->sound_focus.cb_pending = TRUE;
8321         player->sound_focus.by_asm_cb = TRUE;
8322 //      player->sound_focus.event_src = event_src;
8323
8324         if (focus_state == FOCUS_IS_RELEASED) {
8325                 LOGW("FOCUS_IS_RELEASED");
8326                 player->sound_focus.acquired = FALSE;
8327
8328                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8329                         player->sound_focus.focus_changed_msg = (int)msg;
8330
8331                 if (strstr(reason_for_change, "call") ||
8332                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8333                         strstr(reason_for_change, "alarm") ||
8334                         strstr(reason_for_change, "media")) {
8335                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8336                                 //hold 0.7 second to excute "fadedown mute" effect
8337                                 LOGW("do fade down->pause->undo fade down");
8338
8339                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8340
8341                                 result = _mmplayer_pause((MMHandleType)player);
8342                                 if (result != MM_ERROR_NONE) {
8343                                         LOGW("fail to set Pause state by asm");
8344                                         goto EXIT;
8345                                 }
8346                                 __mmplayer_undo_sound_fadedown(player);
8347                         } else
8348                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8349                                 _mmplayer_unrealize((MMHandleType)player);
8350                 } else {
8351                         LOGW("pause immediately");
8352                         result = _mmplayer_pause((MMHandleType)player);
8353                         if (result != MM_ERROR_NONE) {
8354                                 LOGW("fail to set Pause state by asm");
8355                                 goto EXIT;
8356                         }
8357                 }
8358         } else if (focus_state == FOCUS_IS_ACQUIRED) {
8359                 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8360                 player->sound_focus.acquired = TRUE;
8361                 player->sound_focus.antishock = TRUE;
8362                 player->sound_focus.by_asm_cb = FALSE;
8363
8364                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8365                         player->sound_focus.focus_changed_msg = (int)msg;
8366
8367                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8368                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8369                 goto DONE;
8370         } else
8371                 LOGW("unknown focus state %d", focus_state);
8372
8373 DONE:
8374         player->sound_focus.by_asm_cb = FALSE;
8375         player->sound_focus.cb_pending = FALSE;
8376
8377 EXIT:
8378         MMPLAYER_CMD_UNLOCK(player);
8379         LOGW("dispatched");
8380         return;
8381
8382 EXIT_WITHOUT_UNLOCK:
8383         LOGW("dispatched");
8384         return;
8385 }
8386
8387
8388 int
8389 _mmplayer_create_player(MMHandleType handle) // @
8390 {
8391         int ret = MM_ERROR_PLAYER_INTERNAL;
8392         mm_player_t* player = MM_PLAYER_CAST(handle);
8393
8394         MMPLAYER_FENTER();
8395
8396         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8397
8398         /* initialize player state */
8399         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8400         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8401         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8402         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8403
8404         /* check current state */
8405         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8406
8407         /* construct attributes */
8408         player->attrs = _mmplayer_construct_attribute(handle);
8409
8410         if (!player->attrs) {
8411                 LOGE("Failed to construct attributes\n");
8412                 return ret;
8413         }
8414
8415         /* initialize gstreamer with configured parameter */
8416         if (!__mmplayer_init_gstreamer(player)) {
8417                 LOGE("Initializing gstreamer failed\n");
8418                 _mmplayer_deconstruct_attribute(handle);
8419                 return ret;
8420         }
8421
8422         /* initialize factories if not using decodebin */
8423         if (player->factories == NULL)
8424                 __mmplayer_init_factories(player);
8425
8426         /* create lock. note that g_tread_init() has already called in gst_init() */
8427         g_mutex_init(&player->fsink_lock);
8428
8429         /* create update tag lock */
8430         g_mutex_init(&player->update_tag_lock);
8431
8432         /* create repeat mutex */
8433         g_mutex_init(&player->repeat_thread_mutex);
8434
8435         /* create repeat cond */
8436         g_cond_init(&player->repeat_thread_cond);
8437
8438         /* create repeat thread */
8439         player->repeat_thread =
8440                 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8441         if (!player->repeat_thread) {
8442                 LOGE("failed to create repeat_thread(%s)");
8443                 g_mutex_clear(&player->repeat_thread_mutex);
8444                 g_cond_clear(&player->repeat_thread_cond);
8445                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8446                 goto ERROR;
8447         }
8448
8449         /* create next play mutex */
8450         g_mutex_init(&player->next_play_thread_mutex);
8451
8452         /* create next play cond */
8453         g_cond_init(&player->next_play_thread_cond);
8454
8455         /* create next play thread */
8456         player->next_play_thread =
8457                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8458         if (!player->next_play_thread) {
8459                 LOGE("failed to create next play thread");
8460                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8461                 g_mutex_clear(&player->next_play_thread_mutex);
8462                 g_cond_clear(&player->next_play_thread_cond);
8463                 goto ERROR;
8464         }
8465
8466         ret = _mmplayer_initialize_video_capture(player);
8467         if (ret != MM_ERROR_NONE) {
8468                 LOGE("failed to initialize video capture\n");
8469                 goto ERROR;
8470         }
8471
8472         /* initialize resource manager */
8473         if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8474                 LOGE("failed to initialize resource manager\n");
8475                 goto ERROR;
8476         }
8477
8478         if (MMPLAYER_IS_HTTP_PD(player)) {
8479                 player->pd_downloader = NULL;
8480                 player->pd_file_save_path = NULL;
8481         }
8482
8483         /* create video bo lock and cond */
8484         g_mutex_init(&player->video_bo_mutex);
8485         g_cond_init(&player->video_bo_cond);
8486
8487         /* create media stream callback mutex */
8488         g_mutex_init(&player->media_stream_cb_lock);
8489
8490         player->streaming_type = STREAMING_SERVICE_NONE;
8491
8492         /* give default value of audio effect setting */
8493         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8494         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8495
8496         player->play_subtitle = FALSE;
8497         player->use_textoverlay = FALSE;
8498         player->play_count = 0;
8499         player->use_decodebin = TRUE;
8500         player->ignore_asyncdone = FALSE;
8501         player->use_deinterleave = FALSE;
8502         player->max_audio_channels = 0;
8503         player->video_share_api_delta = 0;
8504         player->video_share_clock_delta = 0;
8505         player->has_closed_caption = FALSE;
8506         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8507         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8508         player->pending_resume = FALSE;
8509         if (player->ini.dump_element_keyword[0][0] == '\0')
8510                 player->ini.set_dump_element_flag = FALSE;
8511         else
8512                 player->ini.set_dump_element_flag = TRUE;
8513
8514         /* set player state to null */
8515         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8516         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8517
8518         return MM_ERROR_NONE;
8519
8520 ERROR:
8521         /* free lock */
8522         g_mutex_clear(&player->fsink_lock);
8523
8524         /* free update tag lock */
8525         g_mutex_clear(&player->update_tag_lock);
8526
8527         /* free thread */
8528         if (player->repeat_thread) {
8529                 player->repeat_thread_exit = TRUE;
8530                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8531
8532                 g_thread_join(player->repeat_thread);
8533                 player->repeat_thread = NULL;
8534
8535                 g_mutex_clear(&player->repeat_thread_mutex);
8536                 g_cond_clear(&player->repeat_thread_cond);
8537         }
8538
8539         /* free next play thread */
8540         if (player->next_play_thread) {
8541                 player->next_play_thread_exit = TRUE;
8542                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8543
8544                 g_thread_join(player->next_play_thread);
8545                 player->next_play_thread = NULL;
8546
8547                 g_mutex_clear(&player->next_play_thread_mutex);
8548                 g_cond_clear(&player->next_play_thread_cond);
8549         }
8550
8551         /* release attributes */
8552         _mmplayer_deconstruct_attribute(handle);
8553
8554         MMPLAYER_FLEAVE();
8555
8556         return ret;
8557 }
8558
8559 static gboolean
8560 __mmplayer_init_gstreamer(mm_player_t* player) // @
8561 {
8562         static gboolean initialized = FALSE;
8563         static const int max_argc = 50;
8564         gint* argc = NULL;
8565         gchar** argv = NULL;
8566         gchar** argv2 = NULL;
8567         GError *err = NULL;
8568         int i = 0;
8569         int arg_count = 0;
8570
8571         if (initialized) {
8572                 LOGD("gstreamer already initialized.\n");
8573                 return TRUE;
8574         }
8575
8576         /* alloc */
8577         argc = malloc(sizeof(int));
8578         argv = malloc(sizeof(gchar*) * max_argc);
8579         argv2 = malloc(sizeof(gchar*) * max_argc);
8580
8581         if (!argc || !argv || !argv2)
8582                 goto ERROR;
8583
8584         memset(argv, 0, sizeof(gchar*) * max_argc);
8585         memset(argv2, 0, sizeof(gchar*) * max_argc);
8586
8587         /* add initial */
8588         *argc = 1;
8589         argv[0] = g_strdup("mmplayer");
8590
8591         /* add gst_param */
8592         for (i = 0; i < 5; i++) {
8593                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8594                 if (strlen(player->ini.gst_param[i]) > 0) {
8595                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8596                         (*argc)++;
8597                 }
8598         }
8599
8600         /* we would not do fork for scanning plugins */
8601         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8602         (*argc)++;
8603
8604         /* check disable registry scan */
8605         if (player->ini.skip_rescan) {
8606                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8607                 (*argc)++;
8608         }
8609
8610         /* check disable segtrap */
8611         if (player->ini.disable_segtrap) {
8612                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8613                 (*argc)++;
8614         }
8615
8616         LOGD("initializing gstreamer with following parameter\n");
8617         LOGD("argc : %d\n", *argc);
8618         arg_count = *argc;
8619
8620         for (i = 0; i < arg_count; i++) {
8621                 argv2[i] = argv[i];
8622                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8623         }
8624
8625
8626         /* initializing gstreamer */
8627         if (!gst_init_check(argc, &argv, &err)) {
8628                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8629                 if (err)
8630                         g_error_free(err);
8631
8632                 goto ERROR;
8633         }
8634         /* release */
8635         for (i = 0; i < arg_count; i++) {
8636                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8637                 MMPLAYER_FREEIF(argv2[i]);
8638         }
8639
8640         MMPLAYER_FREEIF(argv);
8641         MMPLAYER_FREEIF(argv2);
8642         MMPLAYER_FREEIF(argc);
8643
8644         /* done */
8645         initialized = TRUE;
8646
8647         return TRUE;
8648
8649 ERROR:
8650
8651         /* release */
8652         for (i = 0; i < arg_count; i++) {
8653                 LOGD("free[%d] : %s\n", i, argv2[i]);
8654                 MMPLAYER_FREEIF(argv2[i]);
8655         }
8656
8657         MMPLAYER_FREEIF(argv);
8658         MMPLAYER_FREEIF(argv2);
8659         MMPLAYER_FREEIF(argc);
8660
8661         return FALSE;
8662 }
8663
8664 int
8665 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8666 {
8667         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8668
8669         if (player->pd_downloader) {
8670                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8671                 MMPLAYER_FREEIF(player->pd_downloader);
8672         }
8673
8674         if (MMPLAYER_IS_HTTP_PD(player)) {
8675                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8676                 MMPLAYER_FREEIF(player->pd_file_save_path);
8677         }
8678
8679         return MM_ERROR_NONE;
8680 }
8681
8682 static void
8683 __mmplayer_check_async_state_transition(mm_player_t* player)
8684 {
8685         GstState element_state = GST_STATE_VOID_PENDING;
8686         GstState element_pending_state = GST_STATE_VOID_PENDING;
8687         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8688         GstElement * element = NULL;
8689         gboolean async = FALSE;
8690
8691         /* check player handle */
8692         MMPLAYER_RETURN_IF_FAIL(player &&
8693                                                 player->pipeline &&
8694                                                 player->pipeline->mainbin &&
8695                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8696
8697         if (player->attrs)
8698                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8699
8700         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8701                 LOGD("don't need to check the pipeline state");
8702                 return;
8703         }
8704
8705         MMPLAYER_PRINT_STATE(player);
8706
8707         /* wait for state transition */
8708         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8709         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8710
8711         if (ret == GST_STATE_CHANGE_FAILURE) {
8712                 LOGE(" [%s] state : %s   pending : %s \n",
8713                         GST_ELEMENT_NAME(element),
8714                         gst_element_state_get_name(element_state),
8715                         gst_element_state_get_name(element_pending_state));
8716
8717                 /* dump state of all element */
8718                 __mmplayer_dump_pipeline_state(player);
8719
8720                 return;
8721         }
8722
8723         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8724         return;
8725 }
8726
8727 int
8728 _mmplayer_destroy(MMHandleType handle) // @
8729 {
8730         mm_player_t* player = MM_PLAYER_CAST(handle);
8731
8732         MMPLAYER_FENTER();
8733
8734         /* check player handle */
8735         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736
8737         /* destroy can called at anytime */
8738         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8739
8740         /* check async state transition */
8741         __mmplayer_check_async_state_transition(player);
8742
8743         __mmplayer_destroy_streaming_ext(player);
8744
8745         /* release repeat thread */
8746         if (player->repeat_thread) {
8747                 player->repeat_thread_exit = TRUE;
8748                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8749
8750                 LOGD("waitting for repeat thread exit\n");
8751                 g_thread_join(player->repeat_thread);
8752                 g_mutex_clear(&player->repeat_thread_mutex);
8753                 g_cond_clear(&player->repeat_thread_cond);
8754                 LOGD("repeat thread released\n");
8755         }
8756
8757         /* release next play thread */
8758         if (player->next_play_thread) {
8759                 player->next_play_thread_exit = TRUE;
8760                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8761
8762                 LOGD("waitting for next play thread exit\n");
8763                 g_thread_join(player->next_play_thread);
8764                 g_mutex_clear(&player->next_play_thread_mutex);
8765                 g_cond_clear(&player->next_play_thread_cond);
8766                 LOGD("next play thread released\n");
8767         }
8768
8769         _mmplayer_release_video_capture(player);
8770
8771         /* flush any pending asm_cb */
8772         if (player->sound_focus.cb_pending) {
8773                 /* set a flag for make sure asm_cb to be returned immediately */
8774                 LOGW("asm cb has pending state");
8775                 player->sound_focus.exit_cb = TRUE;
8776
8777                 /* make sure to release any pending asm_cb which locked by cmd_lock */
8778                 MMPLAYER_CMD_UNLOCK(player);
8779                 sched_yield();
8780                 MMPLAYER_CMD_LOCK(player);
8781         }
8782
8783         /* withdraw asm */
8784         if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8785                 LOGE("failed to deregister asm server\n");
8786
8787         /* de-initialize resource manager */
8788         if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8789                 LOGE("failed to deinitialize resource manager\n");
8790
8791 #ifdef USE_LAZY_PAUSE
8792         if (player->lazy_pause_event_id) {
8793                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8794                 player->lazy_pause_event_id = 0;
8795         }
8796 #endif
8797
8798         if (player->resume_event_id) {
8799                 g_source_remove(player->resume_event_id);
8800                 player->resume_event_id = 0;
8801         }
8802
8803         if (player->resumable_cancel_id) {
8804                 g_source_remove(player->resumable_cancel_id);
8805                 player->resumable_cancel_id = 0;
8806         }
8807
8808         /* release pipeline */
8809         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8810                 LOGE("failed to destory pipeline\n");
8811                 return MM_ERROR_PLAYER_INTERNAL;
8812         }
8813
8814         if (player->is_external_subtitle_present && player->subtitle_language_list) {
8815           g_list_free(player->subtitle_language_list);
8816           player->subtitle_language_list = NULL;
8817         }
8818
8819         __mmplayer_release_dump_list(player->dump_list);
8820
8821         /* release miscellaneous information.
8822            these info needs to be released after pipeline is destroyed. */
8823         __mmplayer_release_misc_post(player);
8824
8825         /* release attributes */
8826         _mmplayer_deconstruct_attribute(handle);
8827
8828         /* release factories */
8829         __mmplayer_release_factories(player);
8830
8831         /* release lock */
8832         g_mutex_clear(&player->fsink_lock);
8833
8834         /* release lock */
8835         g_mutex_clear(&player->update_tag_lock);
8836
8837         /* release video bo lock and cond */
8838         g_mutex_clear(&player->video_bo_mutex);
8839         g_cond_clear(&player->video_bo_cond);
8840
8841         /* release media stream callback lock */
8842         g_mutex_clear(&player->media_stream_cb_lock);
8843
8844         MMPLAYER_FLEAVE();
8845
8846         return MM_ERROR_NONE;
8847 }
8848
8849 int
8850 __mmplayer_realize_streaming_ext(mm_player_t* player)
8851 {
8852         int ret = MM_ERROR_NONE;
8853
8854         MMPLAYER_FENTER();
8855         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8856
8857         if (MMPLAYER_IS_HTTP_PD(player)) {
8858                 gboolean bret = FALSE;
8859
8860                 player->pd_downloader = _mmplayer_create_pd_downloader();
8861                 if (!player->pd_downloader) {
8862                         LOGE("Unable to create PD Downloader...");
8863                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8864                 }
8865
8866                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8867
8868                 if (FALSE == bret) {
8869                         LOGE("Unable to create PD Downloader...");
8870                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8871                 }
8872         }
8873
8874         MMPLAYER_FLEAVE();
8875         return ret;
8876 }
8877
8878 int
8879 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8880 {
8881         mm_player_t* player = (mm_player_t*)hplayer;
8882         MMHandleType attrs = 0;
8883         int ret = MM_ERROR_NONE;
8884
8885         attrs = MMPLAYER_GET_ATTRS(player);
8886         if (!attrs) {
8887                 LOGE("fail to get attributes.\n");
8888                 return MM_ERROR_PLAYER_INTERNAL;
8889         }
8890
8891         player->sound_focus.pid = pid;
8892
8893         /* register to asm */
8894         if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8895                                                 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8896                                                 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8897                                                 (void*)player)) {
8898                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8899                 LOGE("failed to register asm server\n");
8900                 return MM_ERROR_POLICY_INTERNAL;
8901         }
8902         return ret;
8903 }
8904
8905 int
8906 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8907 {
8908         mm_player_t* player = (mm_player_t*) hplayer;
8909
8910         MMPLAYER_FENTER();
8911
8912         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8913
8914         *pid = player->sound_focus.pid;
8915
8916         LOGD("registered pid[%d] %p", *pid, player);
8917
8918         MMPLAYER_FLEAVE();
8919
8920         return MM_ERROR_NONE;
8921 }
8922
8923 int
8924 _mmplayer_realize(MMHandleType hplayer) // @
8925 {
8926         mm_player_t* player = (mm_player_t*)hplayer;
8927         char *uri = NULL;
8928         void *param = NULL;
8929         gboolean update_registry = FALSE;
8930         MMHandleType attrs = 0;
8931         int ret = MM_ERROR_NONE;
8932
8933         MMPLAYER_FENTER();
8934
8935         /* check player handle */
8936         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8937
8938         /* check current state */
8939         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8940
8941         attrs = MMPLAYER_GET_ATTRS(player);
8942         if (!attrs) {
8943                 LOGE("fail to get attributes.\n");
8944                 return MM_ERROR_PLAYER_INTERNAL;
8945         }
8946         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8947         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8948
8949         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8950                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8951
8952                 if (ret != MM_ERROR_NONE) {
8953                         LOGE("failed to parse profile\n");
8954                         return ret;
8955                 }
8956         }
8957
8958         /* FIXIT : we can use thouse in player->profile directly */
8959         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8960                 player->mem_buf.buf = (char *)player->profile.mem;
8961                 player->mem_buf.len = player->profile.mem_size;
8962                 player->mem_buf.offset = 0;
8963         }
8964
8965         if (uri && (strstr(uri, "es_buff://"))) {
8966                 if (strstr(uri, "es_buff://push_mode"))
8967                         player->es_player_push_mode = TRUE;
8968                 else
8969                         player->es_player_push_mode = FALSE;
8970         }
8971
8972         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8973                 LOGW("mms protocol is not supported format.\n");
8974                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8975         }
8976
8977         if (MMPLAYER_IS_STREAMING(player))
8978                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8979         else
8980                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8981
8982         player->smooth_streaming = FALSE;
8983         player->videodec_linked  = 0;
8984         player->videosink_linked = 0;
8985         player->audiodec_linked  = 0;
8986         player->audiosink_linked = 0;
8987         player->textsink_linked = 0;
8988         player->is_external_subtitle_present = FALSE;
8989         player->is_external_subtitle_added_now = FALSE;
8990         /* set the subtitle ON default */
8991         player->is_subtitle_off = FALSE;
8992
8993         /* registry should be updated for downloadable codec */
8994         mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8995
8996         if (update_registry) {
8997                 LOGD("updating registry...\n");
8998                 gst_update_registry();
8999
9000                 /* then we have to rebuild factories */
9001                 __mmplayer_release_factories(player);
9002                 __mmplayer_init_factories(player);
9003         }
9004
9005         /* realize pipeline */
9006         ret = __gst_realize(player);
9007         if (ret != MM_ERROR_NONE)
9008                 LOGE("fail to realize the player.\n");
9009         else
9010                 ret = __mmplayer_realize_streaming_ext(player);
9011
9012         MMPLAYER_FLEAVE();
9013
9014         return ret;
9015 }
9016
9017 int
9018 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9019 {
9020         MMPLAYER_FENTER();
9021         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9022
9023         /* destroy can called at anytime */
9024         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9025                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9026                 MMPLAYER_FREEIF(player->pd_downloader);
9027         }
9028
9029         MMPLAYER_FLEAVE();
9030         return MM_ERROR_NONE;
9031 }
9032
9033 int
9034 _mmplayer_unrealize(MMHandleType hplayer)
9035 {
9036         mm_player_t* player = (mm_player_t*)hplayer;
9037         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9038         int ret = MM_ERROR_NONE;
9039
9040         MMPLAYER_FENTER();
9041
9042         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9043
9044         /* check current state */
9045         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9046
9047         /* check async state transition */
9048         __mmplayer_check_async_state_transition(player);
9049
9050         __mmplayer_unrealize_streaming_ext(player);
9051
9052         /* unrealize pipeline */
9053         ret = __gst_unrealize(player);
9054
9055         /* set asm stop if success */
9056         if (MM_ERROR_NONE == ret) {
9057                 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9058                 if (ret != MM_ERROR_NONE)
9059                         LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9060
9061                 if (!player->resource_manager.by_rm_cb &&
9062                         _mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9063                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9064                                 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9065                                 if (ret != MM_ERROR_NONE)
9066                                         LOGE("failed to release resource, ret(0x%x)\n", ret);
9067                         }
9068                 }
9069
9070                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9071                         if (resource_state == RESOURCE_STATE_PREPARED) {
9072                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9073                                 if (ret != MM_ERROR_NONE)
9074                                         LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9075                         }
9076                 }
9077         } else
9078                 LOGE("failed and don't change asm state to stop");
9079
9080         MMPLAYER_FLEAVE();
9081
9082         return ret;
9083 }
9084
9085 int
9086 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9087 {
9088         mm_player_t* player = (mm_player_t*)hplayer;
9089
9090         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9091
9092         return __gst_set_message_callback(player, callback, user_param);
9093 }
9094
9095 int
9096 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9097 {
9098         mm_player_t *player = (mm_player_t*)hplayer;
9099
9100         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9101
9102         *state = MMPLAYER_CURRENT_STATE(player);
9103
9104         return MM_ERROR_NONE;
9105 }
9106
9107
9108 int
9109 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9110 {
9111         mm_player_t* player = (mm_player_t*) hplayer;
9112         GstElement* vol_element = NULL;
9113         int i = 0;
9114
9115         MMPLAYER_FENTER();
9116
9117         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9118
9119         LOGD("volume [L]=%f:[R]=%f\n",
9120                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9121
9122         /* invalid factor range or not */
9123         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9124                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9125                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
9126                         return MM_ERROR_INVALID_ARGUMENT;
9127                 }
9128         }
9129
9130         /* not support to set other value into each channel */
9131         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9132                 return MM_ERROR_INVALID_ARGUMENT;
9133
9134         /* Save volume to handle. Currently the first array element will be saved. */
9135         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9136
9137         /* check pipeline handle */
9138         if (!player->pipeline || !player->pipeline->audiobin) {
9139                 LOGD("audiobin is not created yet\n");
9140                 LOGD("but, current stored volume will be set when it's created.\n");
9141
9142                 /* NOTE : stored volume will be used in create_audiobin
9143                  * returning MM_ERROR_NONE here makes application to able to
9144                  * set volume at anytime.
9145                  */
9146                 return MM_ERROR_NONE;
9147         }
9148
9149         /* setting volume to volume element */
9150         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9151
9152         if (vol_element) {
9153                 LOGD("volume is set [%f]\n", player->sound.volume);
9154                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9155         }
9156
9157         MMPLAYER_FLEAVE();
9158
9159         return MM_ERROR_NONE;
9160 }
9161
9162
9163 int
9164 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9165 {
9166         mm_player_t* player = (mm_player_t*) hplayer;
9167         int i = 0;
9168
9169         MMPLAYER_FENTER();
9170
9171         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9172         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9173
9174         /* returning stored volume */
9175         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9176                 volume->level[i] = player->sound.volume;
9177
9178         MMPLAYER_FLEAVE();
9179
9180         return MM_ERROR_NONE;
9181 }
9182
9183
9184
9185 int
9186 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9187 {
9188         mm_player_t* player = (mm_player_t*) hplayer;
9189         GstElement* vol_element = NULL;
9190
9191         MMPLAYER_FENTER();
9192
9193         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9194
9195         /* mute value shoud 0 or 1 */
9196         if (mute != 0 && mute != 1) {
9197                 LOGE("bad mute value\n");
9198
9199                 /* FIXIT : definitly, we need _BAD_PARAM error code */
9200                 return MM_ERROR_INVALID_ARGUMENT;
9201         }
9202
9203         player->sound.mute = mute;
9204
9205         /* just hold mute value if pipeline is not ready */
9206         if (!player->pipeline || !player->pipeline->audiobin) {
9207                 LOGD("pipeline is not ready. holding mute value\n");
9208                 return MM_ERROR_NONE;
9209         }
9210
9211         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9212
9213         /* NOTE : volume will only created when the bt is enabled */
9214         if (vol_element) {
9215                 LOGD("mute : %d\n", mute);
9216                 g_object_set(vol_element, "mute", mute, NULL);
9217         } else
9218                 LOGD("volume elemnet is not created. using volume in audiosink\n");
9219
9220         MMPLAYER_FLEAVE();
9221
9222         return MM_ERROR_NONE;
9223 }
9224
9225 int
9226 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9227 {
9228         mm_player_t* player = (mm_player_t*) hplayer;
9229
9230         MMPLAYER_FENTER();
9231
9232         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9233         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9234
9235         /* just hold mute value if pipeline is not ready */
9236         if (!player->pipeline || !player->pipeline->audiobin) {
9237                 LOGD("pipeline is not ready. returning stored value\n");
9238                 *pmute = player->sound.mute;
9239                 return MM_ERROR_NONE;
9240         }
9241
9242         *pmute = player->sound.mute;
9243
9244         MMPLAYER_FLEAVE();
9245
9246         return MM_ERROR_NONE;
9247 }
9248
9249 int
9250 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9251 {
9252         mm_player_t* player = (mm_player_t*) hplayer;
9253
9254         MMPLAYER_FENTER();
9255
9256         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9257
9258         player->video_stream_changed_cb = callback;
9259         player->video_stream_changed_cb_user_param = user_param;
9260         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9261
9262         MMPLAYER_FLEAVE();
9263
9264         return MM_ERROR_NONE;
9265 }
9266
9267 int
9268 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9269 {
9270         mm_player_t* player = (mm_player_t*) hplayer;
9271
9272         MMPLAYER_FENTER();
9273
9274         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9275
9276         player->audio_stream_changed_cb = callback;
9277         player->audio_stream_changed_cb_user_param = user_param;
9278         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9279
9280         MMPLAYER_FLEAVE();
9281
9282         return MM_ERROR_NONE;
9283 }
9284
9285 int
9286 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9287 {
9288         mm_player_t* player = (mm_player_t*) hplayer;
9289
9290         MMPLAYER_FENTER();
9291
9292         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9293
9294         player->audio_stream_render_cb_ex = callback;
9295         player->audio_stream_cb_user_param = user_param;
9296         player->audio_stream_sink_sync = sync;
9297         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);
9298
9299         MMPLAYER_FLEAVE();
9300
9301         return MM_ERROR_NONE;
9302 }
9303
9304 int
9305 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9306 {
9307         mm_player_t* player = (mm_player_t*) hplayer;
9308
9309         MMPLAYER_FENTER();
9310
9311         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9312
9313         if (callback && !player->bufmgr)
9314                 player->bufmgr = tbm_bufmgr_init(-1);
9315
9316         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9317         player->video_stream_cb = callback;
9318         player->video_stream_cb_user_param = user_param;
9319
9320         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9321
9322         MMPLAYER_FLEAVE();
9323
9324         return MM_ERROR_NONE;
9325 }
9326
9327 int
9328 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9329 {
9330         mm_player_t* player = (mm_player_t*) hplayer;
9331
9332         MMPLAYER_FENTER();
9333
9334         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9335
9336         player->audio_stream_cb = callback;
9337         player->audio_stream_cb_user_param = user_param;
9338         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9339
9340         MMPLAYER_FLEAVE();
9341
9342         return MM_ERROR_NONE;
9343 }
9344
9345 // set prepare size
9346 int
9347 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9348 {
9349         mm_player_t* player = (mm_player_t*) hplayer;
9350
9351         MMPLAYER_FENTER();
9352
9353         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9354
9355         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
9356                 return MM_ERROR_PLAYER_INVALID_STATE;
9357
9358         LOGD("pre buffer size : %d sec\n", second);
9359
9360         if (second <= 0) {
9361                 LOGE("bad size value\n");
9362                 return MM_ERROR_INVALID_ARGUMENT;
9363         }
9364
9365         if (player->streamer == NULL) {
9366                 player->streamer = __mm_player_streaming_create();
9367                 __mm_player_streaming_initialize(player->streamer);
9368         }
9369
9370         player->streamer->buffering_req.initial_second = second;
9371
9372         MMPLAYER_FLEAVE();
9373
9374         return MM_ERROR_NONE;
9375 }
9376
9377 // set runtime mode
9378 int
9379 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9380 {
9381         mm_player_t* player = (mm_player_t*) hplayer;
9382
9383         MMPLAYER_FENTER();
9384
9385         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9386
9387         LOGD("mode %d\n", mode);
9388
9389         if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9390                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9391                 return MM_ERROR_INVALID_ARGUMENT;
9392
9393         if (player->streamer == NULL) {
9394                 player->streamer = __mm_player_streaming_create();
9395                 __mm_player_streaming_initialize(player->streamer);
9396         }
9397
9398         player->streamer->buffering_req.mode = mode;
9399
9400         if ((second > 0) &&
9401                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9402                 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9403                 player->streamer->buffering_req.runtime_second = second;
9404
9405         MMPLAYER_FLEAVE();
9406
9407         return MM_ERROR_NONE;
9408 }
9409
9410 int
9411 __mmplayer_start_streaming_ext(mm_player_t *player)
9412 {
9413         gint ret = MM_ERROR_NONE;
9414
9415         MMPLAYER_FENTER();
9416         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9417
9418         if (MMPLAYER_IS_HTTP_PD(player)) {
9419                 if (!player->pd_downloader) {
9420                         ret = __mmplayer_realize_streaming_ext(player);
9421
9422                         if (ret != MM_ERROR_NONE) {
9423                                 LOGE("failed to realize streaming ext\n");
9424                                 return ret;
9425                         }
9426                 }
9427
9428                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9429                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9430                         if (!ret) {
9431                                 LOGE("ERROR while starting PD...\n");
9432                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9433                         }
9434                         ret = MM_ERROR_NONE;
9435                 }
9436         }
9437
9438         MMPLAYER_FLEAVE();
9439         return ret;
9440 }
9441
9442 int
9443 _mmplayer_start(MMHandleType hplayer) // @
9444 {
9445         mm_player_t* player = (mm_player_t*) hplayer;
9446         gint ret = MM_ERROR_NONE;
9447
9448         MMPLAYER_FENTER();
9449
9450         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9451
9452         /* check current state */
9453         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9454
9455         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9456         if (ret != MM_ERROR_NONE) {
9457                 LOGE("failed to acquire sound focus.\n");
9458                 return ret;
9459         }
9460
9461         /* NOTE : we should check and create pipeline again if not created as we destroy
9462          * whole pipeline when stopping in streamming playback
9463          */
9464         if (!player->pipeline) {
9465                 ret = __gst_realize(player);
9466                 if (MM_ERROR_NONE != ret) {
9467                         LOGE("failed to realize before starting. only in streamming\n");
9468                         /* unlock */
9469                         return ret;
9470                 }
9471         }
9472
9473         ret = __mmplayer_start_streaming_ext(player);
9474         if (ret != MM_ERROR_NONE)
9475                 LOGE("failed to start streaming ext \n");
9476
9477         /* start pipeline */
9478         ret = __gst_start(player);
9479         if (ret != MM_ERROR_NONE)
9480                 LOGE("failed to start player.\n");
9481
9482         MMPLAYER_FLEAVE();
9483
9484         return ret;
9485 }
9486
9487 /* NOTE: post "not supported codec message" to application
9488  * when one codec is not found during AUTOPLUGGING in MSL.
9489  * So, it's separated with error of __mmplayer_gst_callback().
9490  * And, if any codec is not found, don't send message here.
9491  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9492  */
9493 int
9494 __mmplayer_handle_missed_plugin(mm_player_t* player)
9495 {
9496         MMMessageParamType msg_param;
9497         memset(&msg_param, 0, sizeof(MMMessageParamType));
9498         gboolean post_msg_direct = FALSE;
9499
9500         MMPLAYER_FENTER();
9501
9502         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9503
9504         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9505                         player->not_supported_codec, player->can_support_codec);
9506
9507         if (player->not_found_demuxer) {
9508                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9509                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9510
9511                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9512                 MMPLAYER_FREEIF(msg_param.data);
9513
9514                 return MM_ERROR_NONE;
9515         }
9516
9517         if (player->not_supported_codec) {
9518                 if (player->can_support_codec) {
9519                         // There is one codec to play
9520                         post_msg_direct = TRUE;
9521                 } else {
9522                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9523                                 post_msg_direct = TRUE;
9524                 }
9525
9526                 if (post_msg_direct) {
9527                         MMMessageParamType msg_param;
9528                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9529
9530                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9531                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9532
9533                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9534                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9535                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9536                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9537
9538                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9539                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9540                         }
9541
9542                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9543
9544                         MMPLAYER_FREEIF(msg_param.data);
9545
9546                         return MM_ERROR_NONE;
9547                 } else {
9548                         // no any supported codec case
9549                         LOGW("not found any codec, posting error code to application.\n");
9550
9551                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9552                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9553                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9554                         } else {
9555                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9556                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9557                         }
9558
9559                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9560
9561                         MMPLAYER_FREEIF(msg_param.data);
9562                 }
9563         }
9564
9565         MMPLAYER_FLEAVE();
9566
9567         return MM_ERROR_NONE;
9568 }
9569
9570 static void __mmplayer_check_pipeline(mm_player_t* player)
9571 {
9572         GstState element_state = GST_STATE_VOID_PENDING;
9573         GstState element_pending_state = GST_STATE_VOID_PENDING;
9574         gint timeout = 0;
9575         int ret = MM_ERROR_NONE;
9576
9577         if (player->gapless.reconfigure) {
9578                 LOGW("pipeline is under construction.\n");
9579
9580                 MMPLAYER_PLAYBACK_LOCK(player);
9581                 MMPLAYER_PLAYBACK_UNLOCK(player);
9582
9583                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9584
9585                 /* wait for state transition */
9586                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9587
9588                 if (ret == GST_STATE_CHANGE_FAILURE)
9589                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9590         }
9591 }
9592
9593 /* NOTE : it should be able to call 'stop' anytime*/
9594 int
9595 _mmplayer_stop(MMHandleType hplayer) // @
9596 {
9597         mm_player_t* player = (mm_player_t*)hplayer;
9598         int ret = MM_ERROR_NONE;
9599
9600         MMPLAYER_FENTER();
9601
9602         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9603
9604         /* check current state */
9605         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9606
9607         /* check pipline building state */
9608         __mmplayer_check_pipeline(player);
9609         __mmplayer_reset_gapless_state(player);
9610
9611         /* NOTE : application should not wait for EOS after calling STOP */
9612         __mmplayer_cancel_eos_timer(player);
9613
9614         __mmplayer_unrealize_streaming_ext(player);
9615
9616         /* reset */
9617         player->doing_seek = FALSE;
9618
9619         /* stop pipeline */
9620         ret = __gst_stop(player);
9621
9622         if (ret != MM_ERROR_NONE)
9623                 LOGE("failed to stop player.\n");
9624
9625         MMPLAYER_FLEAVE();
9626
9627         return ret;
9628 }
9629
9630 int
9631 _mmplayer_pause(MMHandleType hplayer) // @
9632 {
9633         mm_player_t* player = (mm_player_t*)hplayer;
9634         gint64 pos_msec = 0;
9635         gboolean async = FALSE;
9636         gint ret = MM_ERROR_NONE;
9637
9638         MMPLAYER_FENTER();
9639
9640         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9641
9642         /* check current state */
9643         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9644
9645         /* check pipline building state */
9646         __mmplayer_check_pipeline(player);
9647
9648         switch (MMPLAYER_CURRENT_STATE(player)) {
9649         case MM_PLAYER_STATE_READY:
9650                 {
9651                         /* check prepare async or not.
9652                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9653                          */
9654                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9655                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9656
9657                         /* Changing back sync of rtspsrc to async */
9658                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9659                                 LOGD("async prepare working mode for rtsp");
9660                                 async = TRUE;
9661                         }
9662                 }
9663                 break;
9664
9665         case MM_PLAYER_STATE_PLAYING:
9666                 {
9667                         /* NOTE : store current point to overcome some bad operation
9668                         *(returning zero when getting current position in paused state) of some
9669                         * elements
9670                         */
9671                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9672                                 LOGW("getting current position failed in paused\n");
9673
9674                         player->last_position = pos_msec;
9675
9676                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9677                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9678                            This causes problem is position calculation during normal pause resume scenarios also.
9679                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9680                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9681                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9682                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9683                         }
9684                 }
9685                 break;
9686         }
9687
9688         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9689                 LOGD("doing async pause in case of ms buff src");
9690                 async = TRUE;
9691         }
9692
9693         /* pause pipeline */
9694         ret = __gst_pause(player, async);
9695
9696         if (ret != MM_ERROR_NONE)
9697                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9698
9699         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9700                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9701                         LOGE("failed to update display_rotation");
9702         }
9703
9704         MMPLAYER_FLEAVE();
9705
9706         return ret;
9707 }
9708
9709 int
9710 _mmplayer_resume(MMHandleType hplayer)
9711 {
9712         mm_player_t* player = (mm_player_t*)hplayer;
9713         int ret = MM_ERROR_NONE;
9714         gboolean async = FALSE;
9715
9716         MMPLAYER_FENTER();
9717
9718         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9719
9720         /* Changing back sync mode rtspsrc to async */
9721         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9722                 LOGD("async resume for rtsp case");
9723                 async = TRUE;
9724         }
9725
9726         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9727         if (ret != MM_ERROR_NONE) {
9728                 LOGE("failed to acquire sound focus.\n");
9729                 return ret;
9730         }
9731
9732         /* check current state */
9733         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9734
9735         ret = __gst_resume(player, async);
9736
9737         if (ret != MM_ERROR_NONE)
9738                 LOGE("failed to resume player.\n");
9739
9740         MMPLAYER_FLEAVE();
9741
9742         return ret;
9743 }
9744
9745 int
9746 __mmplayer_set_play_count(mm_player_t* player, gint count)
9747 {
9748         MMHandleType attrs = 0;
9749
9750         MMPLAYER_FENTER();
9751
9752         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9753
9754         attrs =  MMPLAYER_GET_ATTRS(player);
9755         if (!attrs) {
9756                 LOGE("fail to get attributes.\n");
9757                 return MM_ERROR_PLAYER_INTERNAL;
9758         }
9759
9760         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9761         if (mmf_attrs_commit(attrs)) /* return -1 if error */
9762                 LOGE("failed to commit\n");
9763
9764         MMPLAYER_FLEAVE();
9765
9766         return  MM_ERROR_NONE;
9767 }
9768
9769 int
9770 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9771 {
9772         mm_player_t* player = (mm_player_t*)hplayer;
9773         gint64 start_pos = 0;
9774         gint64 end_pos = 0;
9775         gint infinity = -1;
9776
9777         MMPLAYER_FENTER();
9778
9779         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9780         MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9781
9782         player->section_repeat = TRUE;
9783         player->section_repeat_start = start;
9784         player->section_repeat_end = end;
9785
9786         start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9787         end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9788
9789         __mmplayer_set_play_count(player, infinity);
9790
9791         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9792                                         player->playback_rate,
9793                                         GST_FORMAT_TIME,
9794                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9795                                         GST_SEEK_TYPE_SET, start_pos,
9796                                         GST_SEEK_TYPE_SET, end_pos))) {
9797                 LOGE("failed to activate section repeat\n");
9798
9799                 return MM_ERROR_PLAYER_SEEK;
9800         }
9801
9802         LOGD("succeeded to set section repeat from %d to %d\n",
9803                 player->section_repeat_start, player->section_repeat_end);
9804
9805         MMPLAYER_FLEAVE();
9806
9807         return  MM_ERROR_NONE;
9808 }
9809
9810 static int
9811 __mmplayer_set_pcm_extraction(mm_player_t* player)
9812 {
9813         gint64 start_nsec = 0;
9814         gint64 end_nsec = 0;
9815         gint64 dur_nsec = 0;
9816         gint64 dur_msec = 0;
9817         int required_start = 0;
9818         int required_end = 0;
9819         int ret = 0;
9820
9821         MMPLAYER_FENTER();
9822
9823         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9824
9825         mm_attrs_multiple_get(player->attrs,
9826                 NULL,
9827                 "pcm_extraction_start_msec", &required_start,
9828                 "pcm_extraction_end_msec", &required_end,
9829                 NULL);
9830
9831         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9832
9833         if (required_start == 0 && required_end == 0) {
9834                 LOGD("extracting entire stream");
9835                 return MM_ERROR_NONE;
9836         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9837                 LOGD("invalid range for pcm extraction");
9838                 return MM_ERROR_INVALID_ARGUMENT;
9839         }
9840
9841         /* get duration */
9842         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9843         if (!ret) {
9844                 LOGE("failed to get duration");
9845                 return MM_ERROR_PLAYER_INTERNAL;
9846         }
9847         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9848
9849         if (dur_msec < required_end) {
9850                 // FIXME
9851                 LOGD("invalid end pos for pcm extraction");
9852                 return MM_ERROR_INVALID_ARGUMENT;
9853         }
9854
9855         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9856         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9857
9858         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9859                                         1.0,
9860                                         GST_FORMAT_TIME,
9861                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9862                                         GST_SEEK_TYPE_SET, start_nsec,
9863                                         GST_SEEK_TYPE_SET, end_nsec))) {
9864                 LOGE("failed to seek for pcm extraction\n");
9865
9866                 return MM_ERROR_PLAYER_SEEK;
9867         }
9868
9869         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9870
9871         MMPLAYER_FLEAVE();
9872
9873         return MM_ERROR_NONE;
9874 }
9875
9876 int
9877 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9878 {
9879         mm_player_t* player = (mm_player_t*)hplayer;
9880         gint64 cur_pos = 0;
9881         gint onetime = 1;
9882
9883         MMPLAYER_FENTER();
9884
9885         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9886
9887         player->section_repeat = FALSE;
9888
9889         __mmplayer_set_play_count(player, onetime);
9890
9891         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9892
9893         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9894                                         1.0,
9895                                         GST_FORMAT_TIME,
9896                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9897                                         GST_SEEK_TYPE_SET, cur_pos,
9898                                         GST_SEEK_TYPE_SET, player->duration))) {
9899                 LOGE("failed to deactivate section repeat\n");
9900
9901                 return MM_ERROR_PLAYER_SEEK;
9902         }
9903
9904         MMPLAYER_FENTER();
9905
9906         return MM_ERROR_NONE;
9907 }
9908
9909 int
9910 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9911 {
9912         mm_player_t* player = (mm_player_t*)hplayer;
9913         gint64 pos_msec = 0;
9914         int ret = MM_ERROR_NONE;
9915         int mute = FALSE;
9916         signed long long start = 0, stop = 0;
9917         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9918         MMPLAYER_FENTER();
9919
9920         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9921         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9922
9923         /* The sound of video is not supported under 0.0 and over 2.0. */
9924         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9925                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9926                         mute = TRUE;
9927         }
9928         _mmplayer_set_mute(hplayer, mute);
9929
9930         if (player->playback_rate == rate)
9931                 return MM_ERROR_NONE;
9932
9933         /* If the position is reached at start potion during fast backward, EOS is posted.
9934          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9935          * */
9936         player->playback_rate = rate;
9937
9938         current_state = MMPLAYER_CURRENT_STATE(player);
9939
9940         if (current_state != MM_PLAYER_STATE_PAUSED)
9941                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9942
9943         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9944
9945         if ((current_state == MM_PLAYER_STATE_PAUSED)
9946                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9947                 LOGW("returning last point : %lld\n", player->last_position);
9948                 pos_msec = player->last_position;
9949         }
9950
9951
9952         if (rate >= 0) {
9953                 start = pos_msec;
9954                 stop = GST_CLOCK_TIME_NONE;
9955         } else {
9956                 start = GST_CLOCK_TIME_NONE;
9957                 stop = pos_msec;
9958         }
9959         if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9960                                 rate,
9961                                 GST_FORMAT_TIME,
9962                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9963                                 GST_SEEK_TYPE_SET, start,
9964                                 GST_SEEK_TYPE_SET, stop))) {
9965                 LOGE("failed to set speed playback\n");
9966                 return MM_ERROR_PLAYER_SEEK;
9967         }
9968
9969         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9970
9971         MMPLAYER_FLEAVE();
9972
9973         return MM_ERROR_NONE;;
9974 }
9975
9976 int
9977 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9978 {
9979         mm_player_t* player = (mm_player_t*)hplayer;
9980         int ret = MM_ERROR_NONE;
9981
9982         MMPLAYER_FENTER();
9983
9984         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9985
9986         /* check pipline building state */
9987         __mmplayer_check_pipeline(player);
9988
9989         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9990
9991         MMPLAYER_FLEAVE();
9992
9993         return ret;
9994 }
9995
9996 int
9997 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
9998 {
9999         mm_player_t* player = (mm_player_t*)hplayer;
10000         int ret = MM_ERROR_NONE;
10001
10002         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10003
10004         ret = __gst_get_position(player, format, position);
10005
10006         return ret;
10007 }
10008
10009 int
10010 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10011 {
10012         mm_player_t* player = (mm_player_t*)hplayer;
10013         int ret = MM_ERROR_NONE;
10014
10015         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10016
10017         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10018
10019         return ret;
10020 }
10021
10022 int
10023 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10024 {
10025         mm_player_t* player = (mm_player_t*)hplayer;
10026         int ret = MM_ERROR_NONE;
10027
10028         MMPLAYER_FENTER();
10029
10030         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10031
10032         ret = __gst_adjust_subtitle_position(player, format, position);
10033
10034         MMPLAYER_FLEAVE();
10035
10036         return ret;
10037 }
10038 int
10039 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10040 {
10041         mm_player_t* player = (mm_player_t*)hplayer;
10042         int ret = MM_ERROR_NONE;
10043
10044         MMPLAYER_FENTER();
10045
10046         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10047
10048         ret = __gst_adjust_video_position(player, offset);
10049
10050         MMPLAYER_FLEAVE();
10051
10052         return ret;
10053 }
10054
10055 static gboolean
10056 __mmplayer_is_midi_type(gchar* str_caps)
10057 {
10058         if ((g_strrstr(str_caps, "audio/midi")) ||
10059                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10060                 (g_strrstr(str_caps, "application/x-smaf")) ||
10061                 (g_strrstr(str_caps, "audio/x-imelody")) ||
10062                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10063                 (g_strrstr(str_caps, "audio/xmf")) ||
10064                 (g_strrstr(str_caps, "audio/mxmf"))) {
10065                 LOGD("midi\n");
10066                 return TRUE;
10067         }
10068
10069         return FALSE;
10070 }
10071
10072 static gboolean
10073 __mmplayer_is_only_mp3_type(gchar *str_caps)
10074 {
10075         if (g_strrstr(str_caps, "application/x-id3") ||
10076                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10077                 return TRUE;
10078         return FALSE;
10079 }
10080
10081 static void
10082 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10083 {
10084         GstStructure* caps_structure = NULL;
10085         gint samplerate = 0;
10086         gint channels = 0;
10087
10088         MMPLAYER_FENTER();
10089         MMPLAYER_RETURN_IF_FAIL(player && caps);
10090
10091         caps_structure = gst_caps_get_structure(caps, 0);
10092
10093         /* set stream information */
10094         gst_structure_get_int(caps_structure, "rate", &samplerate);
10095         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10096
10097         gst_structure_get_int(caps_structure, "channels", &channels);
10098         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10099
10100         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
10101 }
10102
10103 static void
10104 __mmplayer_update_content_type_info(mm_player_t* player)
10105 {
10106         MMPLAYER_FENTER();
10107         MMPLAYER_RETURN_IF_FAIL(player && player->type);
10108
10109         if (__mmplayer_is_midi_type(player->type)) {
10110                 player->bypass_audio_effect = TRUE;
10111         } else if (g_strrstr(player->type, "application/x-hls")) {
10112                 /* If it can't know exact type when it parses uri because of redirection case,
10113                  * it will be fixed by typefinder or when doing autoplugging.
10114                  */
10115                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10116                 if (player->streamer) {
10117                         player->streamer->is_adaptive_streaming = TRUE;
10118                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10119                         player->streamer->buffering_req.runtime_second = 5;
10120                 }
10121         } else if (g_strrstr(player->type, "application/dash+xml")) {
10122                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10123         }
10124
10125         MMPLAYER_FLEAVE();
10126 }
10127
10128 static void
10129 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10130 GstCaps *caps, gpointer data)
10131 {
10132         mm_player_t* player = (mm_player_t*)data;
10133         GstPad* pad = NULL;
10134
10135         MMPLAYER_FENTER();
10136
10137         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10138
10139         /* store type string */
10140         MMPLAYER_FREEIF(player->type);
10141         player->type = gst_caps_to_string(caps);
10142         if (player->type)
10143                 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10144
10145         if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10146                 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10147                 (g_strrstr(player->type, "audio/x-raw-int"))) {
10148                 LOGE("not support media format\n");
10149
10150                 if (player->msg_posted == FALSE) {
10151                         MMMessageParamType msg_param;
10152                         memset(&msg_param, 0, sizeof(MMMessageParamType));
10153
10154                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10155                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10156
10157                         /* don't post more if one was sent already */
10158                         player->msg_posted = TRUE;
10159                 }
10160                 return;
10161         }
10162
10163         __mmplayer_update_content_type_info(player);
10164
10165         pad = gst_element_get_static_pad(tf, "src");
10166         if (!pad) {
10167                 LOGE("fail to get typefind src pad.\n");
10168                 return;
10169         }
10170
10171         if (player->use_decodebin) {
10172                 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10173                         gboolean async = FALSE;
10174                         LOGE("failed to autoplug %s\n", player->type);
10175
10176                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10177
10178                         if (async && player->msg_posted == FALSE)
10179                                 __mmplayer_handle_missed_plugin(player);
10180
10181                         goto DONE;
10182                 }
10183         } else {
10184                 /* try to plug */
10185                 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10186                         gboolean async = FALSE;
10187                         LOGE("failed to autoplug %s\n", player->type);
10188
10189                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10190
10191                         if (async && player->msg_posted == FALSE)
10192                                 __mmplayer_handle_missed_plugin(player);
10193
10194                         goto DONE;
10195                 }
10196
10197                 /* finish autopluging if no dynamic pad waiting */
10198                 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10199                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
10200                                 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10201                 }
10202         }
10203
10204 DONE:
10205         gst_object_unref(GST_OBJECT(pad));
10206
10207         MMPLAYER_FLEAVE();
10208
10209         return;
10210 }
10211
10212 static GstElement *
10213 __mmplayer_create_decodebin(mm_player_t* player)
10214 {
10215         GstElement *decodebin = NULL;
10216
10217         MMPLAYER_FENTER();
10218
10219         /* create decodebin */
10220         decodebin = gst_element_factory_make("decodebin", NULL);
10221
10222         if (!decodebin) {
10223                 LOGE("fail to create decodebin\n");
10224                 goto ERROR;
10225         }
10226
10227         /* raw pad handling signal */
10228         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10229                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10230
10231         /* no-more-pad pad handling signal */
10232         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10233                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10234
10235         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10236                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10237
10238         /* This signal is emitted when a pad for which there is no further possible
10239            decoding is added to the decodebin.*/
10240         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10241                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10242
10243         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10244            before looking for any elements that can handle that stream.*/
10245         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10246                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10247
10248         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10249            before looking for any elements that can handle that stream.*/
10250         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10251                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10252
10253         /* This signal is emitted once decodebin has finished decoding all the data.*/
10254         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10255                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10256
10257         /* This signal is emitted when a element is added to the bin.*/
10258         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10259                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
10260
10261 ERROR:
10262         return decodebin;
10263 }
10264
10265 static gboolean
10266 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10267 {
10268         MMPlayerGstElement* mainbin = NULL;
10269         GstElement* decodebin = NULL;
10270         GstElement* queue2 = NULL;
10271         GstPad* sinkpad = NULL;
10272         GstPad* qsrcpad = NULL;
10273         gchar *caps_str = NULL;
10274         gint64 dur_bytes = 0L;
10275
10276         guint max_buffer_size_bytes = 0;
10277         gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10278
10279         MMPLAYER_FENTER();
10280         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10281
10282         mainbin = player->pipeline->mainbin;
10283
10284         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10285                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10286                 LOGD("creating http streaming buffering queue(queue2)\n");
10287
10288                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10289                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10290                 } else {
10291                         queue2 = gst_element_factory_make("queue2", "queue2");
10292                         if (!queue2) {
10293                                 LOGE("failed to create buffering queue element\n");
10294                                 goto ERROR;
10295                         }
10296
10297                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10298                                 LOGE("failed to add buffering queue\n");
10299                                 goto ERROR;
10300                         }
10301
10302                         sinkpad = gst_element_get_static_pad(queue2, "sink");
10303                         qsrcpad = gst_element_get_static_pad(queue2, "src");
10304
10305                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10306                                 LOGE("failed to link buffering queue\n");
10307                                 goto ERROR;
10308                         }
10309
10310                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10311                                 LOGE("fail to get duration.\n");
10312
10313                         LOGD("dur_bytes = %lld\n", dur_bytes);
10314
10315                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10316
10317                         if (dur_bytes > 0) {
10318                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10319                                         type = MUXED_BUFFER_TYPE_FILE;
10320                                 } else {
10321                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10322                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10323                                 }
10324                         } else {
10325                                 dur_bytes = 0;
10326                         }
10327
10328                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
10329                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10330                         if (!g_strrstr(player->type, "video/mpegts")) {
10331                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10332                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10333
10334                                 __mm_player_streaming_set_queue2(player->streamer,
10335                                                                                                 queue2,
10336                                                                                                 FALSE,
10337                                                                                                 max_buffer_size_bytes,
10338                                                                                                 player->ini.http_buffering_time,
10339                                                                                                 1.0,                                                            // no meaning
10340                                                                                                 player->ini.http_buffering_limit,       // no meaning
10341                                                                                                 type,
10342                                                                                                 player->http_file_buffering_path,
10343                                                                                                 (guint64)dur_bytes);
10344                         }
10345
10346                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10347                                 LOGE("failed to sync queue2 state with parent\n");
10348                                 goto ERROR;
10349                         }
10350
10351                         srcpad = qsrcpad;
10352
10353                         gst_object_unref(GST_OBJECT(sinkpad));
10354
10355                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10356                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10357                 }
10358         }
10359
10360         /* create decodebin */
10361         decodebin = __mmplayer_create_decodebin(player);
10362
10363         if (!decodebin) {
10364                 LOGE("can not create autoplug element\n");
10365                 goto ERROR;
10366         }
10367
10368         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10369                 LOGE("failed to add decodebin\n");
10370                 goto ERROR;
10371         }
10372
10373         /* to force caps on the decodebin element and avoid reparsing stuff by
10374         * typefind. It also avoids a deadlock in the way typefind activates pads in
10375         * the state change */
10376         g_object_set(decodebin, "sink-caps", caps, NULL);
10377
10378         sinkpad = gst_element_get_static_pad(decodebin, "sink");
10379
10380         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10381                 LOGE("failed to link decodebin\n");
10382                 goto ERROR;
10383         }
10384
10385         gst_object_unref(GST_OBJECT(sinkpad));
10386
10387         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10388         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10389
10390         /* set decodebin property about buffer in streaming playback. *
10391          * in case of hls, it does not need to have big buffer        *
10392          * because it is kind of adaptive streaming.                  */
10393         if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10394            (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10395                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10396                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10397                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10398
10399                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10400                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10401                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10402                 }
10403
10404                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10405                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
10406                                                                                         "low-percent", 1,   // 1%
10407                                                                                         "max-size-bytes", max_size_bytes,
10408                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
10409                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
10410         }
10411
10412         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10413                 LOGE("failed to sync decodebin state with parent\n");
10414                 goto ERROR;
10415         }
10416
10417         MMPLAYER_FLEAVE();
10418
10419         return TRUE;
10420
10421 ERROR:
10422
10423         MMPLAYER_FREEIF(caps_str);
10424
10425         if (sinkpad)
10426                 gst_object_unref(GST_OBJECT(sinkpad));
10427
10428         if (queue2) {
10429                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10430                  * You need to explicitly set elements to the NULL state before
10431                  * dropping the final reference, to allow them to clean up.
10432                  */
10433                 gst_element_set_state(queue2, GST_STATE_NULL);
10434
10435                 /* And, it still has a parent "player".
10436                  * You need to let the parent manage the object instead of unreffing the object directly.
10437                  */
10438                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10439                 gst_object_unref(queue2);
10440                 queue2 = NULL;
10441         }
10442
10443         if (decodebin) {
10444                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10445                  * You need to explicitly set elements to the NULL state before
10446                  * dropping the final reference, to allow them to clean up.
10447                  */
10448                 gst_element_set_state(decodebin, GST_STATE_NULL);
10449
10450                 /* And, it still has a parent "player".
10451                  * You need to let the parent manage the object instead of unreffing the object directly.
10452                  */
10453
10454                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10455                 gst_object_unref(decodebin);
10456                 decodebin = NULL;
10457         }
10458
10459         return FALSE;
10460 }
10461
10462 /* it will return first created element */
10463 static gboolean
10464 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10465 {
10466         MMPlayerGstElement* mainbin = NULL;
10467         const char* mime = NULL;
10468         const GList* item = NULL;
10469         const gchar* klass = NULL;
10470         GstCaps* res = NULL;
10471         gboolean skip = FALSE;
10472         GstPad* queue_pad = NULL;
10473         GstElement* queue = NULL;
10474         GstElement *element = NULL;
10475
10476         MMPLAYER_FENTER();
10477
10478         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10479
10480         mainbin = player->pipeline->mainbin;
10481
10482         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10483
10484         /* return if we got raw output */
10485         if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10486                 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10487
10488                 element = (GstElement*)gst_pad_get_parent(pad);
10489 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10490  * No queue will be added. I think it can caused breaking sound when playing raw audio
10491  * frames but there's no different. Decodebin also doesn't add with those wav fils.
10492  * Anyway, currentely raw-queue seems not necessary.
10493  */
10494 #if 1
10495                 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10496                  * has linked. if so, we need to add queue for quality of output. note that
10497                  * decodebin also has same problem.
10498                  */
10499                 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10500
10501                 /* add queue if needed */
10502                 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10503                         || g_strrstr(klass, "Parse")) &&  !g_str_has_prefix(mime, "text")) {
10504                         LOGD("adding raw queue\n");
10505
10506                         queue = gst_element_factory_make("queue", NULL);
10507                         if (!queue) {
10508                                 LOGW("failed to create queue\n");
10509                                 goto ERROR;
10510                         }
10511
10512                         /* warmup */
10513                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10514                                 LOGW("failed to set state READY to queue\n");
10515                                 goto ERROR;
10516                         }
10517
10518                         /* add to pipeline */
10519                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10520                                 LOGW("failed to add queue\n");
10521                                 goto ERROR;
10522                         }
10523
10524                         /* link queue */
10525                         queue_pad = gst_element_get_static_pad(queue, "sink");
10526
10527                         if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10528                                 LOGW("failed to link queue\n");
10529                                 goto ERROR;
10530                         }
10531                         gst_object_unref(GST_OBJECT(queue_pad));
10532                         queue_pad = NULL;
10533
10534                         /* running */
10535                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10536                                 LOGW("failed to set state PAUSED to queue\n");
10537                                 goto ERROR;
10538                         }
10539
10540                         /* replace given pad to queue:src */
10541                         pad = gst_element_get_static_pad(queue, "src");
10542                         if (!pad) {
10543                                 LOGW("failed to get pad from queue\n");
10544                                 goto ERROR;
10545                         }
10546                 }
10547 #endif
10548                 /* check if player can do start continually */
10549                 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10550
10551                 if (__mmplayer_link_sink(player, pad))
10552                         __mmplayer_gst_decode_callback(element, pad, player);
10553
10554                 gst_object_unref(GST_OBJECT(element));
10555                 element = NULL;
10556
10557                 return TRUE;
10558         }
10559
10560         item = player->factories;
10561         for (; item != NULL; item = item->next) {
10562                 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10563                 const GList *pads;
10564                 gint idx = 0;
10565
10566                 skip = FALSE;
10567
10568                 /* filtering exclude keyword */
10569                 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10570                         if (g_strrstr(GST_OBJECT_NAME(factory),
10571                                         player->ini.exclude_element_keyword[idx])) {
10572                                 LOGW("skipping [%s] by exculde keyword [%s]\n",
10573                                         GST_OBJECT_NAME(factory),
10574                                         player->ini.exclude_element_keyword[idx]);
10575
10576                                 skip = TRUE;
10577                                 break;
10578                         }
10579                 }
10580
10581                 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10582                         // omx decoder can not support mpeg4video data partitioned
10583                         // rtsp streaming didn't know mpeg4video data partitioned format
10584                         // so, if rtsp playback, player will skip omx_mpeg4dec.
10585                         LOGW("skipping [%s] when rtsp streaming \n",
10586                                         GST_OBJECT_NAME(factory));
10587
10588                         skip = TRUE;
10589                 }
10590
10591                 if (skip) continue;
10592
10593                 /* check factory class for filtering */
10594                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10595
10596                 /*parsers are not required in case of external feeder*/
10597                 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10598                         continue;
10599
10600                 /* NOTE : msl don't need to use image plugins.
10601                  * So, those plugins should be skipped for error handling.
10602                  */
10603                 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10604                         LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10605                         continue;
10606                 }
10607
10608                 /* check pad compatability */
10609                 for (pads = gst_element_factory_get_static_pad_templates(factory);
10610                                         pads != NULL; pads = pads->next) {
10611                         GstStaticPadTemplate *temp1 = pads->data;
10612                         GstCaps* static_caps = NULL;
10613
10614                         if (temp1->direction != GST_PAD_SINK
10615                                 || temp1->presence != GST_PAD_ALWAYS)
10616                                 continue;
10617
10618                         /* using existing caps */
10619                         if (GST_IS_CAPS(&temp1->static_caps.caps))
10620                                 static_caps = gst_caps_ref(temp1->static_caps.caps);
10621                         /* create one */
10622                         else
10623                                 static_caps = gst_caps_from_string(temp1->static_caps.string);
10624
10625                         res = gst_caps_intersect((GstCaps*)caps, static_caps);
10626                         gst_caps_unref(static_caps);
10627                         static_caps = NULL;
10628
10629                         if (res && !gst_caps_is_empty(res)) {
10630                                 GstElement *new_element;
10631                                 GList *elements = player->parsers;
10632                                 char *name_template = g_strdup(temp1->name_template);
10633                                 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10634                                 gst_caps_unref(res);
10635
10636                                 /* check ALP Codec can be used or not */
10637                                 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10638                                         /* consider mp3 audio only */
10639                                         if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10640                                                 /* try to use ALP decoder first instead of selected decoder */
10641                                                 GstElement *element = NULL;
10642                                                 GstElementFactory * element_facory;
10643                                                 gchar *path = NULL;
10644                                                 guint64 data_size = 0;
10645                                                 #define MIN_THRESHOLD_SIZE  320 * 1024 // 320K
10646                                                 struct stat sb;
10647
10648                                                 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10649
10650                                                 if (stat(path, &sb) == 0)
10651                                                         data_size = (guint64)sb.st_size;
10652                                                 LOGD("file size : %u", data_size);
10653
10654                                                 if (data_size > MIN_THRESHOLD_SIZE) {
10655                                                         LOGD("checking if ALP can be used or not");
10656                                                         element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10657                                                         if (element) {
10658                                                                 /* check availability because multi-instance is not supported */
10659                                                                 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10660
10661                                                                 if (ret != GST_STATE_CHANGE_SUCCESS) {
10662                                                                         // use just selected decoder
10663                                                                         gst_object_unref(element);
10664                                                                 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10665                                                                         // replace facotry to use omx
10666                                                                         /* clean  */
10667                                                                         gst_element_set_state(element, GST_STATE_NULL);
10668                                                                         gst_object_unref(element);
10669
10670                                                                         element_facory = gst_element_factory_find("omx_mp3dec");
10671                                                                         /* replace, otherwise use selected thing instead */
10672                                                                         if (element_facory) {
10673                                                                                 factory = element_facory;
10674                                                                                 name_to_plug = GST_OBJECT_NAME(factory);
10675                                                                         }
10676                                                                 }
10677                                                         }
10678                                                 }
10679                                         }
10680                                 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10681                                         if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10682                                                 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10683                                                 if (env != NULL) {
10684                                                         if (strncasecmp(env, "yes", 3) == 0) {
10685                                                                 LOGD("skipping [%s] by disabled\n", name_to_plug);
10686                                                                 MMPLAYER_FREEIF(name_template);
10687                                                                 continue;
10688                                                         }
10689                                                 }
10690                                         }
10691                                 }
10692
10693                                 LOGD("found %s to plug\n", name_to_plug);
10694
10695                                 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10696                                 if (!new_element) {
10697                                         LOGE("failed to create element [%s]. continue with next.\n",
10698                                                 GST_OBJECT_NAME(factory));
10699
10700                                         MMPLAYER_FREEIF(name_template);
10701
10702                                         continue;
10703                                 }
10704
10705                                 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10706                                  * because parser can accept its own output as input.
10707                                  */
10708                                 if (g_strrstr(klass, "Parser")) {
10709                                         gchar *selected = NULL;
10710
10711                                         for (; elements; elements = g_list_next(elements)) {
10712                                                 gchar *element_name = elements->data;
10713
10714                                                 if (g_strrstr(element_name, name_to_plug)) {
10715                                                         LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10716                                                         skip = TRUE;
10717                                                 }
10718                                         }
10719
10720                                         if (skip) {
10721                                                 MMPLAYER_FREEIF(name_template);
10722                                                 continue;
10723                                         }
10724
10725                                         selected = g_strdup(name_to_plug);
10726                                         player->parsers = g_list_append(player->parsers, selected);
10727                                 }
10728
10729                                 /* store specific handles for futher control */
10730                                 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10731                                         /* FIXIT : first value will be overwritten if there's more
10732                                          * than 1 demuxer/parser
10733                                          */
10734                                         LOGD("plugged element is demuxer. take it\n");
10735                                         mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10736                                         mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10737
10738                                         /*Added for multi audio support */
10739                                         if (g_strrstr(klass, "Demux")) {
10740                                                 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10741                                                 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10742
10743                                                 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10744                                                 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10745                                                 this code should be removed after mpegtsdemux is fixed */
10746                                                 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10747                                                         LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10748                                                         player->no_more_pad = TRUE;
10749                                                 }
10750                                         }
10751                                         if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10752                                                 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10753                                 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10754                                         if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10755                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10756                                                 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10757                                                 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10758                                         } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10759                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10760                                                 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10761                                                 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10762                                         }
10763                                         /* NOTE : IF one codec is found, add it to supported_codec and remove from
10764                                          * missing plugin. Both of them are used to check what's supported codec
10765                                          * before returning result of play start. And, missing plugin should be
10766                                          * updated here for multi track files.
10767                                          */
10768                                         if (g_str_has_prefix(mime, "video")) {
10769                                                 GstPad *src_pad = NULL;
10770                                                 GstPadTemplate *pad_templ = NULL;
10771                                                 GstCaps *caps = NULL;
10772                                                 gchar *caps_str = NULL;
10773
10774                                                 LOGD("found VIDEO decoder\n");
10775                                                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10776                                                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10777
10778                                                 src_pad = gst_element_get_static_pad(new_element, "src");
10779                                                 pad_templ = gst_pad_get_pad_template(src_pad);
10780                                                 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10781
10782                                                 caps_str = gst_caps_to_string(caps);
10783
10784                                                 /* clean */
10785                                                 MMPLAYER_FREEIF(caps_str);
10786                                                 gst_object_unref(src_pad);
10787                                         } else if (g_str_has_prefix(mime, "audio")) {
10788                                                 LOGD("found AUDIO decoder\n");
10789                                                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10790                                                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10791                                         }
10792                                 }
10793
10794                                 if (!__mmplayer_close_link(player, pad, new_element,
10795                                                         name_template, gst_element_factory_get_static_pad_templates(factory))) {
10796                                         MMPLAYER_FREEIF(name_template);
10797                                         if (player->keep_detecting_vcodec)
10798                                                 continue;
10799
10800                                         /* Link is failed even though a supportable codec is found. */
10801                                         __mmplayer_check_not_supported_codec(player, klass, mime);
10802
10803                                         LOGE("failed to call _close_link\n");
10804                                         return FALSE;
10805                                 }
10806
10807                                 MMPLAYER_FREEIF(name_template);
10808                                 return TRUE;
10809                         }
10810
10811                         gst_caps_unref(res);
10812                         break;
10813                 }
10814         }
10815
10816         /* There is no available codec. */
10817         __mmplayer_check_not_supported_codec(player, klass, mime);
10818
10819         MMPLAYER_FLEAVE();
10820         return FALSE;
10821
10822 ERROR:
10823         /* release */
10824         if (queue)
10825                 gst_object_unref(queue);
10826
10827         if (queue_pad)
10828                 gst_object_unref(queue_pad);
10829
10830         if (element)
10831                 gst_object_unref(element);
10832
10833         return FALSE;
10834 }
10835
10836
10837 static int
10838 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10839 {
10840         MMPLAYER_FENTER();
10841
10842         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10843         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10844
10845         LOGD("class : %s, mime : %s \n", factory_class, mime);
10846
10847         /* add missing plugin */
10848         /* NOTE : msl should check missing plugin for image mime type.
10849          * Some motion jpeg clips can have playable audio track.
10850          * So, msl have to play audio after displaying popup written video format not supported.
10851          */
10852         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10853                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10854                         LOGD("not found demuxer\n");
10855                         player->not_found_demuxer = TRUE;
10856                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10857
10858                         goto DONE;
10859                 }
10860         }
10861
10862         if (!g_strrstr(factory_class, "Demuxer")) {
10863                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10864                         LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10865                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10866
10867                         /* check that clip have multi tracks or not */
10868                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10869                                 LOGD("video plugin is already linked\n");
10870                         } else {
10871                                 LOGW("add VIDEO to missing plugin\n");
10872                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10873                         }
10874                 } else if (g_str_has_prefix(mime, "audio")) {
10875                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10876                                 LOGD("audio plugin is already linked\n");
10877                         } else {
10878                                 LOGW("add AUDIO to missing plugin\n");
10879                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10880                         }
10881                 }
10882         }
10883
10884 DONE:
10885         MMPLAYER_FLEAVE();
10886
10887         return MM_ERROR_NONE;
10888 }
10889
10890
10891 static void
10892 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10893 {
10894         mm_player_t* player = (mm_player_t*)data;
10895
10896         MMPLAYER_FENTER();
10897
10898         MMPLAYER_RETURN_IF_FAIL(player);
10899
10900         /* remove fakesink. */
10901         if (!__mmplayer_gst_remove_fakesink(player,
10902                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10903                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10904                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10905                  * source element are not same. To overcome this situation, this function will called
10906                  * several places and several times. Therefore, this is not an error case.
10907                  */
10908                 return;
10909         }
10910
10911         LOGD("pipeline has completely constructed\n");
10912
10913         if ((player->ini.async_start) &&
10914                 (player->msg_posted == FALSE) &&
10915                 (player->cmd >= MMPLAYER_COMMAND_START))
10916                 __mmplayer_handle_missed_plugin(player);
10917
10918         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10919 }
10920
10921 static gboolean
10922 __mmplayer_verify_next_play_path(mm_player_t *player)
10923 {
10924         MMHandleType attrs = 0;
10925         MMPlayerParseProfile profile;
10926         gint uri_idx = 0, check_cnt = 0;
10927         char *uri = NULL;
10928         gint mode = MM_PLAYER_PD_MODE_NONE;
10929         gint video = 0;
10930         gint count = 0;
10931         gint gapless = 0;
10932         guint num_of_list = 0;
10933         static int profile_tv = -1;
10934
10935         MMPLAYER_FENTER();
10936
10937         LOGD("checking for gapless play");
10938
10939         if (player->pipeline->textbin) {
10940                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10941                 goto ERROR;
10942         }
10943
10944         attrs = MMPLAYER_GET_ATTRS(player);
10945         if (!attrs) {
10946                 LOGE("fail to get attributes.\n");
10947                 goto ERROR;
10948         }
10949
10950         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10951
10952         if (__builtin_expect(profile_tv == -1, 0)) {
10953                 char *profileName;
10954                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10955                 switch (*profileName) {
10956                         case 't':
10957                         case 'T':
10958                                 profile_tv = 1;
10959                                 break;
10960                         default:
10961                                 profile_tv = 0;
10962                 }
10963                 free(profileName);
10964         }
10965         /* gapless playback is not supported in case of video at TV profile. */
10966         if (profile_tv && video) {
10967                 LOGW("not support video gapless playback");
10968                 goto ERROR;
10969         }
10970
10971         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10972                 if (mode == TRUE) {
10973                         LOGW("pd mode\n");
10974                         goto ERROR;
10975                 }
10976         }
10977
10978         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10979                 LOGE("can not get play count\n");
10980
10981         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10982                 LOGE("can not get gapless mode\n");
10983
10984         if (video && !gapless) {
10985                 LOGW("not enabled video gapless playback");
10986                 goto ERROR;
10987         }
10988
10989         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10990                 gapless = 1;
10991
10992         if (!gapless) {
10993                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10994                 goto ERROR;
10995         }
10996
10997         num_of_list = g_list_length(player->uri_info.uri_list);
10998
10999         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11000
11001         if (num_of_list == 0) {
11002                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11003                         LOGE("can not get profile_uri\n");
11004                         goto ERROR;
11005                 }
11006
11007                 if (!uri) {
11008                         LOGE("uri list is empty.\n");
11009                         goto ERROR;
11010                 }
11011
11012                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11013                 LOGD("add original path : %s ", uri);
11014
11015                 num_of_list = 1;
11016                 uri = NULL;
11017         }
11018
11019         uri_idx = player->uri_info.uri_idx;
11020
11021         while (TRUE) {
11022                 check_cnt++;
11023
11024                 if (check_cnt > num_of_list) {
11025                         LOGE("there is no valid uri.");
11026                         goto ERROR;
11027                 }
11028
11029                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11030
11031                 if (uri_idx < num_of_list-1) {
11032                         uri_idx++;
11033                 } else {
11034                         if ((count <= 1) && (count != -1)) {
11035                                 LOGD("no repeat.");
11036                                 goto ERROR;
11037                         } else if (count > 1) {
11038                                 /* decrease play count */
11039                                 /* we succeeded to rewind. update play count and then wait for next EOS */
11040                                 count--;
11041
11042                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11043
11044                                 /* commit attribute */
11045                                 if (mmf_attrs_commit(attrs))
11046                                         LOGE("failed to commit attribute\n");
11047                         }
11048
11049                         /* count < 0 : repeat continually */
11050                         uri_idx = 0;
11051                 }
11052
11053                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11054                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11055
11056                 if (uri == NULL) {
11057                         LOGW("next uri does not exist\n");
11058                         continue;
11059                 }
11060
11061                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11062                         LOGE("failed to parse profile\n");
11063                         continue;
11064                 }
11065
11066                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11067                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11068                         LOGW("uri type is not supported(%d).", profile.uri_type);
11069                         continue;
11070                 }
11071
11072                 break;
11073         }
11074
11075         player->uri_info.uri_idx = uri_idx;
11076         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11077
11078         if (mmf_attrs_commit(player->attrs)) {
11079                 LOGE("failed to commit.\n");
11080                 goto ERROR;
11081         }
11082
11083         LOGD("next uri %s(%d)\n", uri, uri_idx);
11084
11085         return TRUE;
11086
11087 ERROR:
11088
11089         LOGE("unable to play next path. EOS will be posted soon.\n");
11090         return FALSE;
11091 }
11092
11093 static void
11094 __mmplayer_initialize_next_play(mm_player_t *player)
11095 {
11096         int i;
11097
11098         MMPLAYER_FENTER();
11099
11100         player->smooth_streaming = FALSE;
11101         player->videodec_linked = 0;
11102         player->audiodec_linked = 0;
11103         player->videosink_linked = 0;
11104         player->audiosink_linked = 0;
11105         player->textsink_linked = 0;
11106         player->is_external_subtitle_present = FALSE;
11107         player->is_external_subtitle_added_now = FALSE;
11108         player->not_supported_codec = MISSING_PLUGIN_NONE;
11109         player->can_support_codec = FOUND_PLUGIN_NONE;
11110         player->pending_seek.is_pending = FALSE;
11111         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11112         player->pending_seek.pos = 0;
11113         player->msg_posted = FALSE;
11114         player->has_many_types = FALSE;
11115         player->no_more_pad = FALSE;
11116         player->not_found_demuxer = 0;
11117         player->doing_seek = FALSE;
11118         player->max_audio_channels = 0;
11119         player->is_subtitle_force_drop = FALSE;
11120         player->play_subtitle = FALSE;
11121         player->use_textoverlay = FALSE;
11122         player->adjust_subtitle_pos = 0;
11123
11124         player->updated_bitrate_count = 0;
11125         player->total_bitrate = 0;
11126         player->updated_maximum_bitrate_count = 0;
11127         player->total_maximum_bitrate = 0;
11128
11129         _mmplayer_track_initialize(player);
11130
11131         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11132                 player->bitrate[i] = 0;
11133                 player->maximum_bitrate[i] = 0;
11134         }
11135
11136         if (player->v_stream_caps) {
11137                 gst_caps_unref(player->v_stream_caps);
11138                 player->v_stream_caps = NULL;
11139         }
11140
11141         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11142         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11143
11144         /* clean found parsers */
11145         if (player->parsers) {
11146                 GList *parsers = player->parsers;
11147                 for (; parsers; parsers = g_list_next(parsers)) {
11148                         gchar *name = parsers->data;
11149                         MMPLAYER_FREEIF(name);
11150                 }
11151                 g_list_free(player->parsers);
11152                 player->parsers = NULL;
11153         }
11154
11155         /* clean found audio decoders */
11156         if (player->audio_decoders) {
11157                 GList *a_dec = player->audio_decoders;
11158                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11159                         gchar *name = a_dec->data;
11160                         MMPLAYER_FREEIF(name);
11161                 }
11162                 g_list_free(player->audio_decoders);
11163                 player->audio_decoders = NULL;
11164         }
11165
11166         MMPLAYER_FLEAVE();
11167 }
11168
11169 static void
11170 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11171 {
11172         MMPlayerGstElement *mainbin = NULL;
11173         MMMessageParamType msg_param = {0,};
11174         GstElement *element = NULL;
11175         MMHandleType attrs = 0;
11176         char *uri = NULL;
11177         enum MainElementID elemId = MMPLAYER_M_NUM;
11178
11179         MMPLAYER_FENTER();
11180
11181         if ((player == NULL) ||
11182                 (player->pipeline == NULL) ||
11183                 (player->pipeline->mainbin == NULL)) {
11184                 LOGE("player is null.\n");
11185                 goto ERROR;
11186         }
11187
11188         mainbin = player->pipeline->mainbin;
11189         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11190
11191         attrs = MMPLAYER_GET_ATTRS(player);
11192         if (!attrs) {
11193                 LOGE("fail to get attributes.\n");
11194                 goto ERROR;
11195         }
11196
11197         /* Initialize Player values */
11198         __mmplayer_initialize_next_play(player);
11199
11200         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11201
11202         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11203                 LOGE("failed to parse profile\n");
11204                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11205                 goto ERROR;
11206         }
11207
11208         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11209                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11210                 LOGE("it's dash or hls. not support.");
11211                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11212                 goto ERROR;
11213         }
11214
11215         /* setup source */
11216         switch (player->profile.uri_type) {
11217         /* file source */
11218         case MM_PLAYER_URI_TYPE_FILE:
11219         {
11220                 LOGD("using filesrc for 'file://' handler.\n");
11221
11222                 element = gst_element_factory_make("filesrc", "source");
11223
11224                 if (!element) {
11225                         LOGE("failed to create filesrc\n");
11226                         break;
11227                 }
11228
11229                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
11230                 break;
11231         }
11232         case MM_PLAYER_URI_TYPE_URL_HTTP:
11233         {
11234                 gchar *user_agent, *proxy, *cookies, **cookie_list;
11235                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11236                 user_agent = proxy = cookies = NULL;
11237                 cookie_list = NULL;
11238
11239                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11240                 if (!element) {
11241                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11242                         break;
11243                 }
11244                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11245
11246                 /* get attribute */
11247                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11248                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11249                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11250                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11251
11252                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11253                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11254                         LOGD("get timeout from ini\n");
11255                         http_timeout = player->ini.http_timeout;
11256                 }
11257
11258                 /* get attribute */
11259                 SECURE_LOGD("location : %s\n", player->profile.uri);
11260                 SECURE_LOGD("cookies : %s\n", cookies);
11261                 SECURE_LOGD("proxy : %s\n", proxy);
11262                 SECURE_LOGD("user_agent :  %s\n", user_agent);
11263                 LOGD("timeout : %d\n", http_timeout);
11264
11265                 /* setting property to streaming source */
11266                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11267                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11268                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11269
11270                 /* check if prosy is vailid or not */
11271                 if (util_check_valid_url(proxy))
11272                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11273                 /* parsing cookies */
11274                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11275                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11276                 if (user_agent)
11277                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11278                 break;
11279         }
11280         default:
11281                 LOGE("not support uri type %d\n", player->profile.uri_type);
11282                 break;
11283         }
11284
11285         if (!element) {
11286                 LOGE("no source element was created.\n");
11287                 goto ERROR;
11288         }
11289
11290         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11291                 LOGE("failed to add source element to pipeline\n");
11292                 gst_object_unref(GST_OBJECT(element));
11293                 element = NULL;
11294                 goto ERROR;
11295         }
11296
11297         /* take source element */
11298         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11299         mainbin[MMPLAYER_M_SRC].gst = element;
11300
11301         element = NULL;
11302
11303         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11304                 if (player->streamer == NULL) {
11305                         player->streamer = __mm_player_streaming_create();
11306                         __mm_player_streaming_initialize(player->streamer);
11307                 }
11308
11309                 elemId = MMPLAYER_M_TYPEFIND;
11310                 element = gst_element_factory_make("typefind", "typefinder");
11311                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11312                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11313         } else {
11314                 elemId = MMPLAYER_M_AUTOPLUG;
11315                 element = __mmplayer_create_decodebin(player);
11316         }
11317
11318         /* check autoplug element is OK */
11319         if (!element) {
11320                 LOGE("can not create element(%d)\n", elemId);
11321                 goto ERROR;
11322         }
11323
11324         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11325                 LOGE("failed to add sinkbin to pipeline\n");
11326                 gst_object_unref(GST_OBJECT(element));
11327                 element = NULL;
11328                 goto ERROR;
11329         }
11330
11331         mainbin[elemId].id = elemId;
11332         mainbin[elemId].gst = element;
11333
11334         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11335                 LOGE("Failed to link src - autoplug(or typefind)\n");
11336                 goto ERROR;
11337         }
11338
11339         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11340                 LOGE("Failed to change state of src element\n");
11341                 goto ERROR;
11342         }
11343
11344         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11345                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11346                         LOGE("Failed to change state of decodebin\n");
11347                         goto ERROR;
11348                 }
11349         } else {
11350                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11351                         LOGE("Failed to change state of src element\n");
11352                         goto ERROR;
11353                 }
11354         }
11355
11356         player->gapless.stream_changed = TRUE;
11357         player->gapless.running = TRUE;
11358         MMPLAYER_FLEAVE();
11359         return;
11360
11361 ERROR:
11362         if (player) {
11363                 MMPLAYER_PLAYBACK_UNLOCK(player);
11364
11365                 if (!player->msg_posted) {
11366                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11367                         player->msg_posted = TRUE;
11368                 }
11369         }
11370         return;
11371 }
11372
11373 static gboolean
11374 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11375 {
11376         mm_player_selector_t *selector = &player->selector[type];
11377         MMPlayerGstElement *sinkbin = NULL;
11378         enum MainElementID selectorId = MMPLAYER_M_NUM;
11379         enum MainElementID sinkId = MMPLAYER_M_NUM;
11380         GstPad *srcpad = NULL;
11381         GstPad *sinkpad = NULL;
11382         gboolean send_notice = FALSE;
11383
11384         MMPLAYER_FENTER();
11385         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11386
11387         LOGD("type %d", type);
11388
11389         switch (type) {
11390         case MM_PLAYER_TRACK_TYPE_AUDIO:
11391                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11392                 sinkId = MMPLAYER_A_BIN;
11393                 sinkbin = player->pipeline->audiobin;
11394                 break;
11395         case MM_PLAYER_TRACK_TYPE_VIDEO:
11396                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11397                 sinkId = MMPLAYER_V_BIN;
11398                 sinkbin = player->pipeline->videobin;
11399                 send_notice = TRUE;
11400                 break;
11401         case MM_PLAYER_TRACK_TYPE_TEXT:
11402                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11403                 sinkId = MMPLAYER_T_BIN;
11404                 sinkbin = player->pipeline->textbin;
11405                 break;
11406         default:
11407                 LOGE("requested type is not supportable");
11408                 return FALSE;
11409                 break;
11410         }
11411
11412         if (player->pipeline->mainbin[selectorId].gst) {
11413                 gint n;
11414
11415                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11416
11417                 if (selector->event_probe_id != 0)
11418                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
11419                 selector->event_probe_id = 0;
11420
11421                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11422                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11423
11424                         if (srcpad && sinkpad) {
11425                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
11426                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11427                                 gst_pad_unlink(srcpad, sinkpad);
11428
11429                                 /* send custom event to sink pad to handle it at video sink */
11430                                 if (send_notice) {
11431                                         LOGD("send custom event to sinkpad");
11432                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11433                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11434                                         gst_pad_send_event(sinkpad, event);
11435                                 }
11436                         }
11437
11438                         gst_object_unref(sinkpad);
11439                         sinkpad = NULL;
11440                 }
11441                 gst_object_unref(srcpad);
11442                 srcpad = NULL;
11443
11444                 LOGD("selector release");
11445
11446                 /* release and unref requests pad from the selector */
11447                 for (n = 0; n < selector->channels->len; n++) {
11448                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11449                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11450                 }
11451                 g_ptr_array_set_size(selector->channels, 0);
11452
11453                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11454                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11455
11456                 player->pipeline->mainbin[selectorId].gst = NULL;
11457                 selector = NULL;
11458         }
11459
11460         return TRUE;
11461 }
11462
11463 static void
11464 __mmplayer_deactivate_old_path(mm_player_t *player)
11465 {
11466         MMPLAYER_FENTER();
11467         MMPLAYER_RETURN_IF_FAIL(player);
11468
11469         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11470                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11471                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11472                 LOGE("deactivate selector error");
11473                 goto ERROR;
11474         }
11475
11476         _mmplayer_track_destroy(player);
11477         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11478
11479         if (player->streamer) {
11480                 __mm_player_streaming_deinitialize(player->streamer);
11481                 __mm_player_streaming_destroy(player->streamer);
11482                 player->streamer = NULL;
11483         }
11484
11485         MMPLAYER_PLAYBACK_LOCK(player);
11486         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11487
11488         MMPLAYER_FLEAVE();
11489         return;
11490
11491 ERROR:
11492
11493         if (!player->msg_posted) {
11494                 MMMessageParamType msg = {0,};
11495
11496                 /*post error*/
11497                 msg.code = MM_ERROR_PLAYER_INTERNAL;
11498                 LOGE("next_uri_play> deactivate error");
11499
11500                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11501                 player->msg_posted = TRUE;
11502         }
11503         return;
11504 }
11505
11506 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11507 {
11508         int result = MM_ERROR_NONE;
11509         mm_player_t* player = (mm_player_t*) hplayer;
11510         MMPLAYER_FENTER();
11511
11512         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11513
11514         if (file_path) {
11515                 player->http_file_buffering_path = (gchar*)file_path;
11516                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11517         }
11518         MMPLAYER_FLEAVE();
11519         return result;
11520 }
11521
11522 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11523 {
11524         int result = MM_ERROR_NONE;
11525         mm_player_t* player = (mm_player_t*) hplayer;
11526         MMPLAYER_FENTER();
11527
11528         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11529
11530         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11531         if (mmf_attrs_commit(player->attrs)) {
11532                 LOGE("failed to commit the original uri.\n");
11533                 result = MM_ERROR_PLAYER_INTERNAL;
11534         } else {
11535                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11536                         LOGE("failed to add the original uri in the uri list.\n");
11537         }
11538
11539         MMPLAYER_FLEAVE();
11540         return result;
11541 }
11542
11543 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11544 {
11545         mm_player_t* player = (mm_player_t*) hplayer;
11546         guint num_of_list = 0;
11547
11548         MMPLAYER_FENTER();
11549
11550         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11551         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11552
11553         if (player->pipeline && player->pipeline->textbin) {
11554                 LOGE("subtitle path is enabled.\n");
11555                 return MM_ERROR_PLAYER_INVALID_STATE;
11556         }
11557
11558         num_of_list = g_list_length(player->uri_info.uri_list);
11559
11560         if (is_first_path == TRUE) {
11561                 if (num_of_list == 0) {
11562                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11563                         LOGD("add original path : %s", uri);
11564                 } else {
11565                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11566                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11567
11568                         LOGD("change original path : %s", uri);
11569                 }
11570         } else {
11571                 MMHandleType attrs = 0;
11572                 attrs = MMPLAYER_GET_ATTRS(player);
11573
11574                 if (num_of_list == 0) {
11575                         char *original_uri = NULL;
11576
11577                         if (attrs) {
11578                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11579
11580                                 if (!original_uri) {
11581                                         LOGE("there is no original uri.");
11582                                         return MM_ERROR_PLAYER_INVALID_STATE;
11583                                 }
11584
11585                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11586                                 player->uri_info.uri_idx = 0;
11587
11588                                 LOGD("add original path at first : %s(%d)", original_uri);
11589                         }
11590                 }
11591
11592                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11593                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11594         }
11595
11596         MMPLAYER_FLEAVE();
11597         return MM_ERROR_NONE;
11598 }
11599
11600 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11601 {
11602         mm_player_t* player = (mm_player_t*) hplayer;
11603         char *next_uri = NULL;
11604         guint num_of_list = 0;
11605
11606         MMPLAYER_FENTER();
11607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11608
11609         num_of_list = g_list_length(player->uri_info.uri_list);
11610
11611         if (num_of_list > 0) {
11612                 gint uri_idx = player->uri_info.uri_idx;
11613
11614                 if (uri_idx < num_of_list-1)
11615                         uri_idx++;
11616                 else
11617                         uri_idx = 0;
11618
11619                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11620                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11621
11622                 *uri = g_strdup(next_uri);
11623         }
11624
11625         MMPLAYER_FLEAVE();
11626         return MM_ERROR_NONE;
11627 }
11628
11629 static void
11630 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
11631 GstCaps *caps, gpointer data)
11632 {
11633         mm_player_t* player = (mm_player_t*)data;
11634         const gchar* klass = NULL;
11635         const gchar* mime = NULL;
11636         gchar* caps_str = NULL;
11637
11638         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11639         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11640         caps_str = gst_caps_to_string(caps);
11641
11642         LOGW("unknown type of caps : %s from %s",
11643                                         caps_str, GST_ELEMENT_NAME(elem));
11644
11645         MMPLAYER_FREEIF(caps_str);
11646
11647         /* There is no available codec. */
11648         __mmplayer_check_not_supported_codec(player, klass, mime);
11649 }
11650
11651 static gboolean
11652 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
11653 GstCaps * caps,  gpointer data)
11654 {
11655         mm_player_t* player = (mm_player_t*)data;
11656         const char* mime = NULL;
11657         gboolean ret = TRUE;
11658
11659         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11660         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11661
11662         if (g_str_has_prefix(mime, "audio")) {
11663                 GstStructure* caps_structure = NULL;
11664                 gint samplerate = 0;
11665                 gint channels = 0;
11666                 gchar *caps_str = NULL;
11667
11668                 caps_structure = gst_caps_get_structure(caps, 0);
11669                 gst_structure_get_int(caps_structure, "rate", &samplerate);
11670                 gst_structure_get_int(caps_structure, "channels", &channels);
11671
11672                 if ((channels > 0 && samplerate == 0)) {
11673                         LOGD("exclude audio...");
11674                         ret = FALSE;
11675                 }
11676
11677                 caps_str = gst_caps_to_string(caps);
11678                 /* set it directly because not sent by TAG */
11679                 if (g_strrstr(caps_str, "mobile-xmf"))
11680                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11681                 MMPLAYER_FREEIF(caps_str);
11682         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11683                 MMMessageParamType msg_param;
11684                 memset(&msg_param, 0, sizeof(MMMessageParamType));
11685                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11686                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11687                 LOGD("video file is not supported on this device");
11688                 ret = FALSE;
11689         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11690                 LOGD("already video linked");
11691                 ret = FALSE;
11692         } else {
11693                 LOGD("found new stream");
11694         }
11695
11696         return ret;
11697 }
11698
11699 static gint
11700 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
11701 GstCaps* caps, GstElementFactory* factory, gpointer data)
11702 {
11703         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11704          We are defining our own and will be removed when it actually exposed */
11705         typedef enum {
11706                 GST_AUTOPLUG_SELECT_TRY,
11707                 GST_AUTOPLUG_SELECT_EXPOSE,
11708                 GST_AUTOPLUG_SELECT_SKIP
11709         } GstAutoplugSelectResult;
11710
11711         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11712         mm_player_t* player = (mm_player_t*)data;
11713
11714         gchar* factory_name = NULL;
11715         gchar* caps_str = NULL;
11716         const gchar* klass = NULL;
11717         gint idx = 0;
11718         int surface_type = 0;
11719
11720         factory_name = GST_OBJECT_NAME(factory);
11721         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11722         caps_str = gst_caps_to_string(caps);
11723
11724         LOGD("found new element [%s] to link", factory_name);
11725
11726         /* store type string */
11727         if (player->type == NULL) {
11728                 player->type = gst_caps_to_string(caps);
11729                 __mmplayer_update_content_type_info(player);
11730         }
11731
11732         mm_attrs_get_int_by_name(player->attrs,
11733                                 "display_surface_type", &surface_type);
11734         LOGD("check display surface type attribute: %d", surface_type);
11735
11736         /* filtering exclude keyword */
11737         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11738                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11739                         LOGW("skipping [%s] by exculde keyword [%s]\n",
11740                         factory_name, player->ini.exclude_element_keyword[idx]);
11741
11742                         // NOTE : does we need to check n_value against the number of item selected?
11743                         result = GST_AUTOPLUG_SELECT_SKIP;
11744                         goto DONE;
11745                 }
11746         }
11747
11748         /* exclude webm format */
11749         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11750          * because webm format is not supportable.
11751          * If webm is disabled in "autoplug-continue", there is no state change
11752          * failure or error because the decodebin will expose the pad directly.
11753          * It make MSL invoke _prepare_async_callback.
11754          * So, we need to disable webm format in "autoplug-select" */
11755         if (strstr(caps_str, "webm")) {
11756                 LOGW("webm is not supported");
11757                 result = GST_AUTOPLUG_SELECT_SKIP;
11758                 goto DONE;
11759         }
11760
11761         /* check factory class for filtering */
11762         /* NOTE : msl don't need to use image plugins.
11763          * So, those plugins should be skipped for error handling.
11764          */
11765         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11766                 LOGD("skipping [%s] by not required\n", factory_name);
11767                 result = GST_AUTOPLUG_SELECT_SKIP;
11768                 goto DONE;
11769         }
11770
11771         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11772                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11773                 // TO CHECK : subtitle if needed, add subparse exception.
11774                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11775                 result = GST_AUTOPLUG_SELECT_SKIP;
11776                 goto DONE;
11777         }
11778
11779         if (g_strrstr(factory_name, "mpegpsdemux")) {
11780                 LOGD("skipping PS container - not support\n");
11781                 result = GST_AUTOPLUG_SELECT_SKIP;
11782                 goto DONE;
11783         }
11784
11785         if (g_strrstr(factory_name, "mssdemux"))
11786                 player->smooth_streaming = TRUE;
11787
11788         /* check ALP Codec can be used or not */
11789         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11790                 GstStructure* str = NULL;
11791                 gint channels = 0;
11792
11793                 str = gst_caps_get_structure(caps, 0);
11794                 if (str) {
11795                         gst_structure_get_int(str, "channels", &channels);
11796
11797                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11798                         if (player->max_audio_channels < channels)
11799                                 player->max_audio_channels = channels;
11800                 }
11801                 /* set stream information */
11802                 if (!player->audiodec_linked)
11803                         __mmplayer_set_audio_attrs(player, caps);
11804         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11805                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11806                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11807                         /* prepare resource manager for video decoder */
11808                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11809
11810                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11811                                 /* prepare resource manager for video decoder */
11812                                 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11813                                         if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11814                                                 != MM_ERROR_NONE) {
11815                                                 LOGW("could not prepare for video_decoder resource, skip it.");
11816                                                 result = GST_AUTOPLUG_SELECT_SKIP;
11817                                                 goto DONE;
11818                                         }
11819                                 }
11820                         }
11821                 }
11822         }
11823
11824         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11825                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11826                 gint stype = 0;
11827                 gint width = 0;
11828                 GstStructure *str = NULL;
11829                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11830
11831                 /* don't make video because of not required */
11832                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11833                         (player->set_mode.media_packet_video_stream == FALSE)) {
11834                         LOGD("no video because it's not required. -> return expose");
11835                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11836                         goto DONE;
11837                 }
11838
11839                 /* get w/h for omx state-tune */
11840                 str = gst_caps_get_structure(caps, 0);
11841                 gst_structure_get_int(str, "width", &width);
11842
11843                 if (width != 0) {
11844                         if (player->v_stream_caps) {
11845                                 gst_caps_unref(player->v_stream_caps);
11846                                 player->v_stream_caps = NULL;
11847                         }
11848
11849                         player->v_stream_caps = gst_caps_copy(caps);
11850                         LOGD("take caps for video state tune");
11851                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11852                 }
11853         }
11854
11855         if (g_strrstr(klass, "Decoder")) {
11856                 const char* mime = NULL;
11857                 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11858
11859                 if (g_str_has_prefix(mime, "video")) {
11860                         // __mmplayer_check_video_zero_cpoy(player, factory);
11861
11862                         player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11863                         player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11864
11865                         player->videodec_linked = 1;
11866                 } else if (g_str_has_prefix(mime, "audio")) {
11867                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11868                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11869
11870                         player->audiodec_linked = 1;
11871                 }
11872         }
11873
11874 DONE:
11875         MMPLAYER_FREEIF(caps_str);
11876
11877         return result;
11878 }
11879
11880
11881 #if 0
11882 static GValueArray*
11883 __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad,
11884 GstCaps * caps,  gpointer data)
11885 {
11886         //mm_player_t* player = (mm_player_t*)data;
11887
11888         LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11889         gst_caps_to_string(caps),
11890         GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11891
11892         return NULL;
11893 }
11894 #endif
11895
11896 static void
11897 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11898 gpointer data) // @
11899 {
11900         //mm_player_t* player = (mm_player_t*)data;
11901         GstCaps* caps = NULL;
11902
11903         LOGD("[Decodebin2] pad-removed signal\n");
11904
11905         caps = gst_pad_query_caps(new_pad, NULL);
11906         if (caps) {
11907                 gchar* caps_str = NULL;
11908                 caps_str = gst_caps_to_string(caps);
11909
11910                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11911
11912                 MMPLAYER_FREEIF(caps_str);
11913         }
11914 }
11915
11916 static void
11917 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11918 {
11919         mm_player_t* player = (mm_player_t*)data;
11920         GstIterator *iter = NULL;
11921         GValue item = { 0, };
11922         GstPad *pad = NULL;
11923         gboolean done = FALSE;
11924         gboolean is_all_drained = TRUE;
11925
11926         MMPLAYER_FENTER();
11927         MMPLAYER_RETURN_IF_FAIL(player);
11928
11929         LOGD("__mmplayer_gst_decode_drained");
11930
11931         if (player->use_deinterleave == TRUE) {
11932                 LOGD("group playing mode.");
11933                 return;
11934         }
11935
11936         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11937                 LOGW("Fail to get cmd lock");
11938                 return;
11939         }
11940
11941         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11942                 !__mmplayer_verify_next_play_path(player)) {
11943                 LOGD("decoding is finished.");
11944                 __mmplayer_reset_gapless_state(player);
11945                 MMPLAYER_CMD_UNLOCK(player);
11946                 return;
11947         }
11948
11949         player->gapless.reconfigure = TRUE;
11950
11951         /* check decodebin src pads whether they received EOS or not */
11952         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11953
11954         while (!done) {
11955                 switch (gst_iterator_next(iter, &item)) {
11956                 case GST_ITERATOR_OK:
11957                         pad = g_value_get_object(&item);
11958                         if (!GST_PAD_IS_EOS(pad)) {
11959                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11960                                 is_all_drained = FALSE;
11961                                 break;
11962                         }
11963                         g_value_reset(&item);
11964                         break;
11965                 case GST_ITERATOR_RESYNC:
11966                         gst_iterator_resync(iter);
11967                         break;
11968                 case GST_ITERATOR_ERROR:
11969                 case GST_ITERATOR_DONE:
11970                         done = TRUE;
11971                         break;
11972                 }
11973         }
11974         g_value_unset(&item);
11975         gst_iterator_free(iter);
11976
11977         if (!is_all_drained) {
11978                 LOGD("Wait util the all pads get EOS.");
11979                 MMPLAYER_CMD_UNLOCK(player);
11980                 MMPLAYER_FLEAVE();
11981                 return;
11982         }
11983
11984         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11985         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11986
11987         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11988         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11989         __mmplayer_deactivate_old_path(player);
11990         MMPLAYER_CMD_UNLOCK(player);
11991
11992         MMPLAYER_FLEAVE();
11993 }
11994
11995 static void
11996 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11997 {
11998         mm_player_t* player = (mm_player_t*)data;
11999         const gchar* klass = NULL;
12000         gchar* factory_name = NULL;
12001
12002         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12003         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12004
12005         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12006
12007         if (__mmplayer_add_dump_buffer_probe(player, element))
12008                 LOGD("add buffer probe");
12009
12010         //<-
12011         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12012                 gchar* selected = NULL;
12013                 selected = g_strdup(GST_ELEMENT_NAME(element));
12014                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12015         }
12016         //-> temp code
12017
12018         if (g_strrstr(klass, "Parser")) {
12019                 gchar* selected = NULL;
12020
12021                 selected = g_strdup(factory_name);
12022                 player->parsers = g_list_append(player->parsers, selected);
12023         }
12024
12025         if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
12026                 /* FIXIT : first value will be overwritten if there's more
12027                  * than 1 demuxer/parser
12028                  */
12029
12030                 //LOGD("plugged element is demuxer. take it\n");
12031                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12032                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12033
12034                 /*Added for multi audio support */ // Q. del?
12035                 if (g_strrstr(klass, "Demux")) {
12036                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12037                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12038                 }
12039         }
12040
12041         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12042                 int surface_type = 0;
12043
12044                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12045         }
12046
12047         // to support trust-zone only
12048         if (g_strrstr(factory_name, "asfdemux")) {
12049                 LOGD("set file-location %s\n", player->profile.uri);
12050                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12051
12052                 if (player->video_hub_download_mode == TRUE)
12053                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12054         } else if (g_strrstr(factory_name, "legacyh264parse")) {
12055                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12056                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12057         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12058                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12059                         (__mmplayer_is_only_mp3_type(player->type))) {
12060                         LOGD("[mpegaudioparse] set streaming pull mode.");
12061                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12062                 }
12063         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12064                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12065
12066
12067         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12068                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12069                 LOGD("plugged element is multiqueue. take it\n");
12070
12071                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12072                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12073
12074                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12075                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12076                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12077                         __mm_player_streaming_set_multiqueue(player->streamer,
12078                                 element,
12079                                 TRUE,
12080                                 player->ini.http_buffering_time,
12081                                 1.0,
12082                                 player->ini.http_buffering_limit);
12083
12084                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12085                 }
12086         }
12087
12088         return;
12089 }
12090
12091 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12092 {
12093         MMPLAYER_FENTER();
12094         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12095
12096         if (MMPLAYER_IS_STREAMING(player))
12097                 return FALSE;
12098
12099         /* This callback can be set to music player only. */
12100         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12101                 LOGW("audio callback is not supported for video");
12102                 return FALSE;
12103         }
12104
12105         if (player->audio_stream_cb) {
12106                 GstPad *pad = NULL;
12107
12108                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12109
12110                 if (!pad) {
12111                         LOGE("failed to get sink pad from audiosink to probe data\n");
12112                         return FALSE;
12113                 }
12114                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12115                         __mmplayer_audio_stream_probe, player, NULL);
12116
12117                 gst_object_unref(pad);
12118
12119                 pad = NULL;
12120         } else {
12121                 LOGE("There is no audio callback to configure.\n");
12122                 return FALSE;
12123         }
12124
12125         MMPLAYER_FLEAVE();
12126
12127         return TRUE;
12128 }
12129
12130 static void
12131 __mmplayer_init_factories(mm_player_t* player) // @
12132 {
12133         MMPLAYER_RETURN_IF_FAIL(player);
12134
12135         player->factories = gst_registry_feature_filter(gst_registry_get(),
12136                 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12137         player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12138 }
12139
12140 static void
12141 __mmplayer_release_factories(mm_player_t* player) // @
12142 {
12143         MMPLAYER_FENTER();
12144         MMPLAYER_RETURN_IF_FAIL(player);
12145
12146         if (player->factories) {
12147                 gst_plugin_feature_list_free(player->factories);
12148                 player->factories = NULL;
12149         }
12150
12151         MMPLAYER_FLEAVE();
12152 }
12153
12154 static void
12155 __mmplayer_release_misc(mm_player_t* player)
12156 {
12157         int i;
12158         gboolean cur_mode = player->set_mode.rich_audio;
12159         MMPLAYER_FENTER();
12160
12161         MMPLAYER_RETURN_IF_FAIL(player);
12162
12163         player->video_stream_cb = NULL;
12164         player->video_stream_cb_user_param = NULL;
12165         player->video_stream_prerolled = FALSE;
12166
12167         player->audio_stream_cb = NULL;
12168         player->audio_stream_render_cb_ex = NULL;
12169         player->audio_stream_cb_user_param = NULL;
12170         player->audio_stream_sink_sync = false;
12171
12172         player->video_stream_changed_cb = NULL;
12173         player->video_stream_changed_cb_user_param = NULL;
12174
12175         player->audio_stream_changed_cb = NULL;
12176         player->audio_stream_changed_cb_user_param = NULL;
12177
12178         player->sent_bos = FALSE;
12179         player->playback_rate = DEFAULT_PLAYBACK_RATE;
12180
12181         player->doing_seek = FALSE;
12182
12183         player->updated_bitrate_count = 0;
12184         player->total_bitrate = 0;
12185         player->updated_maximum_bitrate_count = 0;
12186         player->total_maximum_bitrate = 0;
12187
12188         player->not_found_demuxer = 0;
12189
12190         player->last_position = 0;
12191         player->duration = 0;
12192         player->http_content_size = 0;
12193         player->not_supported_codec = MISSING_PLUGIN_NONE;
12194         player->can_support_codec = FOUND_PLUGIN_NONE;
12195         player->pending_seek.is_pending = FALSE;
12196         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12197         player->pending_seek.pos = 0;
12198         player->msg_posted = FALSE;
12199         player->has_many_types = FALSE;
12200         player->max_audio_channels = 0;
12201         player->video_share_api_delta = 0;
12202         player->video_share_clock_delta = 0;
12203         player->sound_focus.keep_last_pos = FALSE;
12204         player->sound_focus.acquired = FALSE;
12205         player->is_subtitle_force_drop = FALSE;
12206         player->play_subtitle = FALSE;
12207         player->use_textoverlay = FALSE;
12208         player->adjust_subtitle_pos = 0;
12209         player->last_multiwin_status = FALSE;
12210         player->has_closed_caption = FALSE;
12211         player->set_mode.media_packet_video_stream = FALSE;
12212         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12213         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12214         /* recover mode */
12215         player->set_mode.rich_audio = cur_mode;
12216
12217         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12218                 player->bitrate[i] = 0;
12219                 player->maximum_bitrate[i] = 0;
12220         }
12221
12222         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12223
12224         /* remove media stream cb(appsrc cb) */
12225         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12226                 player->media_stream_buffer_status_cb[i] = NULL;
12227                 player->media_stream_seek_data_cb[i] = NULL;
12228         }
12229         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12230
12231         /* free memory related to audio effect */
12232         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12233
12234         if (player->state_tune_caps) {
12235                 gst_caps_unref(player->state_tune_caps);
12236                 player->state_tune_caps = NULL;
12237         }
12238
12239         MMPLAYER_FLEAVE();
12240 }
12241
12242 static void
12243 __mmplayer_release_misc_post(mm_player_t* player)
12244 {
12245         char *original_uri = NULL;
12246         MMPLAYER_FENTER();
12247
12248         /* player->pipeline is already released before. */
12249
12250         MMPLAYER_RETURN_IF_FAIL(player);
12251
12252         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12253         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12254
12255         /* clean found parsers */
12256         if (player->parsers) {
12257                 GList *parsers = player->parsers;
12258                 for (; parsers; parsers = g_list_next(parsers)) {
12259                         gchar *name = parsers->data;
12260                         MMPLAYER_FREEIF(name);
12261                 }
12262                 g_list_free(player->parsers);
12263                 player->parsers = NULL;
12264         }
12265
12266         /* clean found audio decoders */
12267         if (player->audio_decoders) {
12268                 GList *a_dec = player->audio_decoders;
12269                 for (; a_dec; a_dec = g_list_next(a_dec)) {
12270                         gchar *name = a_dec->data;
12271                         MMPLAYER_FREEIF(name);
12272                 }
12273                 g_list_free(player->audio_decoders);
12274                 player->audio_decoders = NULL;
12275         }
12276
12277         /* clean the uri list except original uri */
12278         if (player->uri_info.uri_list) {
12279                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12280
12281                 if (player->attrs) {
12282                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12283                         LOGD("restore original uri = %s\n", original_uri);
12284
12285                         if (mmf_attrs_commit(player->attrs))
12286                                 LOGE("failed to commit the original uri.\n");
12287                 }
12288
12289                 GList *uri_list = player->uri_info.uri_list;
12290                 for (; uri_list; uri_list = g_list_next(uri_list)) {
12291                         gchar *uri = uri_list->data;
12292                         MMPLAYER_FREEIF(uri);
12293                 }
12294                 g_list_free(player->uri_info.uri_list);
12295                 player->uri_info.uri_list = NULL;
12296         }
12297
12298         /* clear the audio stream buffer list */
12299         __mmplayer_audio_stream_clear_buffer(player, FALSE);
12300
12301         /* clear the video stream bo list */
12302         __mmplayer_video_stream_destroy_bo_list(player);
12303
12304         player->uri_info.uri_idx = 0;
12305         MMPLAYER_FLEAVE();
12306 }
12307
12308 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12309 {
12310         GstElement *element = NULL;
12311         GstPad *sinkpad;
12312
12313         LOGD("creating %s to plug\n", name);
12314
12315         element = gst_element_factory_make(name, NULL);
12316         if (!element) {
12317                 LOGE("failed to create queue\n");
12318                 return NULL;
12319         }
12320
12321         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12322                 LOGE("failed to set state READY to %s\n", name);
12323                 gst_object_unref(element);
12324                 return NULL;
12325         }
12326
12327         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12328                 LOGE("failed to add %s\n", name);
12329                 gst_object_unref(element);
12330                 return NULL;
12331         }
12332
12333         sinkpad = gst_element_get_static_pad(element, "sink");
12334
12335         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12336                 LOGE("failed to link %s\n", name);
12337                 gst_object_unref(sinkpad);
12338                 gst_object_unref(element);
12339                 return NULL;
12340         }
12341
12342         LOGD("linked %s to pipeline successfully\n", name);
12343
12344         gst_object_unref(sinkpad);
12345
12346         return element;
12347 }
12348
12349 static gboolean
12350 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12351 const char *padname, const GList *templlist)
12352 {
12353         GstPad *pad = NULL;
12354         gboolean has_dynamic_pads = FALSE;
12355         gboolean has_many_types = FALSE;
12356         const char *klass = NULL;
12357         GstStaticPadTemplate *padtemplate = NULL;
12358         GstElementFactory *factory = NULL;
12359         GstElement* queue = NULL;
12360         GstElement* parser = NULL;
12361         GstPad *pssrcpad = NULL;
12362         GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12363         MMPlayerGstElement *mainbin = NULL;
12364         GstStructure* str = NULL;
12365         GstCaps* srccaps = NULL;
12366         GstState target_state = GST_STATE_READY;
12367         gboolean isvideo_decoder = FALSE;
12368         guint q_max_size_time = 0;
12369
12370         MMPLAYER_FENTER();
12371
12372         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12373                 player->pipeline &&
12374                 player->pipeline->mainbin,
12375                 FALSE);
12376
12377         mainbin = player->pipeline->mainbin;
12378
12379         LOGD("plugging pad %s:%s to newly create %s:%s\n",
12380                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12381                         GST_PAD_NAME(srcpad),
12382                         GST_ELEMENT_NAME(sinkelement),
12383                         padname);
12384
12385         factory = gst_element_get_factory(sinkelement);
12386         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12387
12388         /* check if player can do start continually */
12389         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12390
12391         /* need it to warm up omx before linking to pipeline */
12392         if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12393                 LOGD("get demux caps.\n");
12394                 if (player->state_tune_caps) {
12395                         gst_caps_unref(player->state_tune_caps);
12396                         player->state_tune_caps = NULL;
12397                 }
12398                 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12399         }
12400
12401         /* NOTE : OMX Codec can check if resource is available or not at this state. */
12402         if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12403                 if (player->state_tune_caps != NULL) {
12404                         LOGD("set demux's caps to omx codec if resource is available");
12405                         if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12406                                 target_state = GST_STATE_PAUSED;
12407                                 isvideo_decoder = TRUE;
12408                                 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12409                         } else
12410                                 LOGW("failed to set caps for state tuning");
12411                 }
12412                 gst_caps_unref(player->state_tune_caps);
12413                 player->state_tune_caps = NULL;
12414         }
12415
12416         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12417                 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12418                 if (isvideo_decoder) {
12419                         gst_element_set_state(sinkelement, GST_STATE_NULL);
12420                         gst_object_unref(G_OBJECT(sinkelement));
12421                         player->keep_detecting_vcodec = TRUE;
12422                 }
12423                 goto ERROR;
12424         }
12425
12426         /* add to pipeline */
12427         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12428                 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12429                 goto ERROR;
12430         }
12431
12432         LOGD("element klass : %s\n", klass);
12433
12434         /* added to support multi track files */
12435         /* only decoder case and any of the video/audio still need to link*/
12436         if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12437                 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12438
12439                 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12440                         gchar *src_demux_caps_str = NULL;
12441                         gchar *needed_parser = NULL;
12442                         GstCaps *src_demux_caps = NULL;
12443                         gboolean smooth_streaming = FALSE;
12444
12445                         src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12446                         src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12447
12448                         gst_caps_unref(src_demux_caps);
12449
12450                         if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12451                                 if (g_strrstr(name, "mssdemux")) {
12452                                         needed_parser = g_strdup("legacyh264parse");
12453                                         smooth_streaming = TRUE;
12454                                 } else
12455                                         needed_parser = g_strdup("h264parse");
12456                         } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12457                                 needed_parser = g_strdup("mpeg4videoparse");
12458
12459                         MMPLAYER_FREEIF(src_demux_caps_str);
12460
12461                         if (needed_parser) {
12462                                 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12463                                 MMPLAYER_FREEIF(needed_parser);
12464
12465                                 if (!parser) {
12466                                         LOGE("failed to create parser\n");
12467                                 } else {
12468                                         if (smooth_streaming)
12469                                                 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12470
12471                                         /* update srcpad if parser is created */
12472                                         pssrcpad = gst_element_get_static_pad(parser, "src");
12473                                         srcpad = pssrcpad;
12474                                 }
12475                         }
12476                 }
12477                 MMPLAYER_FREEIF(name);
12478
12479                 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12480                 if (!queue) {
12481                         LOGE("failed to create queue\n");
12482                         goto ERROR;
12483                 }
12484
12485                 /* update srcpad to link with decoder */
12486                 qsrcpad = gst_element_get_static_pad(queue, "src");
12487                 srcpad = qsrcpad;
12488
12489                 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12490
12491                 /* assigning queue handle for futher manipulation purpose */
12492                 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12493                 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12494                         mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12495                         mainbin[MMPLAYER_M_Q1].gst = queue;
12496
12497                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12498                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12499                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12500                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12501                         } else {
12502                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12503                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12504                         }
12505                 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12506                         mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12507                         mainbin[MMPLAYER_M_Q2].gst = queue;
12508
12509                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12510                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12511                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12512                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12513                         } else {
12514                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12515                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12516                         }
12517                 } else {
12518                         LOGE("Not supporting more then two elementary stream\n");
12519                         g_assert(1);
12520                 }
12521
12522                 pad = gst_element_get_static_pad(sinkelement, padname);
12523
12524                 if (!pad) {
12525                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12526                                 padname, GST_ELEMENT_NAME(sinkelement));
12527
12528                         pad = gst_element_get_static_pad(sinkelement, "sink");
12529                         if (!pad) {
12530                                 LOGE("failed to get pad(sink) from %s. \n",
12531                                 GST_ELEMENT_NAME(sinkelement));
12532                                 goto ERROR;
12533                         }
12534                 }
12535
12536                 /* to check the video/audio type set the proper flag*/
12537                 const gchar *mime_type = NULL;
12538                 srccaps = gst_pad_query_caps(srcpad, NULL);
12539                 if (!srccaps)
12540                         goto ERROR;
12541                 str = gst_caps_get_structure(srccaps, 0);
12542                 if (!str)
12543                         goto ERROR;
12544                 mime_type = gst_structure_get_name(str);
12545                 if (!mime_type)
12546                         goto ERROR;
12547
12548                 /* link queue and decoder. so, it will be queue - decoder. */
12549                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12550                         gst_object_unref(GST_OBJECT(pad));
12551                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12552
12553                         /* reconstitute supportable codec */
12554                         if (strstr(mime_type, "video"))
12555                                 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12556                         else if (strstr(mime_type, "audio"))
12557                                 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12558                         goto ERROR;
12559                 }
12560
12561                 if (strstr(mime_type, "video")) {
12562                         player->videodec_linked = 1;
12563                         LOGI("player->videodec_linked set to 1\n");
12564
12565                 } else if (strstr(mime_type, "audio")) {
12566                         player->audiodec_linked = 1;
12567                         LOGI("player->auddiodec_linked set to 1\n");
12568                 }
12569
12570                 gst_object_unref(GST_OBJECT(pad));
12571                 gst_caps_unref(GST_CAPS(srccaps));
12572                 srccaps = NULL;
12573         }
12574
12575         if (!MMPLAYER_IS_HTTP_PD(player)) {
12576                 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12577                         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12578                                 gint64 dur_bytes = 0L;
12579                                 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12580
12581                                 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12582                                         LOGD("creating http streaming buffering queue\n");
12583
12584                                         queue = gst_element_factory_make("queue2", "queue2");
12585                                         if (!queue) {
12586                                                 LOGE("failed to create buffering queue element\n");
12587                                                 goto ERROR;
12588                                         }
12589
12590                                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12591                                                 LOGE("failed to set state READY to buffering queue\n");
12592                                                 goto ERROR;
12593                                         }
12594
12595                                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12596                                                 LOGE("failed to add buffering queue\n");
12597                                                 goto ERROR;
12598                                         }
12599
12600                                         qsinkpad = gst_element_get_static_pad(queue, "sink");
12601                                         qsrcpad = gst_element_get_static_pad(queue, "src");
12602
12603                                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12604                                                 LOGE("failed to link buffering queue\n");
12605                                                 goto ERROR;
12606                                         }
12607                                         srcpad = qsrcpad;
12608
12609
12610                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12611                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12612
12613                                         if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12614                                                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12615                                                         LOGE("fail to get duration.\n");
12616
12617                                                 if (dur_bytes > 0) {
12618                                                         if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12619                                                                 type = MUXED_BUFFER_TYPE_FILE;
12620                                                         } else {
12621                                                                 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12622                                                                 if (player->streamer)
12623                                                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12624                                                         }
12625                                                 } else {
12626                                                         dur_bytes = 0;
12627                                                 }
12628                                         }
12629
12630                                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
12631                                         if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12632                                                 __mm_player_streaming_set_queue2(player->streamer,
12633                                                         queue,
12634                                                         TRUE,
12635                                                         player->ini.http_max_size_bytes,
12636                                                         player->ini.http_buffering_time,
12637                                                         1.0,
12638                                                         player->ini.http_buffering_limit,
12639                                                         type,
12640                                                         player->http_file_buffering_path,
12641                                                         (guint64)dur_bytes);
12642                                         }
12643                                 }
12644                         }
12645                 }
12646         }
12647         /* if it is not decoder or */
12648         /* in decoder case any of the video/audio still need to link*/
12649         if (!g_strrstr(klass, "Decoder")) {
12650                 pad = gst_element_get_static_pad(sinkelement, padname);
12651                 if (!pad) {
12652                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12653                                         padname, GST_ELEMENT_NAME(sinkelement));
12654
12655                         pad = gst_element_get_static_pad(sinkelement, "sink");
12656
12657                         if (!pad) {
12658                                 LOGE("failed to get pad(sink) from %s. \n",
12659                                         GST_ELEMENT_NAME(sinkelement));
12660                                 goto ERROR;
12661                         }
12662                 }
12663
12664                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12665                         gst_object_unref(GST_OBJECT(pad));
12666                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12667                         goto ERROR;
12668                 }
12669
12670                 gst_object_unref(GST_OBJECT(pad));
12671         }
12672
12673         for (; templlist != NULL; templlist = templlist->next) {
12674                 padtemplate = templlist->data;
12675
12676                 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12677
12678                 if (padtemplate->direction != GST_PAD_SRC ||
12679                         padtemplate->presence == GST_PAD_REQUEST)
12680                         continue;
12681
12682                 switch (padtemplate->presence) {
12683                 case GST_PAD_ALWAYS:
12684                         {
12685                                 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12686                                 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12687
12688                                 /* Check whether caps has many types */
12689                                 if (!gst_caps_is_fixed(caps)) {
12690                                         LOGD("always pad but, caps has many types");
12691                                         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12692                                         has_many_types = TRUE;
12693                                         break;
12694                                 }
12695
12696                                 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12697                                         gst_object_unref(GST_OBJECT(srcpad));
12698                                         gst_caps_unref(GST_CAPS(caps));
12699
12700                                         LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12701                                         goto ERROR;
12702                                 }
12703
12704                                 gst_caps_unref(GST_CAPS(caps));
12705                                 gst_object_unref(GST_OBJECT(srcpad));
12706
12707                         }
12708                         break;
12709
12710
12711                 case GST_PAD_SOMETIMES:
12712                         has_dynamic_pads = TRUE;
12713                         break;
12714
12715                 default:
12716                         break;
12717                 }
12718         }
12719
12720         /* check if player can do start continually */
12721         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12722
12723         if (has_dynamic_pads) {
12724                 player->have_dynamic_pad = TRUE;
12725                 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12726                         G_CALLBACK(__mmplayer_add_new_pad), player);
12727
12728                 /* for streaming, more then one typefind will used for each elementary stream
12729                  * so this doesn't mean the whole pipeline completion
12730                  */
12731                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12732                         MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12733                                 G_CALLBACK(__mmplayer_pipeline_complete), player);
12734                 }
12735         }
12736
12737         if (has_many_types) {
12738                 GstPad *pad = NULL;
12739
12740                 player->has_many_types = has_many_types;
12741
12742                 pad = gst_element_get_static_pad(sinkelement, "src");
12743                 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12744                 gst_object_unref(GST_OBJECT(pad));
12745         }
12746
12747
12748         /* check if player can do start continually */
12749         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12750
12751         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12752                 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12753                 goto ERROR;
12754         }
12755
12756         if (queue) {
12757                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12758                         LOGE("failed to set state PAUSED to queue\n");
12759                         goto ERROR;
12760                 }
12761
12762                 queue = NULL;
12763
12764                 gst_object_unref(GST_OBJECT(qsrcpad));
12765                 qsrcpad = NULL;
12766         }
12767
12768         if (parser) {
12769                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12770                         LOGE("failed to set state PAUSED to queue\n");
12771                         goto ERROR;
12772                 }
12773
12774                 parser = NULL;
12775
12776                 gst_object_unref(GST_OBJECT(pssrcpad));
12777                 pssrcpad = NULL;
12778         }
12779
12780         MMPLAYER_FLEAVE();
12781
12782         return TRUE;
12783
12784 ERROR:
12785
12786         if (queue) {
12787                 gst_object_unref(GST_OBJECT(qsrcpad));
12788
12789                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12790                  * You need to explicitly set elements to the NULL state before
12791                  * dropping the final reference, to allow them to clean up.
12792                  */
12793                 gst_element_set_state(queue, GST_STATE_NULL);
12794                 /* And, it still has a parent "player".
12795                  * You need to let the parent manage the object instead of unreffing the object directly.
12796                  */
12797
12798                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12799                 //gst_object_unref(queue);
12800         }
12801
12802         if (srccaps)
12803                 gst_caps_unref(GST_CAPS(srccaps));
12804
12805         return FALSE;
12806 }
12807
12808 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12809 {
12810         const gchar *klass;
12811
12812         /* we only care about element factories */
12813         if (!GST_IS_ELEMENT_FACTORY(feature))
12814                 return FALSE;
12815
12816         /* only parsers, demuxers and decoders */
12817                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12818
12819         if (g_strrstr(klass, "Demux") == NULL &&
12820                         g_strrstr(klass, "Codec/Decoder") == NULL &&
12821                         g_strrstr(klass, "Depayloader") == NULL &&
12822                         g_strrstr(klass, "Parse") == NULL)
12823                 return FALSE;
12824         return TRUE;
12825 }
12826
12827
12828 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12829 {
12830         mm_player_t* player = (mm_player_t*) data;
12831         GstCaps *caps = NULL;
12832         GstStructure *str = NULL;
12833         const char *name;
12834
12835         MMPLAYER_FENTER();
12836
12837         MMPLAYER_RETURN_IF_FAIL(pad)
12838         MMPLAYER_RETURN_IF_FAIL(unused)
12839         MMPLAYER_RETURN_IF_FAIL(data)
12840
12841         caps = gst_pad_query_caps(pad, NULL);
12842         if (!caps)
12843                 return;
12844
12845         str = gst_caps_get_structure(caps, 0);
12846         if (!str)
12847                 return;
12848
12849         name = gst_structure_get_name(str);
12850         if (!name)
12851                 return;
12852         LOGD("name=%s\n", name);
12853
12854         if (!__mmplayer_try_to_plug(player, pad, caps)) {
12855                 LOGE("failed to autoplug for type(%s)\n", name);
12856                 gst_caps_unref(caps);
12857                 return;
12858         }
12859
12860         gst_caps_unref(caps);
12861
12862         __mmplayer_pipeline_complete(NULL, (gpointer)player);
12863
12864         MMPLAYER_FLEAVE();
12865
12866         return;
12867 }
12868
12869 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12870 {
12871         GstStructure *str;
12872         gint version = 0;
12873         const char *stream_type;
12874         gchar *version_field = NULL;
12875
12876         MMPLAYER_FENTER();
12877
12878         MMPLAYER_RETURN_IF_FAIL(player);
12879         MMPLAYER_RETURN_IF_FAIL(caps);
12880
12881         str = gst_caps_get_structure(caps, 0);
12882         if (!str)
12883                 return;
12884
12885         stream_type = gst_structure_get_name(str);
12886         if (!stream_type)
12887                 return;
12888
12889
12890         /* set unlinked mime type for downloadable codec */
12891         if (g_str_has_prefix(stream_type, "video/")) {
12892                 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12893                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12894                         version_field = MM_PLAYER_MPEG_VNAME;
12895                 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12896                         gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12897                         version_field = MM_PLAYER_WMV_VNAME;
12898
12899                 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12900                         gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12901                         version_field = MM_PLAYER_DIVX_VNAME;
12902                 }
12903
12904                 if (version)
12905                         player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12906                 else
12907                         player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12908         } else if (g_str_has_prefix(stream_type, "audio/")) {
12909                 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12910                         // mp3 or aac
12911                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12912                         version_field = MM_PLAYER_MPEG_VNAME;
12913                 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12914                         gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12915                         version_field = MM_PLAYER_WMA_VNAME;
12916                 }
12917
12918                 if (version)
12919                         player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12920                 else
12921                         player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12922         }
12923
12924         MMPLAYER_FLEAVE();
12925 }
12926
12927 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12928 {
12929         mm_player_t* player = (mm_player_t*) data;
12930         GstCaps *caps = NULL;
12931         GstStructure *str = NULL;
12932         const char *name;
12933
12934         MMPLAYER_FENTER();
12935         MMPLAYER_RETURN_IF_FAIL(player);
12936         MMPLAYER_RETURN_IF_FAIL(pad);
12937
12938         GST_OBJECT_LOCK(pad);
12939         if ((caps = gst_pad_get_current_caps(pad)))
12940                 gst_caps_ref(caps);
12941         GST_OBJECT_UNLOCK(pad);
12942
12943         if (NULL == caps) {
12944                 caps = gst_pad_query_caps(pad, NULL);
12945                 if (!caps) return;
12946         }
12947
12948         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12949
12950         str = gst_caps_get_structure(caps, 0);
12951         if (!str)
12952                 return;
12953
12954         name = gst_structure_get_name(str);
12955         if (!name)
12956                 return;
12957
12958         player->num_dynamic_pad++;
12959         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12960
12961         /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12962           *     If want to play it, remove this code.
12963           */
12964         if (g_strrstr(name, "application")) {
12965                 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12966                         /* If id3/ape tag comes, keep going */
12967                         LOGD("application mime exception : id3/ape tag");
12968                 } else {
12969                         /* Otherwise, we assume that this stream is subtile. */
12970                         LOGD(" application mime type pad is closed.");
12971                         return;
12972                 }
12973         } else if (g_strrstr(name, "audio")) {
12974                 gint samplerate = 0, channels = 0;
12975
12976                 if (player->audiodec_linked) {
12977                         gst_caps_unref(caps);
12978                         LOGD("multi tracks. skip to plug");
12979                         return;
12980                 }
12981
12982                 /* set stream information */
12983                 /* if possible, set it here because the caps is not distrubed by resampler. */
12984                 gst_structure_get_int(str, "rate", &samplerate);
12985                 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12986
12987                 gst_structure_get_int(str, "channels", &channels);
12988                 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12989
12990                 LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
12991         } else if (g_strrstr(name, "video")) {
12992                 gint stype;
12993                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12994
12995                 /* don't make video because of not required */
12996                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
12997                         LOGD("no video because it's not required");
12998                         return;
12999                 }
13000
13001                 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13002         }
13003
13004         if (!__mmplayer_try_to_plug(player, pad, caps)) {
13005                 LOGE("failed to autoplug for type(%s)", name);
13006
13007                 __mmplayer_set_unlinked_mime_type(player, caps);
13008         }
13009
13010         gst_caps_unref(caps);
13011
13012         MMPLAYER_FLEAVE();
13013         return;
13014 }
13015
13016 gboolean
13017 __mmplayer_check_subtitle(mm_player_t* player)
13018 {
13019         MMHandleType attrs = 0;
13020         char *subtitle_uri = NULL;
13021
13022         MMPLAYER_FENTER();
13023
13024         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13025
13026         /* get subtitle attribute */
13027         attrs = MMPLAYER_GET_ATTRS(player);
13028         if (!attrs)
13029                 return FALSE;
13030
13031         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13032         if (!subtitle_uri || !strlen(subtitle_uri))
13033                 return FALSE;
13034
13035         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13036         player->is_external_subtitle_present = TRUE;
13037
13038         MMPLAYER_FLEAVE();
13039
13040         return TRUE;
13041 }
13042
13043 static gboolean
13044 __mmplayer_can_extract_pcm(mm_player_t* player)
13045 {
13046         MMHandleType attrs = 0;
13047         gboolean sound_extraction = FALSE;
13048
13049         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13050
13051         attrs = MMPLAYER_GET_ATTRS(player);
13052         if (!attrs) {
13053                 LOGE("fail to get attributes.");
13054                 return FALSE;
13055         }
13056
13057         /* get sound_extraction property */
13058         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13059
13060         if (!sound_extraction) {
13061                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13062                 return FALSE;
13063         }
13064
13065         return TRUE;
13066 }
13067
13068 static gboolean
13069 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13070 {
13071         LOGD("\n");
13072         MMMessageParamType msg_param;
13073         gchar *msg_src_element = NULL;
13074         GstStructure *s = NULL;
13075         guint error_id = 0;
13076         gchar *error_string = NULL;
13077
13078         MMPLAYER_FENTER();
13079
13080         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13081         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13082
13083         s = malloc(sizeof(GstStructure));
13084         memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13085
13086         if (!gst_structure_get_uint(s, "error_id", &error_id))
13087                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13088
13089         switch (error_id) {
13090         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13091                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13092                 break;
13093         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13094                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13095                 break;
13096         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13097                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13098                 break;
13099         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13100                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13101                 break;
13102         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13103                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13104                 break;
13105         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13106                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13107                 break;
13108         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13109                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13110                 break;
13111         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13112                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13113                 break;
13114         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13115                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13116                 break;
13117         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13118                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13119                 break;
13120         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13121                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13122                 break;
13123         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13124                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13125                 break;
13126         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13127                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13128                 break;
13129         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13130                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13131                 break;
13132         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13133                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13134                 break;
13135         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13136                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13137                 break;
13138         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13139                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13140                 break;
13141         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13142                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13143                 break;
13144         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13145                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13146                 break;
13147         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13148                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13149                 break;
13150         case MMPLAYER_STREAMING_ERROR_GONE:
13151                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13152                 break;
13153         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13154                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13155                 break;
13156         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13157                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13158                 break;
13159         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13160                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13161                 break;
13162         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13163                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13164                 break;
13165         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13166                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13167                 break;
13168         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13169                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13170                 break;
13171         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13172                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13173                 break;
13174         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13175                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13176                 break;
13177         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13178                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13179                 break;
13180         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13181                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13182                 break;
13183         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13184                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13185                 break;
13186         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13187                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13188                 break;
13189         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13190                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13191                 break;
13192         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13193                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13194                 break;
13195         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13196                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13197                 break;
13198         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13199                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13200                 break;
13201         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13202                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13203                 break;
13204         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13205                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13206                 break;
13207         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13208                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13209                 break;
13210         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13211                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13212                 break;
13213         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13214                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13215                 break;
13216         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13217                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13218                 break;
13219         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13220                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13221                 break;
13222         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13223                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13224                 break;
13225         default:
13226                 {
13227                         MMPLAYER_FREEIF(s);
13228                         return MM_ERROR_PLAYER_STREAMING_FAIL;
13229                 }
13230         }
13231
13232         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13233         if (error_string)
13234                 msg_param.data = (void *) error_string;
13235
13236         if (message->src) {
13237                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13238
13239                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
13240                         msg_src_element, msg_param.code, (char*)msg_param.data);
13241         }
13242
13243         /* post error to application */
13244         if (!player->msg_posted) {
13245                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13246
13247                 /* don't post more if one was sent already */
13248                 player->msg_posted = TRUE;
13249         } else
13250                 LOGD("skip error post because it's sent already.\n");
13251
13252         MMPLAYER_FREEIF(s);
13253         MMPLAYER_FLEAVE();
13254         g_free(error_string);
13255
13256         return TRUE;
13257
13258 }
13259
13260 static void
13261 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13262 {
13263         MMPLAYER_RETURN_IF_FAIL(player);
13264
13265
13266         /* post now if delay is zero */
13267         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13268                 LOGD("eos delay is zero. posting EOS now\n");
13269                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13270
13271                 if (player->set_mode.pcm_extraction)
13272                         __mmplayer_cancel_eos_timer(player);
13273
13274                 return;
13275         }
13276
13277         /* cancel if existing */
13278         __mmplayer_cancel_eos_timer(player);
13279
13280         /* init new timeout */
13281         /* NOTE : consider give high priority to this timer */
13282         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13283
13284         player->eos_timer = g_timeout_add(delay_in_ms,
13285                 __mmplayer_eos_timer_cb, player);
13286
13287         player->context.global_default = g_main_context_default();
13288         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13289
13290         /* check timer is valid. if not, send EOS now */
13291         if (player->eos_timer == 0) {
13292                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13293                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13294         }
13295 }
13296
13297 static void
13298 __mmplayer_cancel_eos_timer(mm_player_t* player)
13299 {
13300         MMPLAYER_RETURN_IF_FAIL(player);
13301
13302         if (player->eos_timer) {
13303                 LOGD("cancel eos timer");
13304                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13305                 player->eos_timer = 0;
13306         }
13307
13308         return;
13309 }
13310
13311 static gboolean
13312 __mmplayer_eos_timer_cb(gpointer u_data)
13313 {
13314         mm_player_t* player = NULL;
13315         player = (mm_player_t*) u_data;
13316
13317         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13318
13319         if (player->play_count > 1) {
13320                 gint ret_value = 0;
13321                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13322                 if (ret_value == MM_ERROR_NONE) {
13323                         MMHandleType attrs = 0;
13324                         attrs = MMPLAYER_GET_ATTRS(player);
13325
13326                         /* we successeded to rewind. update play count and then wait for next EOS */
13327                         player->play_count--;
13328
13329                         mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13330                         mmf_attrs_commit(attrs);
13331                 } else
13332                         LOGE("seeking to 0 failed in repeat play");
13333         } else
13334                 /* posting eos */
13335                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13336
13337         /* we are returning FALSE as we need only one posting */
13338         return FALSE;
13339 }
13340
13341 static gboolean
13342 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13343 {
13344         const gchar* name = NULL;
13345         GstStructure* str = NULL;
13346         GstCaps* srccaps = NULL;
13347
13348         MMPLAYER_FENTER();
13349
13350         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13351         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13352
13353         /* to check any of the decoder(video/audio) need to be linked  to parser*/
13354         srccaps = gst_pad_query_caps(srcpad, NULL);
13355         if (!srccaps)
13356                 goto ERROR;
13357
13358         str = gst_caps_get_structure(srccaps, 0);
13359         if (!str)
13360                 goto ERROR;
13361
13362         name = gst_structure_get_name(str);
13363         if (!name)
13364                 goto ERROR;
13365
13366         if (strstr(name, "video")) {
13367                 if (player->videodec_linked) {
13368                     LOGI("Video decoder already linked\n");
13369                         return FALSE;
13370                 }
13371         }
13372         if (strstr(name, "audio")) {
13373                 if (player->audiodec_linked) {
13374                     LOGI("Audio decoder already linked\n");
13375                         return FALSE;
13376                 }
13377         }
13378
13379         gst_caps_unref(srccaps);
13380
13381         MMPLAYER_FLEAVE();
13382
13383         return TRUE;
13384
13385 ERROR:
13386         if (srccaps)
13387                 gst_caps_unref(srccaps);
13388
13389         return FALSE;
13390 }
13391
13392 static gboolean
13393 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13394 {
13395         const gchar* name = NULL;
13396         GstStructure* str = NULL;
13397         GstCaps* srccaps = NULL;
13398
13399         MMPLAYER_FENTER();
13400
13401         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13402         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13403
13404         /* to check any of the decoder(video/audio) need to be linked   to parser*/
13405         srccaps = gst_pad_query_caps(srcpad, NULL);
13406         if (!srccaps)
13407                 goto ERROR;
13408
13409         str = gst_caps_get_structure(srccaps, 0);
13410         if (!str)
13411                 goto ERROR;
13412
13413         name = gst_structure_get_name(str);
13414         if (!name)
13415                 goto ERROR;
13416
13417         if (strstr(name, "video")) {
13418                 if (player->videosink_linked) {
13419                         LOGI("Video Sink already linked\n");
13420                         return FALSE;
13421                 }
13422         }
13423         if (strstr(name, "audio")) {
13424                 if (player->audiosink_linked) {
13425                         LOGI("Audio Sink already linked\n");
13426                         return FALSE;
13427                 }
13428         }
13429         if (strstr(name, "text")) {
13430                 if (player->textsink_linked) {
13431                         LOGI("Text Sink already linked\n");
13432                         return FALSE;
13433                 }
13434         }
13435
13436         gst_caps_unref(srccaps);
13437
13438         MMPLAYER_FLEAVE();
13439
13440         //return (!player->videosink_linked || !player->audiosink_linked);
13441         return TRUE;
13442
13443 ERROR:
13444         if (srccaps)
13445                 gst_caps_unref(srccaps);
13446
13447         return FALSE;
13448 }
13449
13450
13451 /* sending event to one of sinkelements */
13452 static gboolean
13453 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13454 {
13455         GstEvent * event2 = NULL;
13456         GList *sinks = NULL;
13457         gboolean res = FALSE;
13458         MMPLAYER_FENTER();
13459
13460         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13461         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13462
13463         /* While adding subtitles in live feeds seek is getting called.
13464            Adding defensive check in framework layer.*/
13465         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13466                 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13467                         LOGE ("Should not send seek event during live playback");
13468                         return TRUE;
13469                 }
13470         }
13471
13472         if (player->play_subtitle && !player->use_textoverlay)
13473                 event2 = gst_event_copy((const GstEvent *)event);
13474
13475         sinks = player->sink_elements;
13476         while (sinks) {
13477                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13478
13479                 if (GST_IS_ELEMENT(sink)) {
13480                         /* keep ref to the event */
13481                         gst_event_ref(event);
13482
13483                         if ((res = gst_element_send_event(sink, event))) {
13484                                 LOGD("sending event[%s] to sink element [%s] success!\n",
13485                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13486
13487                                 /* rtsp case, asyn_done is not called after seek during pause state */
13488                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13489                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13490                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13491                                                         LOGD("RTSP seek completed, after pause state..\n");
13492                                                         player->doing_seek = FALSE;
13493                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13494                                                 }
13495
13496                                         }
13497                                 }
13498
13499                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13500                                         sinks = g_list_next(sinks);
13501                                         continue;
13502                                 } else
13503                                         break;
13504                         }
13505
13506                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13507                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13508                 }
13509
13510                 sinks = g_list_next(sinks);
13511         }
13512
13513 #if 0
13514         if (internal_sub)
13515           request pad name = sink0;
13516         else
13517           request pad name = sink1; // external
13518 #endif
13519
13520         /* Note : Textbin is not linked to the video or audio bin.
13521          * It needs to send the event to the text sink seperatelly.
13522          */
13523          if (player->play_subtitle && !player->use_textoverlay) {
13524                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13525
13526                 if (GST_IS_ELEMENT(text_sink)) {
13527                         /* keep ref to the event */
13528                         gst_event_ref(event2);
13529
13530                         if ((res = gst_element_send_event(text_sink, event2)))
13531                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13532                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13533                         else
13534                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13535                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13536
13537                         gst_event_unref(event2);
13538                 }
13539          }
13540
13541         gst_event_unref(event);
13542
13543         MMPLAYER_FLEAVE();
13544
13545         return res;
13546 }
13547
13548 static void
13549 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13550 {
13551         MMPLAYER_FENTER();
13552
13553         MMPLAYER_RETURN_IF_FAIL(player);
13554         MMPLAYER_RETURN_IF_FAIL(sink);
13555
13556         player->sink_elements =
13557                 g_list_append(player->sink_elements, sink);
13558
13559         MMPLAYER_FLEAVE();
13560 }
13561
13562 static void
13563 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13564 {
13565         MMPLAYER_FENTER();
13566
13567         MMPLAYER_RETURN_IF_FAIL(player);
13568         MMPLAYER_RETURN_IF_FAIL(sink);
13569
13570         player->sink_elements =
13571                         g_list_remove(player->sink_elements, sink);
13572
13573         MMPLAYER_FLEAVE();
13574 }
13575
13576 static gboolean
13577 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13578                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13579                         gint64 cur, GstSeekType stop_type, gint64 stop)
13580 {
13581         GstEvent* event = NULL;
13582         gboolean result = FALSE;
13583
13584         MMPLAYER_FENTER();
13585
13586         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13587
13588         if (player->pipeline && player->pipeline->textbin)
13589                 __mmplayer_drop_subtitle(player, FALSE);
13590
13591         event = gst_event_new_seek(rate, format, flags, cur_type,
13592                 cur, stop_type, stop);
13593
13594         result = __gst_send_event_to_sink(player, event);
13595
13596         MMPLAYER_FLEAVE();
13597
13598         return result;
13599 }
13600
13601 /* NOTE : be careful with calling this api. please refer to below glib comment
13602  * glib comment : Note that there is a bug in GObject that makes this function much
13603  * less useful than it might seem otherwise. Once gobject is disposed, the callback
13604  * will no longer be called, but, the signal handler is not currently disconnected.
13605  * If the instance is itself being freed at the same time than this doesn't matter,
13606  * since the signal will automatically be removed, but if instance persists,
13607  * then the signal handler will leak. You should not remove the signal yourself
13608  * because in a future versions of GObject, the handler will automatically be
13609  * disconnected.
13610  *
13611  * It's possible to work around this problem in a way that will continue to work
13612  * with future versions of GObject by checking that the signal handler is still
13613  * connected before disconnected it:
13614  *
13615  *  if (g_signal_handler_is_connected(instance, id))
13616  *    g_signal_handler_disconnect(instance, id);
13617  */
13618 static void
13619 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13620 {
13621         GList* sig_list = NULL;
13622         MMPlayerSignalItem* item = NULL;
13623
13624         MMPLAYER_FENTER();
13625
13626         MMPLAYER_RETURN_IF_FAIL(player);
13627
13628         LOGD("release signals type : %d", type);
13629
13630         if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13631                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13632                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13633                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13634                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13635                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13636                 return;
13637         }
13638
13639         sig_list = player->signals[type];
13640
13641         for (; sig_list; sig_list = sig_list->next) {
13642                 item = sig_list->data;
13643
13644                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13645                         if (g_signal_handler_is_connected(item->obj, item->sig))
13646                                 g_signal_handler_disconnect(item->obj, item->sig);
13647                 }
13648
13649                 MMPLAYER_FREEIF(item);
13650         }
13651
13652         g_list_free(player->signals[type]);
13653         player->signals[type] = NULL;
13654
13655         MMPLAYER_FLEAVE();
13656
13657         return;
13658 }
13659
13660 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13661 {
13662         mm_player_t* player = 0;
13663         int prev_display_surface_type = 0;
13664         void *prev_display_overlay = NULL;
13665         const gchar *klass = NULL;
13666         gchar *cur_videosink_name = NULL;
13667         int ret = 0;
13668         int i = 0;
13669         int num_of_dec = 2; /* DEC1, DEC2 */
13670
13671         MMPLAYER_FENTER();
13672
13673         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13674         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13675
13676         player = MM_PLAYER_CAST(handle);
13677
13678         if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13679                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13680                 MMPLAYER_FLEAVE();
13681                 return MM_ERROR_INVALID_ARGUMENT;
13682         }
13683
13684         /* load previous attributes */
13685         if (player->attrs) {
13686                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13687                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13688                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13689                 if (prev_display_surface_type == surface_type) {
13690                         LOGD("incoming display surface type is same as previous one, do nothing..");
13691                         MMPLAYER_FLEAVE();
13692                         return MM_ERROR_NONE;
13693                 }
13694         } else {
13695                 LOGE("failed to load attributes");
13696                 MMPLAYER_FLEAVE();
13697                 return MM_ERROR_PLAYER_INTERNAL;
13698         }
13699
13700         /* check videosink element is created */
13701         if (!player->pipeline || !player->pipeline->videobin ||
13702                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13703                 LOGD("videosink element is not yet ready");
13704
13705                 /* videobin is not created yet, so we just set attributes related to display surface */
13706                 LOGD("store display attribute for given surface type(%d)", surface_type);
13707                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13708                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13709                 if (mmf_attrs_commit(player->attrs)) {
13710                         LOGE("failed to commit attribute");
13711                         MMPLAYER_FLEAVE();
13712                         return MM_ERROR_PLAYER_INTERNAL;
13713                 }
13714                 MMPLAYER_FLEAVE();
13715                 return MM_ERROR_NONE;
13716         } else {
13717                 /* get player command status */
13718                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13719                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13720                         MMPLAYER_FLEAVE();
13721                         return MM_ERROR_PLAYER_INVALID_STATE;
13722                 }
13723
13724                 /* surface change */
13725                 for (i = 0 ; i < num_of_dec ; i++) {
13726                         if (player->pipeline->mainbin &&
13727                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13728                                 GstElementFactory *decfactory;
13729                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13730
13731                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13732                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13733                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13734                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13735                                                 if (ret) {
13736                                                         goto ERROR_CASE;
13737                                                 } else {
13738                                                         LOGW("success to changing display surface(%d)", surface_type);
13739                                                         MMPLAYER_FLEAVE();
13740                                                         return MM_ERROR_NONE;
13741                                                 }
13742                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13743                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13744                                                 if (ret) {
13745                                                         goto ERROR_CASE;
13746                                                 } else {
13747                                                         LOGW("success to changing display surface(%d)", surface_type);
13748                                                         MMPLAYER_FLEAVE();
13749                                                         return MM_ERROR_NONE;
13750                                                 }
13751                                         } else {
13752                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13753                                                 ret = MM_ERROR_PLAYER_INTERNAL;
13754                                                 goto ERROR_CASE;
13755                                         }
13756                                 }
13757                         }
13758                 }
13759         }
13760
13761 ERROR_CASE:
13762         /* rollback to previous attributes */
13763         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13764         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13765         if (mmf_attrs_commit(player->attrs)) {
13766                 LOGE("failed to commit attributes to rollback");
13767                 MMPLAYER_FLEAVE();
13768                 return MM_ERROR_PLAYER_INTERNAL;
13769         }
13770         MMPLAYER_FLEAVE();
13771         return ret;
13772 }
13773
13774 /* NOTE : It does not support some use cases, eg using colorspace converter */
13775 int
13776 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13777 {
13778         GstPad *src_pad_dec = NULL;
13779         GstPad *sink_pad_videosink = NULL;
13780         GstPad *sink_pad_videobin = NULL;
13781         GstClock *clock = NULL;
13782         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13783         int ret = MM_ERROR_NONE;
13784         gboolean is_audiobin_created = TRUE;
13785
13786         MMPLAYER_FENTER();
13787
13788         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13789         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13790         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13791
13792         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13793         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13794
13795         /* get information whether if audiobin is created */
13796         if (!player->pipeline->audiobin ||
13797                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13798                 LOGW("audiobin is null, this video content may not have audio data");
13799                 is_audiobin_created = FALSE;
13800         }
13801
13802         /* get current state of player */
13803         previous_state = MMPLAYER_CURRENT_STATE(player);
13804         LOGD("previous state(%d)", previous_state);
13805
13806
13807         /* get src pad of decoder and block it */
13808         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13809         if (!src_pad_dec) {
13810                 LOGE("failed to get src pad from decode in mainbin");
13811                 return MM_ERROR_PLAYER_INTERNAL;
13812         }
13813
13814         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13815                 LOGW("trying to block pad(video)");
13816 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13817                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13818                         NULL, NULL, NULL);
13819                 {
13820                         LOGE("failed to set block pad(video)");
13821                         return MM_ERROR_PLAYER_INTERNAL;
13822                 }
13823                 LOGW("pad is blocked(video)");
13824         } else {
13825                 /* no data flows, so no need to do pad_block */
13826                 if (player->doing_seek)
13827                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
13828
13829                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13830         }
13831
13832         /* remove pad */
13833         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13834                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13835                 LOGE("failed to remove previous ghost_pad for videobin");
13836                 return MM_ERROR_PLAYER_INTERNAL;
13837         }
13838
13839         /* change state of videobin to NULL */
13840         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13841         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13842         if (ret != GST_STATE_CHANGE_SUCCESS) {
13843                 LOGE("failed to change state of videobin to NULL");
13844                 return MM_ERROR_PLAYER_INTERNAL;
13845         }
13846
13847         /* unlink between decoder and videobin and remove previous videosink from videobin */
13848         GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13849         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13850                 LOGE("failed to remove former videosink from videobin");
13851                 return MM_ERROR_PLAYER_INTERNAL;
13852         }
13853
13854         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13855
13856         /* create a new videosink and add it to videobin */
13857         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13858         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13859                 LOGE("failed to create videosink element\n");
13860                 MMPLAYER_FLEAVE();
13861                 return MM_ERROR_PLAYER_INTERNAL;
13862         }
13863         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13864         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13865         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13866
13867         /* save attributes */
13868         if (player->attrs) {
13869                 /* set a new display surface type */
13870                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13871                 /* set a new diplay overlay */
13872                 switch (surface_type) {
13873                 case MM_DISPLAY_SURFACE_OVERLAY:
13874                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13875                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13876                         break;
13877                 default:
13878                         LOGE("invalid type(%d) for changing display surface", surface_type);
13879                         MMPLAYER_FLEAVE();
13880                         return MM_ERROR_INVALID_ARGUMENT;
13881                 }
13882                 if (mmf_attrs_commit(player->attrs)) {
13883                         LOGE("failed to commit");
13884                         MMPLAYER_FLEAVE();
13885                         return MM_ERROR_PLAYER_INTERNAL;
13886                 }
13887         } else {
13888                 LOGE("player->attrs is null, failed to save attributes");
13889                 MMPLAYER_FLEAVE();
13890                 return MM_ERROR_PLAYER_INTERNAL;
13891         }
13892
13893         /* update video param */
13894         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13895                 LOGE("failed to update video param");
13896                 return MM_ERROR_PLAYER_INTERNAL;
13897         }
13898
13899         /* change state of videobin to READY */
13900         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13901         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13902         if (ret != GST_STATE_CHANGE_SUCCESS) {
13903                 LOGE("failed to change state of videobin to READY");
13904                 return MM_ERROR_PLAYER_INTERNAL;
13905         }
13906
13907         /* change ghostpad */
13908         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13909         if (!sink_pad_videosink) {
13910                 LOGE("failed to get sink pad from videosink element");
13911                 return MM_ERROR_PLAYER_INTERNAL;
13912         }
13913         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13914         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13915                 LOGE("failed to set active to ghost_pad");
13916                 return MM_ERROR_PLAYER_INTERNAL;
13917         }
13918         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13919                 LOGE("failed to change ghostpad for videobin");
13920                 return MM_ERROR_PLAYER_INTERNAL;
13921         }
13922         gst_object_unref(sink_pad_videosink);
13923
13924         /* link decoder with videobin */
13925         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13926         if (!sink_pad_videobin) {
13927                 LOGE("failed to get sink pad from videobin");
13928                 return MM_ERROR_PLAYER_INTERNAL;
13929         }
13930         if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13931                 LOGE("failed to link");
13932                 return MM_ERROR_PLAYER_INTERNAL;
13933         }
13934         gst_object_unref(sink_pad_videobin);
13935
13936         /* clock setting for a new videosink plugin */
13937         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13938                         so we set it from audiosink plugin or pipeline(system clock) */
13939         if (!is_audiobin_created) {
13940                 LOGW("audiobin is not created, get clock from pipeline..");
13941                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13942         } else {
13943                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13944         }
13945         if (clock) {
13946                 GstClockTime now;
13947                 GstClockTime base_time;
13948                 LOGD("set the clock to videosink");
13949                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13950                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13951                 if (clock) {
13952                         LOGD("got clock of videosink");
13953                         now = gst_clock_get_time(clock);
13954                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13955                         LOGD("at time %" GST_TIME_FORMAT ", base %"
13956                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13957                 } else {
13958                         LOGE("failed to get clock of videosink after setting clock");
13959                         return MM_ERROR_PLAYER_INTERNAL;
13960                 }
13961         } else
13962                 LOGW("failed to get clock, maybe it is the time before first playing");
13963
13964         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13965                 /* change state of videobin to PAUSED */
13966                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13967                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13968                 if (ret != GST_STATE_CHANGE_FAILURE) {
13969                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13970                 } else {
13971                         LOGE("failed to change state of videobin to PLAYING");
13972                         return MM_ERROR_PLAYER_INTERNAL;
13973                 }
13974
13975                 /* release blocked and unref src pad of video decoder */
13976                 #if 0
13977                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13978                         LOGE("failed to set pad blocked FALSE(video)");
13979                         return MM_ERROR_PLAYER_INTERNAL;
13980                 }
13981                 #endif
13982                 LOGW("pad is unblocked(video)");
13983         } else {
13984                 if (player->doing_seek)
13985                         LOGW("not completed seek(%d)", player->doing_seek);
13986                 /* change state of videobin to PAUSED */
13987                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13988                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13989                 if (ret != GST_STATE_CHANGE_FAILURE) {
13990                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13991                 } else {
13992                         LOGE("failed to change state of videobin to PLAYING");
13993                         return MM_ERROR_PLAYER_INTERNAL;
13994                 }
13995
13996                 /* already skipped pad block */
13997                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
13998         }
13999
14000         /* do get/set position for new videosink plugin */
14001         {
14002                 unsigned long position = 0;
14003                 gint64 pos_msec = 0;
14004
14005                 LOGD("do get/set position for new videosink plugin");
14006                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14007                         LOGE("failed to get position");
14008                         return MM_ERROR_PLAYER_INTERNAL;
14009                 }
14010 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14011                 /* accurate seek */
14012                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14013                         LOGE("failed to set position");
14014                         return MM_ERROR_PLAYER_INTERNAL;
14015                 }
14016 #else
14017                 /* key unit seek */
14018                 pos_msec = position * G_GINT64_CONSTANT(1000000);
14019                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14020                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14021                                                         GST_SEEK_TYPE_SET, pos_msec,
14022                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14023                 if (!ret) {
14024                         LOGE("failed to set position");
14025                         return MM_ERROR_PLAYER_INTERNAL;
14026                 }
14027 #endif
14028         }
14029
14030         if (src_pad_dec)
14031                 gst_object_unref(src_pad_dec);
14032         LOGD("success to change sink");
14033
14034         MMPLAYER_FLEAVE();
14035
14036         return MM_ERROR_NONE;
14037 }
14038
14039
14040 /* Note : if silent is true, then subtitle would not be displayed. :*/
14041 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14042 {
14043         mm_player_t* player = (mm_player_t*) hplayer;
14044
14045         MMPLAYER_FENTER();
14046
14047         /* check player handle */
14048         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14049
14050         player->set_mode.subtitle_off = silent;
14051
14052         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14053
14054         MMPLAYER_FLEAVE();
14055
14056         return MM_ERROR_NONE;
14057 }
14058
14059 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
14060 {
14061         int result = MM_ERROR_NONE;
14062         GstPad *peer = NULL, *pad = NULL;
14063         GstElement *Element = NULL;
14064         MMPlayerGstElement* mainbin = NULL;
14065         mainbin = player->pipeline->mainbin;
14066
14067         #if 0
14068         if (!gst_pad_set_blocked(inpad, TRUE)) {
14069                 result = MM_ERROR_PLAYER_INTERNAL;
14070                 goto EXIT;
14071         }
14072         #endif
14073         gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14074                         NULL, NULL, NULL);
14075
14076         /*Getting pad connected to demuxer audio pad */
14077         peer = gst_pad_get_peer(inpad);
14078         /* Disconnecting Demuxer and its peer plugin [audio] */
14079         if (peer) {
14080                 if (!gst_pad_unlink(inpad, peer)) {
14081                         result = MM_ERROR_PLAYER_INTERNAL;
14082                         goto EXIT;
14083                 }
14084         } else {
14085                 result = MM_ERROR_PLAYER_INTERNAL;
14086                 goto EXIT;
14087         }
14088         /*Removing elements between Demuxer and audiobin*/
14089         while (peer != NULL) {
14090                 gchar *Element_name = NULL;
14091                 gchar *factory_name = NULL;
14092                 GList *elements = NULL;
14093                 GstElementFactory *factory = NULL;
14094                 /*Getting peer element*/
14095                 Element = gst_pad_get_parent_element(peer);
14096                 if (Element == NULL) {
14097                         gst_object_unref(peer);
14098                         result = MM_ERROR_PLAYER_INTERNAL;
14099                         break;
14100                 }
14101
14102                 Element_name = gst_element_get_name(Element);
14103                 factory = gst_element_get_factory(Element);
14104                 /*checking the element is audio bin*/
14105                 if (!strcmp(Element_name, "audiobin")) {
14106                         gst_object_unref(peer);
14107                         result = MM_ERROR_NONE;
14108                         g_free(Element_name);
14109                         break;
14110                 }
14111                 factory_name = GST_OBJECT_NAME(factory);
14112                 pad = gst_element_get_static_pad(Element, "src");
14113                 if (pad == NULL) {
14114                         result = MM_ERROR_PLAYER_INTERNAL;
14115                         g_free(Element_name);
14116                         break;
14117                 }
14118                 gst_object_unref(peer);
14119                 peer = gst_pad_get_peer(pad);
14120                 if (peer) {
14121                         if (!gst_pad_unlink(pad, peer)) {
14122                                 gst_object_unref(peer);
14123                                 gst_object_unref(pad);
14124                                 result = MM_ERROR_PLAYER_INTERNAL;
14125                                 g_free(Element_name);
14126                                 break;
14127                         }
14128                 }
14129                 elements = player->parsers;
14130                 /* Removing the element form the list*/
14131                 for (; elements; elements = g_list_next(elements)) {
14132                         Element_name = elements->data;
14133                         if (g_strrstr(Element_name, factory_name))
14134                                 player->parsers = g_list_remove(player->parsers, elements->data);
14135                 }
14136                 gst_element_set_state(Element, GST_STATE_NULL);
14137                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
14138                 gst_object_unref(pad);
14139                 if (Element == mainbin[MMPLAYER_M_Q1].gst)
14140                         mainbin[MMPLAYER_M_Q1].gst = NULL;
14141                 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
14142                         mainbin[MMPLAYER_M_Q2].gst = NULL;
14143                 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
14144                         mainbin[MMPLAYER_M_DEC1].gst = NULL;
14145                 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14146                         mainbin[MMPLAYER_M_DEC2].gst = NULL;
14147
14148                 gst_object_unref(Element);
14149         }
14150 EXIT:
14151         return result;
14152 }
14153
14154 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14155 {
14156         MMPlayerGstElement* mainbin = NULL;
14157         MMPlayerGstElement* textbin = NULL;
14158         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14159         GstState current_state = GST_STATE_VOID_PENDING;
14160         GstState element_state = GST_STATE_VOID_PENDING;
14161         GstState element_pending_state = GST_STATE_VOID_PENDING;
14162         gint64 time = 0;
14163         GstEvent *event = NULL;
14164         int result = MM_ERROR_NONE;
14165
14166         GstClock *curr_clock = NULL;
14167         GstClockTime base_time, start_time, curr_time;
14168
14169
14170         MMPLAYER_FENTER();
14171
14172         /* check player handle */
14173         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14174
14175         if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14176                 LOGE("Pipeline is not in proper state\n");
14177                 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14178                 goto EXIT;
14179         }
14180
14181         mainbin = player->pipeline->mainbin;
14182         textbin = player->pipeline->textbin;
14183
14184         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14185
14186         // sync clock with current pipeline
14187         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14188         curr_time = gst_clock_get_time(curr_clock);
14189
14190         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14191         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14192
14193         LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14194                 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14195
14196         if (current_state > GST_STATE_READY) {
14197                 // sync state with current pipeline
14198                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14199                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14200                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14201
14202                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14203                 if (GST_STATE_CHANGE_FAILURE == ret)
14204                         LOGE("fail to state change.\n");
14205         }
14206
14207         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14208         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14209
14210         if (curr_clock) {
14211                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14212                 gst_object_unref(curr_clock);
14213         }
14214
14215         // seek to current position
14216         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14217                 result = MM_ERROR_PLAYER_INVALID_STATE;
14218                 LOGE("gst_element_query_position failed, invalid state\n");
14219                 goto EXIT;
14220         }
14221
14222         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14223         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);
14224         if (event) {
14225                 __gst_send_event_to_sink(player, event);
14226         } else {
14227                 result = MM_ERROR_PLAYER_INTERNAL;
14228                 LOGE("gst_event_new_seek failed\n");
14229                 goto EXIT;
14230         }
14231
14232         // sync state with current pipeline
14233         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14234         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14235         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14236
14237 EXIT:
14238         return result;
14239 }
14240
14241 static int
14242 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14243 {
14244         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14245         GstState current_state = GST_STATE_VOID_PENDING;
14246
14247         MMHandleType attrs = 0;
14248         MMPlayerGstElement* mainbin = NULL;
14249         MMPlayerGstElement* textbin = NULL;
14250
14251         gchar* subtitle_uri = NULL;
14252         int result = MM_ERROR_NONE;
14253         const gchar *charset = NULL;
14254
14255         MMPLAYER_FENTER();
14256
14257         /* check player handle */
14258         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14259         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14260
14261         if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14262                 result = MM_ERROR_PLAYER_INVALID_STATE;
14263                 LOGE("Pipeline is not in proper state\n");
14264                 goto EXIT;
14265         }
14266
14267         mainbin = player->pipeline->mainbin;
14268         textbin = player->pipeline->textbin;
14269
14270         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14271         if (current_state < GST_STATE_READY) {
14272                 result = MM_ERROR_PLAYER_INVALID_STATE;
14273                 LOGE("Pipeline is not in proper state\n");
14274                 goto EXIT;
14275         }
14276
14277         attrs = MMPLAYER_GET_ATTRS(player);
14278         if (!attrs) {
14279                 LOGE("cannot get content attribute\n");
14280                 result = MM_ERROR_PLAYER_INTERNAL;
14281                 goto EXIT;
14282         }
14283
14284         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14285         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14286                 LOGE("subtitle uri is not proper filepath\n");
14287                 result = MM_ERROR_PLAYER_INVALID_URI;
14288                 goto EXIT;
14289         }
14290
14291         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14292         LOGD("new subtitle file path is [%s]\n", filepath);
14293
14294         if (!strcmp(filepath, subtitle_uri)) {
14295                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14296                 goto EXIT;
14297         } else {
14298                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14299                 if (mmf_attrs_commit(player->attrs)) {
14300                         LOGE("failed to commit.\n");
14301                         goto EXIT;
14302                 }
14303         }
14304
14305         //gst_pad_set_blocked_async(src-srcpad, TRUE)
14306
14307         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14308         if (ret != GST_STATE_CHANGE_SUCCESS) {
14309                 LOGE("failed to change state of textbin to READY");
14310                 result = MM_ERROR_PLAYER_INTERNAL;
14311                 goto EXIT;
14312         }
14313
14314         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14315         if (ret != GST_STATE_CHANGE_SUCCESS) {
14316                 LOGE("failed to change state of subparse to READY");
14317                 result = MM_ERROR_PLAYER_INTERNAL;
14318                 goto EXIT;
14319         }
14320
14321         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14322         if (ret != GST_STATE_CHANGE_SUCCESS) {
14323                 LOGE("failed to change state of filesrc to READY");
14324                 result = MM_ERROR_PLAYER_INTERNAL;
14325                 goto EXIT;
14326         }
14327
14328         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14329
14330         charset = util_get_charset(filepath);
14331         if (charset) {
14332                 LOGD("detected charset is %s\n", charset);
14333                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14334         }
14335
14336         result = _mmplayer_sync_subtitle_pipeline(player);
14337
14338 EXIT:
14339         MMPLAYER_FLEAVE();
14340         return result;
14341 }
14342
14343 /* API to switch between external subtitles */
14344 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14345 {
14346         int result = MM_ERROR_NONE;
14347         mm_player_t* player = (mm_player_t*)hplayer;
14348
14349         MMPLAYER_FENTER();
14350
14351         /* check player handle */
14352         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14353
14354         if (!player->pipeline) {
14355                 // IDLE state
14356                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14357                 if (mmf_attrs_commit(player->attrs)) {
14358                         LOGE("failed to commit.\n");
14359                         result = MM_ERROR_PLAYER_INTERNAL;
14360                 }
14361         } else {
14362                 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14363                 if (filepath == NULL)
14364                         return MM_ERROR_COMMON_INVALID_ARGUMENT;
14365
14366                 if (!__mmplayer_check_subtitle(player)) {
14367                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14368                         if (mmf_attrs_commit(player->attrs)) {
14369                                 LOGE("failed to commit.\n");
14370                                 result = MM_ERROR_PLAYER_INTERNAL;
14371                         }
14372
14373                         if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14374                                 LOGE("fail to create subtitle src\n");
14375
14376                         result = _mmplayer_sync_subtitle_pipeline(player);
14377                 } else
14378                         result = __mmplayer_change_external_subtitle_language(player, filepath);
14379
14380                 player->is_external_subtitle_added_now = TRUE;
14381         }
14382
14383         MMPLAYER_FLEAVE();
14384         return result;
14385 }
14386
14387 static int
14388 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14389 {
14390         int result = MM_ERROR_NONE;
14391         gchar* change_pad_name = NULL;
14392         GstPad* sinkpad = NULL;
14393         MMPlayerGstElement* mainbin = NULL;
14394         enum MainElementID elemId = MMPLAYER_M_NUM;
14395         GstCaps* caps = NULL;
14396         gint total_track_num = 0;
14397
14398         MMPLAYER_FENTER();
14399
14400         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14401                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
14402
14403         LOGD("Change Track(%d) to %d\n", type, index);
14404
14405         mainbin = player->pipeline->mainbin;
14406
14407         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14408                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14409         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14410                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14411         } else {
14412                 /* Changing Video Track is not supported. */
14413                 LOGE("Track Type Error\n");
14414                 goto EXIT;
14415         }
14416
14417         if (mainbin[elemId].gst == NULL) {
14418                 result = MM_ERROR_PLAYER_NO_OP;
14419                 LOGD("Req track doesn't exist\n");
14420                 goto EXIT;
14421         }
14422
14423         total_track_num = player->selector[type].total_track_num;
14424         if (total_track_num <= 0) {
14425                 result = MM_ERROR_PLAYER_NO_OP;
14426                 LOGD("Language list is not available \n");
14427                 goto EXIT;
14428         }
14429
14430         if ((index < 0) || (index >= total_track_num)) {
14431                 result = MM_ERROR_INVALID_ARGUMENT;
14432                 LOGD("Not a proper index : %d \n", index);
14433                 goto EXIT;
14434         }
14435
14436         /*To get the new pad from the selector*/
14437         change_pad_name = g_strdup_printf("sink_%u", index);
14438         if (change_pad_name == NULL) {
14439                 result = MM_ERROR_PLAYER_INTERNAL;
14440                 LOGD("Pad does not exists\n");
14441                 goto EXIT;
14442         }
14443
14444         LOGD("new active pad name: %s\n", change_pad_name);
14445
14446         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14447         if (sinkpad == NULL) {
14448                 LOGD("sinkpad is NULL");
14449                 result = MM_ERROR_PLAYER_INTERNAL;
14450                 goto EXIT;
14451         }
14452
14453         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14454         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14455
14456         caps = gst_pad_get_current_caps(sinkpad);
14457         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14458
14459         if (sinkpad)
14460                 gst_object_unref(sinkpad);
14461
14462         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14463                 __mmplayer_set_audio_attrs(player, caps);
14464
14465 EXIT:
14466
14467         MMPLAYER_FREEIF(change_pad_name);
14468         return result;
14469 }
14470
14471 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14472 {
14473         int result = MM_ERROR_NONE;
14474         mm_player_t* player = NULL;
14475         MMPlayerGstElement* mainbin = NULL;
14476
14477         gint current_active_index = 0;
14478
14479         GstState current_state = GST_STATE_VOID_PENDING;
14480         GstEvent* event = NULL;
14481         gint64 time = 0;
14482
14483         MMPLAYER_FENTER();
14484
14485         player = (mm_player_t*)hplayer;
14486         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14487
14488         if (!player->pipeline) {
14489                 LOGE("Track %d pre setting -> %d\n", type, index);
14490
14491                 player->selector[type].active_pad_index = index;
14492                 goto EXIT;
14493         }
14494
14495         mainbin = player->pipeline->mainbin;
14496
14497         current_active_index = player->selector[type].active_pad_index;
14498
14499         /*If index is same as running index no need to change the pad*/
14500         if (current_active_index == index)
14501                 goto EXIT;
14502
14503         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14504                 result = MM_ERROR_PLAYER_INVALID_STATE;
14505                 goto EXIT;
14506         }
14507
14508         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14509         if (current_state < GST_STATE_PAUSED) {
14510                 result = MM_ERROR_PLAYER_INVALID_STATE;
14511                 LOGW("Pipeline not in porper state\n");
14512                 goto EXIT;
14513         }
14514
14515         result = __mmplayer_change_selector_pad(player, type, index);
14516         if (result != MM_ERROR_NONE) {
14517                 LOGE("change selector pad error\n");
14518                 goto EXIT;
14519         }
14520
14521         player->selector[type].active_pad_index = index;
14522
14523         if (current_state == GST_STATE_PLAYING) {
14524                 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);
14525                 if (event) {
14526                         __gst_send_event_to_sink(player, event);
14527                 } else {
14528                         result = MM_ERROR_PLAYER_INTERNAL;
14529                         goto EXIT;
14530                 }
14531         }
14532
14533 EXIT:
14534         return result;
14535 }
14536
14537 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14538 {
14539         mm_player_t* player = (mm_player_t*) hplayer;
14540
14541         MMPLAYER_FENTER();
14542
14543         /* check player handle */
14544         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14545
14546         *silent = player->set_mode.subtitle_off;
14547
14548         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14549
14550         MMPLAYER_FLEAVE();
14551
14552         return MM_ERROR_NONE;
14553 }
14554
14555 gboolean
14556 __is_ms_buff_src(mm_player_t* player)
14557 {
14558         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14559
14560         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14561 }
14562
14563 gboolean
14564 __has_suffix(mm_player_t* player, const gchar* suffix)
14565 {
14566         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14567         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14568
14569         gboolean ret = FALSE;
14570         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14571         gchar* t_suffix = g_ascii_strdown(suffix, -1);
14572
14573         if (g_str_has_suffix(player->profile.uri, suffix))
14574                 ret = TRUE;
14575
14576         MMPLAYER_FREEIF(t_url);
14577         MMPLAYER_FREEIF(t_suffix);
14578
14579         return ret;
14580 }
14581
14582 int
14583 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14584 {
14585         mm_player_t* player = (mm_player_t*) hplayer;
14586
14587         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14588
14589         MMPLAYER_VIDEO_SINK_CHECK(player);
14590
14591         LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14592
14593         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14594
14595         return MM_ERROR_NONE;
14596 }
14597 int
14598 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14599 {
14600
14601         mm_player_t* player = (mm_player_t*) hplayer;
14602         float _level = 0.0;
14603         int _x = 0;
14604         int _y = 0;
14605
14606         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14607
14608         MMPLAYER_VIDEO_SINK_CHECK(player);
14609
14610         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14611
14612         LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14613
14614         *level = _level;
14615         *x = _x;
14616         *y = _y;
14617
14618         return MM_ERROR_NONE;
14619 }
14620
14621 int
14622 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14623 {
14624         mm_player_t* player = (mm_player_t*) hplayer;
14625
14626         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14627
14628         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14629                 MMPLAYER_PRINT_STATE(player);
14630                 LOGE("wrong-state : can't set the download mode to parse");
14631                 return MM_ERROR_PLAYER_INVALID_STATE;
14632         }
14633
14634         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14635         player->video_hub_download_mode = mode;
14636
14637         return MM_ERROR_NONE;
14638 }
14639
14640 int
14641 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14642 {
14643         mm_player_t* player = (mm_player_t*) hplayer;
14644
14645         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14646
14647         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14648         player->sync_handler = enable;
14649
14650         return MM_ERROR_NONE;
14651 }
14652
14653 int
14654 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14655                                         long long clock,
14656                                         long long clock_delta,
14657                                         long long video_time,
14658                                         long long media_clock,
14659                                         long long audio_time)
14660 {
14661         mm_player_t* player = (mm_player_t*) hplayer;
14662         MMPlayerGstElement* mainbin = NULL;
14663         GstClockTime start_time_audio = 0, start_time_video = 0;
14664         GstClockTimeDiff base_time = 0, new_base_time = 0;
14665         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14666         gint64 api_delta = 0;
14667         gint64 position = 0, position_delta = 0;
14668         gint64 adj_base_time = 0;
14669         GstClock *curr_clock = NULL;
14670         GstClockTime curr_time = 0;
14671         gboolean query_ret = TRUE;
14672         int result = MM_ERROR_NONE;
14673
14674         MMPLAYER_FENTER();
14675
14676         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14677         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14678         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14679
14680         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14681
14682         if ((video_time < 0) || (player->doing_seek)) {
14683                 LOGD("skip setting master clock.  %lld", video_time);
14684                 goto EXIT;
14685         }
14686
14687         mainbin = player->pipeline->mainbin;
14688
14689         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14690         curr_time = gst_clock_get_time(curr_clock);
14691
14692         current_state = MMPLAYER_CURRENT_STATE(player);
14693
14694         if (current_state == MM_PLAYER_STATE_PLAYING)
14695                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14696
14697         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14698                 (!query_ret)) {
14699                 position = player->last_position;
14700                 LOGD("query fail. %lld", position);
14701         }
14702
14703         clock *= GST_USECOND;
14704         clock_delta *= GST_USECOND;
14705
14706         api_delta = clock - curr_time;
14707         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14708                 player->video_share_api_delta = api_delta;
14709         else
14710                 clock_delta += (api_delta - player->video_share_api_delta);
14711
14712         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14713                 player->video_share_clock_delta = (gint64)clock_delta;
14714
14715                 position_delta = (position/GST_USECOND) - video_time;
14716                 position_delta *= GST_USECOND;
14717
14718                 adj_base_time = position_delta;
14719                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14720
14721         } else {
14722                 gint64 new_play_time = 0;
14723                 gint64 network_delay = 0;
14724
14725                 video_time *= GST_USECOND;
14726
14727                 network_delay = clock_delta - player->video_share_clock_delta;
14728                 new_play_time = video_time + network_delay;
14729
14730                 adj_base_time = position - new_play_time;
14731
14732                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14733                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14734         }
14735
14736         /* Adjust Current Stream Time with base_time of sink
14737          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14738          * 2. Set new base time
14739          *    if adj_base_time is positive value, the stream time will be decreased.
14740          * 3. If seek event is occurred, the start time will be reset. */
14741         if ((player->pipeline->audiobin) &&
14742                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14743                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14744
14745                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14746                         LOGD("audio sink : gst_element_set_start_time -> NONE");
14747                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14748                 }
14749
14750                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14751         }
14752
14753         if ((player->pipeline->videobin) &&
14754                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14755                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14756
14757                 if (start_time_video != GST_CLOCK_TIME_NONE) {
14758                         LOGD("video sink : gst_element_set_start_time -> NONE");
14759                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14760                 }
14761
14762                 // if videobin exist, get base_time from videobin.
14763                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14764         }
14765
14766         new_base_time = base_time + adj_base_time;
14767
14768         if ((player->pipeline->audiobin) &&
14769                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14770                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14771
14772         if ((player->pipeline->videobin) &&
14773                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14774                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14775
14776 EXIT:
14777         MMPLAYER_FLEAVE();
14778
14779         return result;
14780 }
14781
14782 int
14783 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14784                                         long long *video_time,
14785                                         long long *media_clock,
14786                                         long long *audio_time)
14787 {
14788         mm_player_t* player = (mm_player_t*) hplayer;
14789         MMPlayerGstElement* mainbin = NULL;
14790         GstClock *curr_clock = NULL;
14791         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14792         gint64 position = 0;
14793         gboolean query_ret = TRUE;
14794
14795         MMPLAYER_FENTER();
14796
14797         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14798         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14799         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14800
14801         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14802         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14803         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14804
14805         mainbin = player->pipeline->mainbin;
14806
14807         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14808
14809         current_state = MMPLAYER_CURRENT_STATE(player);
14810
14811         if (current_state != MM_PLAYER_STATE_PAUSED)
14812                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14813
14814         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14815                 (!query_ret))
14816                 position = player->last_position;
14817
14818         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14819
14820         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14821
14822         if (curr_clock)
14823                 gst_object_unref(curr_clock);
14824
14825         MMPLAYER_FLEAVE();
14826
14827         return MM_ERROR_NONE;
14828 }
14829
14830 int
14831 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14832 {
14833         mm_player_t* player = (mm_player_t*) hplayer;
14834         int org_angle = 0;
14835
14836         MMPLAYER_FENTER();
14837
14838         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14839         MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14840
14841         if (player->v_stream_caps) {
14842                 GstStructure *str = NULL;
14843
14844                 str = gst_caps_get_structure(player->v_stream_caps, 0);
14845                 if (!gst_structure_get_int(str, "orientation", &org_angle))
14846                         LOGD("missing 'orientation' field in video caps");
14847         }
14848
14849         LOGD("orientation: %d", org_angle);
14850         *angle = org_angle;
14851
14852         MMPLAYER_FLEAVE();
14853         return MM_ERROR_NONE;
14854 }
14855
14856 static gboolean
14857 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14858 {
14859         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14860         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14861
14862         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14863         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14864
14865         int idx = 0;
14866
14867         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14868                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14869                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14870                         mm_player_dump_t *dump_s;
14871                         dump_s = g_malloc(sizeof(mm_player_dump_t));
14872
14873                         if (dump_s == NULL) {
14874                                 LOGE("malloc fail");
14875                                 return FALSE;
14876                         }
14877
14878                         dump_s->dump_element_file = NULL;
14879                         dump_s->dump_pad = NULL;
14880                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14881
14882                         if (dump_s->dump_pad) {
14883                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14884                                 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]);
14885                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14886                                 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);
14887                                 /* add list for removed buffer probe and close FILE */
14888                                 player->dump_list = g_list_append(player->dump_list, dump_s);
14889                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
14890                                 return TRUE;
14891                         } else {
14892                                 g_free(dump_s);
14893                                 dump_s = NULL;
14894                                 LOGE("failed to get %s sink pad added", factory_name);
14895                         }
14896
14897
14898                 }
14899         }
14900         return FALSE;
14901 }
14902
14903 static GstPadProbeReturn
14904 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
14905 {
14906         FILE *dump_data = (FILE *) u_data;
14907 //      int written = 0;
14908         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14909         GstMapInfo probe_info = GST_MAP_INFO_INIT;
14910
14911         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14912
14913         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14914
14915 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14916
14917         fwrite(probe_info.data, 1, probe_info.size , dump_data);
14918
14919         return GST_PAD_PROBE_OK;
14920 }
14921
14922 static void
14923 __mmplayer_release_dump_list(GList *dump_list)
14924 {
14925         if (dump_list) {
14926                 GList *d_list = dump_list;
14927                 for (; d_list; d_list = g_list_next(d_list)) {
14928                         mm_player_dump_t *dump_s = d_list->data;
14929                         if (dump_s->dump_pad) {
14930                                 if (dump_s->probe_handle_id)
14931                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14932                         }
14933                         if (dump_s->dump_element_file) {
14934                                 fclose(dump_s->dump_element_file);
14935                                 dump_s->dump_element_file = NULL;
14936                         }
14937                         MMPLAYER_FREEIF(dump_s);
14938                 }
14939                 g_list_free(dump_list);
14940                 dump_list = NULL;
14941         }
14942 }
14943
14944 int
14945 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14946 {
14947         mm_player_t* player = (mm_player_t*) hplayer;
14948
14949         MMPLAYER_FENTER();
14950
14951         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14952         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14953
14954         *exist = player->has_closed_caption;
14955
14956         MMPLAYER_FLEAVE();
14957
14958         return MM_ERROR_NONE;
14959 }
14960
14961 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14962 {
14963         void * ret = NULL
14964         MMPLAYER_FENTER();
14965         /* increase ref count of gst buffer */
14966         if (buffer)
14967                 ret = gst_buffer_ref((GstBuffer *)buffer);
14968
14969         MMPLAYER_FLEAVE();
14970         return ret;
14971 }
14972
14973 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14974 {
14975         MMPLAYER_FENTER();
14976         if (buffer) {
14977                 gst_buffer_unref((GstBuffer *)buffer);
14978                 buffer = NULL;
14979         }
14980         MMPLAYER_FLEAVE();
14981 }
14982
14983 void
14984 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14985 {
14986         mm_player_t *player  = (mm_player_t*)user_data;
14987         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14988         guint64 current_level_bytes = 0;
14989
14990         MMPLAYER_RETURN_IF_FAIL(player);
14991
14992         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14993
14994         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14995         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14996
14997         if (player->media_stream_buffer_status_cb[type])
14998                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14999         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15000
15001 }
15002
15003 void
15004 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15005 {
15006         mm_player_t *player  = (mm_player_t*)user_data;
15007         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15008         guint64 current_level_bytes = 0;
15009
15010         MMPLAYER_RETURN_IF_FAIL(player);
15011
15012         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15013
15014         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15015
15016         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15017         if (player->media_stream_buffer_status_cb[type])
15018                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15019         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15020 }
15021
15022 void
15023 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15024 {
15025         mm_player_t *player  = (mm_player_t*)user_data;
15026         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15027         guint64 current_level_bytes = 0;
15028
15029         MMPLAYER_RETURN_IF_FAIL(player);
15030
15031         LOGI("app-src: feed subtitle\n");
15032
15033         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15034
15035         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15036         if (player->media_stream_buffer_status_cb[type])
15037                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15038
15039         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15040 }
15041
15042 void
15043 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15044 {
15045         mm_player_t *player  = (mm_player_t*)user_data;
15046         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15047         guint64 current_level_bytes = 0;
15048
15049         MMPLAYER_RETURN_IF_FAIL(player);
15050
15051         LOGI("app-src: audio buffer is full.\n");
15052
15053         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15054
15055         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15056
15057         if (player->media_stream_buffer_status_cb[type])
15058                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15059
15060         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15061 }
15062
15063 void
15064 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15065 {
15066         mm_player_t *player  = (mm_player_t*)user_data;
15067         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15068         guint64 current_level_bytes = 0;
15069
15070         MMPLAYER_RETURN_IF_FAIL(player);
15071
15072         LOGI("app-src: video buffer is full.\n");
15073
15074         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15075
15076         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15077         if (player->media_stream_buffer_status_cb[type])
15078                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15079
15080         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15081 }
15082
15083 gboolean
15084 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15085 {
15086         mm_player_t *player  = (mm_player_t*)user_data;
15087         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15088
15089         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15090
15091         LOGD("app-src: seek audio data %llu\n", position);
15092         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15093
15094         if (player->media_stream_seek_data_cb[type])
15095                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15096         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15097
15098         return TRUE;
15099 }
15100
15101 gboolean
15102 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15103 {
15104         mm_player_t *player  = (mm_player_t*)user_data;
15105         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15106
15107         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15108
15109         LOGD("app-src: seek video data %llu\n", position);
15110         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15111         if (player->media_stream_seek_data_cb[type])
15112                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15113         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15114
15115         return TRUE;
15116 }
15117
15118 gboolean
15119 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15120 {
15121         mm_player_t *player  = (mm_player_t*)user_data;
15122         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15123
15124         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15125
15126         LOGD("app-src: seek subtitle data\n");
15127         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15128
15129         if (player->media_stream_seek_data_cb[type])
15130                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15131         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15132
15133         return TRUE;
15134 }
15135
15136 int
15137 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15138 {
15139         mm_player_t* player = (mm_player_t*) hplayer;
15140
15141         MMPLAYER_FENTER();
15142
15143         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15144
15145         player->pcm_samplerate = samplerate;
15146         player->pcm_channel = channel;
15147
15148         MMPLAYER_FLEAVE();
15149         return MM_ERROR_NONE;
15150 }
15151
15152 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15153 {
15154         mm_player_t* player = (mm_player_t*) hplayer;
15155
15156         MMPLAYER_FENTER();
15157
15158         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15159         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15160
15161         if (MMPLAYER_IS_STREAMING(player))
15162                 *timeout = player->ini.live_state_change_timeout;
15163         else
15164                 *timeout = player->ini.localplayback_state_change_timeout;
15165
15166         LOGD("timeout = %d\n", *timeout);
15167
15168         MMPLAYER_FLEAVE();
15169         return MM_ERROR_NONE;
15170 }
15171
15172 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15173 {
15174         mm_player_t* player = (mm_player_t*) hplayer;
15175
15176         MMPLAYER_FENTER();
15177
15178         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15179         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15180
15181         *num = player->video_num_buffers;
15182         *extra_num = player->video_extra_num_buffers;
15183
15184         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15185
15186         MMPLAYER_FLEAVE();
15187         return MM_ERROR_NONE;
15188 }
15189