Add new parameter to focus changed cb
[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 /*===========================================================================================
55 |                                                                                                                                                                                       |
56 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
57 |                                                                                                                                                                                       |
58 ========================================================================================== */
59
60 /*---------------------------------------------------------------------------
61 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
62 ---------------------------------------------------------------------------*/
63
64 /*---------------------------------------------------------------------------
65 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
66 ---------------------------------------------------------------------------*/
67
68 /*---------------------------------------------------------------------------
69 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
70 ---------------------------------------------------------------------------*/
71
72 /*---------------------------------------------------------------------------
73 |    LOCAL #defines:                                                                                                            |
74 ---------------------------------------------------------------------------*/
75 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
76 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
77
78 #define MM_VOLUME_FACTOR_DEFAULT                1.0
79 #define MM_VOLUME_FACTOR_MIN                    0
80 #define MM_VOLUME_FACTOR_MAX                    1.0
81
82 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  700000 // 700 msec
83
84 #define MM_PLAYER_MPEG_VNAME                    "mpegversion"
85 #define MM_PLAYER_DIVX_VNAME                    "divxversion"
86 #define MM_PLAYER_WMV_VNAME                             "wmvversion"
87 #define MM_PLAYER_WMA_VNAME                             "wmaversion"
88
89 #define DEFAULT_PLAYBACK_RATE                   1.0
90 #define PLAYBACK_RATE_EX_AUDIO_MIN              0.5
91 #define PLAYBACK_RATE_EX_AUDIO_MAX              2.0
92 #define PLAYBACK_RATE_EX_VIDEO_MIN              0.5
93 #define PLAYBACK_RATE_EX_VIDEO_MAX              1.5
94 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
95
96 #define GST_QUEUE_DEFAULT_TIME                  4
97 #define GST_QUEUE_HLS_TIME                              8
98
99 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
100         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
101         (player->ini.http_use_file_buffer) && \
102         (player->http_file_buffering_path) && \
103         (strlen(player->http_file_buffering_path) > 0))
104 #define MM_PLAYER_NAME  "mmplayer"
105
106 #define PLAYER_DISPLAY_MODE_DST_ROI             5
107
108 /*---------------------------------------------------------------------------
109 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
110 ---------------------------------------------------------------------------*/
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
126 ---------------------------------------------------------------------------*/
127 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
128 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
129 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
130 static int              __mmplayer_gst_create_subtitle_src(mm_player_t* player);
131 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
132 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
134
135 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
136 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
137 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
138 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
139 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
140 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
141 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
142 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
143 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
144 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
145 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
146 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
147 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
148
149 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
150 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
151 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
155 //static void   __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
156
157 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
158 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
159 static void             __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
160
161 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
162 //static void    __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
164 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
165 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
166
167
168 static void             __mmplayer_init_factories(mm_player_t* player);
169 static void             __mmplayer_release_factories(mm_player_t* player);
170 static void             __mmplayer_release_misc(mm_player_t* player);
171 static void             __mmplayer_release_misc_post(mm_player_t* player);
172 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
173 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
174 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
175
176 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
177 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
178
179 int             __mmplayer_switch_audio_sink(mm_player_t* player);
180 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
181 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
182 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
183 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
184 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
185 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
186
187 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
188 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
189 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
190 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
191 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
192 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
193 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
194 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
195 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
196 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
197 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
198 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
199 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
200 static gpointer __mmplayer_next_play_thread(gpointer data);
201 static gpointer __mmplayer_repeat_thread(gpointer data);
202 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
203
204
205 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
206 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
207 static void __mmplayer_release_dump_list(GList *dump_list);
208
209 static int              __gst_realize(mm_player_t* player);
210 static int              __gst_unrealize(mm_player_t* player);
211 static int              __gst_start(mm_player_t* player);
212 static int              __gst_stop(mm_player_t* player);
213 static int              __gst_pause(mm_player_t* player, gboolean async);
214 static int              __gst_resume(mm_player_t* player, gboolean async);
215 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
216                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
217                                         gint64 cur, GstSeekType stop_type, gint64 stop);
218 static int __gst_pending_seek(mm_player_t* player);
219
220 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
221 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
222 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
223 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
224 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
225
226 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
227
228 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
229 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
230
231 /*fadeout */
232 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
233 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
234
235 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
236 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
237
238 /* util */
239 static gboolean __is_ms_buff_src(mm_player_t* player);
240 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
241
242 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
243 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
244 static int __mmplayer_start_streaming_ext(mm_player_t *player);
245 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
246 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
247
248 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
249 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
250 static void __mmplayer_check_pipeline(mm_player_t* player);
251 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
252 static void __mmplayer_deactivate_old_path(mm_player_t *player);
253 #if 0 // We'll need this in future.
254 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
255 #endif
256
257 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
258 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
259
260 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
261 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
262 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
263 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
264 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
265 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
266 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
267 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
268 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
269 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
270 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
271 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
272 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
273
274 /*===========================================================================================
275 |                                                                                                                                                                                       |
276 |  FUNCTION DEFINITIONS                                                                                                                                         |
277 |                                                                                                                                                                                       |
278 ========================================================================================== */
279
280 #if 0 //debug
281 static void
282 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
283 {
284         gint i, count;
285
286         count = gst_tag_list_get_tag_size(list, tag);
287
288         LOGD("count = %d", count);
289
290         for (i = 0; i < count; i++) {
291                 gchar *str;
292
293                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
294                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
295                                 g_assert_not_reached();
296                 } else
297                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
298
299                 if (i == 0)
300                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
301                 else
302                         g_print("                 : %s\n", str);
303
304                 g_free(str);
305         }
306 }
307 #endif
308
309 /* This function should be called after the pipeline goes PAUSED or higher
310 state. */
311 gboolean
312 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
313 {
314         static gboolean has_duration = FALSE;
315         static gboolean has_video_attrs = FALSE;
316         static gboolean has_audio_attrs = FALSE;
317         static gboolean has_bitrate = FALSE;
318         gboolean missing_only = FALSE;
319         gboolean all = FALSE;
320         gint64 dur_nsec = 0;
321         GstStructure* p = NULL;
322         MMHandleType attrs = 0;
323         gchar *path = NULL;
324         gint stream_service_type = STREAMING_SERVICE_NONE;
325         struct stat sb;
326
327         MMPLAYER_FENTER();
328
329         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
330
331         /* check player state here */
332         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
333                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
334                 /* give warning now only */
335                 LOGW("be careful. content attributes may not available in this state ");
336         }
337
338         /* get content attribute first */
339         attrs = MMPLAYER_GET_ATTRS(player);
340         if (!attrs) {
341                 LOGE("cannot get content attribute");
342                 return FALSE;
343         }
344
345         /* get update flag */
346
347         if (flag & ATTR_MISSING_ONLY) {
348                 missing_only = TRUE;
349                 LOGD("updating missed attr only");
350         }
351
352         if (flag & ATTR_ALL) {
353                 all = TRUE;
354                 has_duration = FALSE;
355                 has_video_attrs = FALSE;
356                 has_audio_attrs = FALSE;
357                 has_bitrate = FALSE;
358
359                 LOGD("updating all attrs");
360         }
361
362         if (missing_only && all) {
363                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
364                 missing_only = FALSE;
365         }
366
367         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
368                 LOGD("try to update duration");
369                 has_duration = FALSE;
370
371                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
372                         player->duration = dur_nsec;
373                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
374                 }
375
376                 /* try to get streaming service type */
377                 stream_service_type = __mmplayer_get_stream_service_type(player);
378                 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
379
380                 /* check duration is OK */
381                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
382                         /* FIXIT : find another way to get duration here. */
383                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
384                 } else {
385                         /*update duration */
386                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
387                         has_duration = TRUE;
388                 }
389         }
390
391         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
392                 /* update audio params
393                 NOTE : We need original audio params and it can be only obtained from src pad of audio
394                 decoder. Below code only valid when we are not using 'resampler' just before
395                 'audioconverter'. */
396
397                 LOGD("try to update audio attrs");
398                 has_audio_attrs = FALSE;
399
400                 if (player->pipeline->audiobin &&
401                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
402                         GstCaps *caps_a = NULL;
403                         GstPad* pad = NULL;
404                         gint samplerate = 0, channels = 0;
405
406                         pad = gst_element_get_static_pad(
407                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
408
409                         if (pad) {
410                                 caps_a = gst_pad_get_current_caps(pad);
411
412                                 if (caps_a) {
413                                         p = gst_caps_get_structure(caps_a, 0);
414
415                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
416
417                                         gst_structure_get_int(p, "rate", &samplerate);
418                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
419
420                                         gst_structure_get_int(p, "channels", &channels);
421                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
422
423                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
424
425                                         gst_caps_unref(caps_a);
426                                         caps_a = NULL;
427
428                                         has_audio_attrs = TRUE;
429                                 } else
430                                         LOGW("not ready to get audio caps");
431
432                                 gst_object_unref(pad);
433                         } else
434                                 LOGW("failed to get pad from audiosink");
435                 }
436         }
437
438         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
439                 LOGD("try to update video attrs");
440                 has_video_attrs = FALSE;
441
442                 if (player->pipeline->videobin &&
443                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
444                         GstCaps *caps_v = NULL;
445                         GstPad* pad = NULL;
446                         gint tmpNu, tmpDe;
447                         gint width, height;
448
449                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
450                         if (pad) {
451                                 caps_v = gst_pad_get_current_caps(pad);
452
453                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
454                                 if (!caps_v && player->v_stream_caps) {
455                                         caps_v = player->v_stream_caps;
456                                         gst_caps_ref(caps_v);
457                                 }
458
459                                 if (caps_v) {
460                                         p = gst_caps_get_structure(caps_v, 0);
461                                         gst_structure_get_int(p, "width", &width);
462                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
463
464                                         gst_structure_get_int(p, "height", &height);
465                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
466
467                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
468
469                                         SECURE_LOGD("width : %d     height : %d", width, height);
470
471                                         gst_caps_unref(caps_v);
472                                         caps_v = NULL;
473
474                                         if (tmpDe > 0) {
475                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
476                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
477                                         }
478
479                                         has_video_attrs = TRUE;
480                                 } else
481                                         LOGD("no negitiated caps from videosink");
482                                 gst_object_unref(pad);
483                                 pad = NULL;
484                         } else
485                                 LOGD("no videosink sink pad");
486                 }
487         }
488
489
490         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
491                 has_bitrate = FALSE;
492
493                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
494                 if (player->duration) {
495                         guint64 data_size = 0;
496
497                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
498                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
499
500                                 if (stat(path, &sb) == 0)
501                                         data_size = (guint64)sb.st_size;
502                         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
503                                 data_size = player->http_content_size;
504                         LOGD("try to update bitrate : data_size = %lld", data_size);
505
506                         if (data_size) {
507                                 guint64 bitrate = 0;
508                                 guint64 msec_dur = 0;
509
510                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
511                                 bitrate = data_size * 8 * 1000 / msec_dur;
512                                 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
513                                 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
514
515                                 has_bitrate = TRUE;
516                         }
517
518                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
519                                 if (player->total_bitrate) {
520                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
521                                         has_bitrate = TRUE;
522                                 }
523                         }
524                 }
525         }
526
527         /* validate all */
528         if (mmf_attrs_commit(attrs)) {
529                 LOGE("failed to update attributes\n");
530                 return FALSE;
531         }
532
533         MMPLAYER_FLEAVE();
534
535         return TRUE;
536 }
537
538 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
539 {
540         gint streaming_type = STREAMING_SERVICE_NONE;
541
542         MMPLAYER_FENTER();
543
544         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
545                         player->pipeline &&
546                         player->pipeline->mainbin &&
547                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
548                         FALSE);
549
550         /* streaming service type if streaming */
551         if (!MMPLAYER_IS_STREAMING(player))
552                 return STREAMING_SERVICE_NONE;
553
554         if (MMPLAYER_IS_HTTP_STREAMING(player))
555                 streaming_type = (player->duration == 0) ?
556                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
557
558         switch (streaming_type) {
559         case STREAMING_SERVICE_LIVE:
560                 LOGD("it's live streaming");
561                 break;
562         case STREAMING_SERVICE_VOD:
563                 LOGD("it's vod streaming");
564                 break;
565         case STREAMING_SERVICE_NONE:
566                 LOGE("should not get here");
567                 break;
568         default:
569                 LOGE("should not get here");
570         }
571
572         player->streaming_type = streaming_type;
573         MMPLAYER_FLEAVE();
574
575         return streaming_type;
576 }
577
578
579 /* this function sets the player state and also report
580  * it to applicaton by calling callback function
581  */
582 int
583 __mmplayer_set_state(mm_player_t* player, int state) // @
584 {
585         MMMessageParamType msg = {0, };
586         int sound_result = MM_ERROR_NONE;
587         gboolean post_bos = FALSE;
588         gboolean interrupted_by_focus = FALSE;
589         gboolean interrupted_by_resource = FALSE;
590         int ret = MM_ERROR_NONE;
591
592         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
593
594         if (MMPLAYER_CURRENT_STATE(player) == state) {
595                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
596                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
597                 return ret;
598         }
599
600         /* update player states */
601         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
602         MMPLAYER_CURRENT_STATE(player) = state;
603
604         /* FIXIT : it's better to do like below code
605         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
606                         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
607         and add more code to handling PENDING_STATE.
608         */
609         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
610                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
611
612         /* print state */
613         MMPLAYER_PRINT_STATE(player);
614
615         /* do some FSM stuffs before posting new state to application  */
616         interrupted_by_focus = player->sound_focus.by_asm_cb;
617         interrupted_by_resource = player->resource_manager.by_rm_cb;
618
619         switch (MMPLAYER_CURRENT_STATE(player)) {
620         case MM_PLAYER_STATE_NULL:
621         case MM_PLAYER_STATE_READY:
622                 {
623                         if (player->cmd == MMPLAYER_COMMAND_STOP) {
624                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
625                                 if (sound_result != MM_ERROR_NONE) {
626                                         LOGE("failed to release sound focus\n");
627                                         return MM_ERROR_POLICY_INTERNAL;
628                                 }
629                         }
630                 }
631                 break;
632
633         case MM_PLAYER_STATE_PAUSED:
634                 {
635                          if (!player->sent_bos) {
636                                 int found = 0;
637                                 #define MMPLAYER_MAX_SOUND_PRIORITY     3
638
639                                 /* it's first time to update all content attrs. */
640                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
641                                 /* set max sound priority to keep own sound and not to mute other's one */
642                                 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
643                                 if (found) {
644                                         mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
645                                         if (found) {
646                                                 LOGD("set max audio priority");
647                                                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
648                                         }
649                                 }
650
651                          }
652
653                         /* add audio callback probe if condition is satisfied */
654                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
655                                 __mmplayer_configure_audio_callback(player);
656                                 /* FIXIT : handle return value */
657
658                         if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
659                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
660                                 if (sound_result != MM_ERROR_NONE) {
661                                         LOGE("failed to release sound focus\n");
662                                         return MM_ERROR_POLICY_INTERNAL;
663                                 }
664                         }
665                 }
666                 break;
667
668         case MM_PLAYER_STATE_PLAYING:
669                 {
670                         /* try to get content metadata */
671                         if (!player->sent_bos) {
672                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
673                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
674                                  * legacy mmfw-player api */
675                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
676                         }
677
678                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
679                                 if (!player->sent_bos)
680                                         __mmplayer_handle_missed_plugin(player);
681                                 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
682                                 if (sound_result != MM_ERROR_NONE) {
683                                         // FIXME : need to check history
684                                         if (player->pipeline->videobin) {
685                                                 MMMessageParamType msg = {0, };
686
687                                                 LOGE("failed to go ahead because of video conflict\n");
688
689                                                 msg.union_type = MM_MSG_UNION_CODE;
690                                                 msg.code = MM_ERROR_POLICY_INTERRUPTED;
691                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
692
693                                                 _mmplayer_unrealize((MMHandleType)player);
694                                         } else {
695                                                 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
696                                                 _mmplayer_pause((MMHandleType)player);
697                                                 return sound_result;
698                                         }
699
700                                         return MM_ERROR_POLICY_INTERNAL;
701                                 }
702                         }
703
704                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
705                                 /* initialize because auto resume is done well. */
706                                 player->resumed_by_rewind = FALSE;
707                                 player->playback_rate = 1.0;
708                         }
709
710                         if (!player->sent_bos) {
711                                 /* check audio codec field is set or not
712                                  * we can get it from typefinder or codec's caps.
713                                  */
714                                 gchar *audio_codec = NULL;
715                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
716
717                                 /* The codec format can't be sent for audio only case like amr, mid etc.
718                                  * Because, parser don't make related TAG.
719                                  * So, if it's not set yet, fill it with found data.
720                                  */
721                                 if (!audio_codec) {
722                                         if (g_strrstr(player->type, "audio/midi"))
723                                                 audio_codec = g_strdup("MIDI");
724                                         else if (g_strrstr(player->type, "audio/x-amr"))
725                                                 audio_codec = g_strdup("AMR");
726                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
727                                                 audio_codec = g_strdup("AAC");
728                                         else
729                                                 audio_codec = g_strdup("unknown");
730                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
731
732                                         MMPLAYER_FREEIF(audio_codec);
733                                         mmf_attrs_commit(player->attrs);
734                                         LOGD("set audio codec type with caps\n");
735                                 }
736
737                                 post_bos = TRUE;
738                         }
739                 }
740                 break;
741
742         case MM_PLAYER_STATE_NONE:
743         default:
744                 LOGW("invalid target state, there is nothing to do.\n");
745                 break;
746         }
747
748
749         /* post message to application */
750         if (MMPLAYER_TARGET_STATE(player) == state) {
751                 /* fill the message with state of player */
752                 msg.state.previous = MMPLAYER_PREV_STATE(player);
753                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
754
755                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
756
757                 /* state changed by focus or resource callback */
758                 if (interrupted_by_focus || interrupted_by_resource) {
759                         msg.union_type = MM_MSG_UNION_CODE;
760                         if (interrupted_by_focus)
761                                 msg.code = player->sound_focus.focus_changed_msg;       /* FIXME: player.c convert function have to be modified. */
762                         else if (interrupted_by_resource)
763                                 msg.code = MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT;
764                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
765                 } else /* state changed by usecase */
766                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
767         } else {
768                 LOGD("intermediate state, do nothing.\n");
769                 MMPLAYER_PRINT_STATE(player);
770                 return ret;
771         }
772
773         if (post_bos) {
774                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
775                 player->sent_bos = TRUE;
776         }
777
778         return ret;
779 }
780
781 static gpointer __mmplayer_next_play_thread(gpointer data)
782 {
783         mm_player_t* player = (mm_player_t*) data;
784         MMPlayerGstElement *mainbin = NULL;
785
786         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
787
788         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
789         while (!player->next_play_thread_exit) {
790                 LOGD("next play thread started. waiting for signal.\n");
791                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
792
793                 LOGD("reconfigure pipeline for gapless play.\n");
794
795                 if (player->next_play_thread_exit) {
796                         if (player->gapless.reconfigure) {
797                                 player->gapless.reconfigure = false;
798                                 MMPLAYER_PLAYBACK_UNLOCK(player);
799                         }
800                         LOGD("exiting gapless play thread\n");
801                         break;
802                 }
803
804                 mainbin = player->pipeline->mainbin;
805
806                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
807                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
808                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
809                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
810                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
811
812                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
813         }
814         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
815
816         return NULL;
817 }
818
819 static gpointer __mmplayer_repeat_thread(gpointer data)
820 {
821         mm_player_t* player = (mm_player_t*) data;
822         gboolean ret_value = FALSE;
823         MMHandleType attrs = 0;
824         gint count = 0;
825
826         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
827
828         MMPLAYER_REPEAT_THREAD_LOCK(player);
829         while (!player->repeat_thread_exit) {
830                 LOGD("repeat thread started. waiting for signal.\n");
831                 MMPLAYER_REPEAT_THREAD_WAIT(player);
832
833                 if (player->repeat_thread_exit) {
834                         LOGD("exiting repeat thread\n");
835                         break;
836                 }
837
838
839                 /* lock */
840                 MMPLAYER_CMD_LOCK(player);
841
842                 attrs = MMPLAYER_GET_ATTRS(player);
843
844                 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
845                         LOGE("can not get play count\n");
846                         break;
847                 }
848
849                 if (player->section_repeat) {
850                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
851                 } else {
852                         if (player->playback_rate < 0.0) {
853                                 player->resumed_by_rewind = TRUE;
854                                 _mmplayer_set_mute((MMHandleType)player, 0);
855                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
856                         }
857
858                         ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
859                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
860                                 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
861
862                         /* initialize */
863                         player->sent_bos = FALSE;
864                 }
865
866                 if (!ret_value) {
867                         LOGE("failed to set position to zero for rewind\n");
868                         continue;
869                 }
870
871                 /* decrease play count */
872                 if (count > 1) {
873                         /* we successeded to rewind. update play count and then wait for next EOS */
874                         count--;
875
876                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
877
878                         /* commit attribute */
879                         if (mmf_attrs_commit(attrs))
880                                 LOGE("failed to commit attribute\n");
881                 }
882
883                 /* unlock */
884                 MMPLAYER_CMD_UNLOCK(player);
885         }
886
887         MMPLAYER_REPEAT_THREAD_UNLOCK(player);
888         return NULL;
889 }
890
891 static void
892 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
893 {
894         MMHandleType attrs = 0;
895         guint64 data_size = 0;
896         gchar* path = NULL;
897         unsigned long pos_msec = 0;
898         struct stat sb;
899
900         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
901
902         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
903
904         attrs = MMPLAYER_GET_ATTRS(player);
905         if (!attrs) {
906                 LOGE("fail to get attributes.\n");
907                 return;
908         }
909
910         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
911                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
912
913                 if (stat(path, &sb) == 0)
914                         data_size = (guint64)sb.st_size;
915         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
916                 data_size = player->http_content_size;
917
918         __mm_player_streaming_buffering(player->streamer,
919                                                                                 buffering_msg,
920                                                                                 data_size,
921                                                                                 player->last_position,
922                                                                                 player->duration);
923
924         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
925
926         return;
927 }
928
929 static int
930 __mmplayer_handle_buffering_message(mm_player_t* player)
931 {
932         int ret = MM_ERROR_NONE;
933         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
934         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
935         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
936         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
937
938         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
939                 LOGW("do nothing for buffering msg\n");
940                 ret = MM_ERROR_PLAYER_INVALID_STATE;
941                 goto exit;
942         }
943
944         prev_state = MMPLAYER_PREV_STATE(player);
945         current_state = MMPLAYER_CURRENT_STATE(player);
946         target_state = MMPLAYER_TARGET_STATE(player);
947         pending_state = MMPLAYER_PENDING_STATE(player);
948
949         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
950                 MMPLAYER_STATE_GET_NAME(prev_state),
951                 MMPLAYER_STATE_GET_NAME(current_state),
952                 MMPLAYER_STATE_GET_NAME(pending_state),
953                 MMPLAYER_STATE_GET_NAME(target_state),
954                 player->streamer->is_buffering);
955
956         if (!player->streamer->is_buffering) {
957                 /* NOTE : if buffering has done, player has to go to target state. */
958                 switch (target_state) {
959                 case MM_PLAYER_STATE_PAUSED:
960                         {
961                                 switch (pending_state) {
962                                 case MM_PLAYER_STATE_PLAYING:
963                                         __gst_pause(player, TRUE);
964                                         break;
965
966                                 case MM_PLAYER_STATE_PAUSED:
967                                         LOGD("player is already going to paused state, there is nothing to do.\n");
968                                         break;
969
970                                 case MM_PLAYER_STATE_NONE:
971                                 case MM_PLAYER_STATE_NULL:
972                                 case MM_PLAYER_STATE_READY:
973                                 default:
974                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
975                                         break;
976                                 }
977                         }
978                         break;
979
980                 case MM_PLAYER_STATE_PLAYING:
981                         {
982                                 switch (pending_state) {
983                                 case MM_PLAYER_STATE_NONE:
984                                         {
985                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
986                                                         __gst_resume(player, TRUE);
987                                         }
988                                         break;
989
990                                 case MM_PLAYER_STATE_PAUSED:
991                                         /* NOTE: It should be worked as asynchronously.
992                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
993                                          */
994                                         __gst_resume(player, TRUE);
995                                         break;
996
997                                 case MM_PLAYER_STATE_PLAYING:
998                                         LOGD("player is already going to playing state, there is nothing to do.\n");
999                                         break;
1000
1001                                 case MM_PLAYER_STATE_NULL:
1002                                 case MM_PLAYER_STATE_READY:
1003                                 default:
1004                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1005                                         break;
1006                                 }
1007                         }
1008                         break;
1009
1010                 case MM_PLAYER_STATE_NULL:
1011                 case MM_PLAYER_STATE_READY:
1012                 case MM_PLAYER_STATE_NONE:
1013                 default:
1014                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1015                         break;
1016                 }
1017         } else {
1018                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1019                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1020                  */
1021                 switch (pending_state) {
1022                 case MM_PLAYER_STATE_NONE:
1023                         {
1024                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1025                                         LOGD("set pause state during buffering\n");
1026                                         __gst_pause(player, TRUE);
1027
1028                                         // to cover the weak-signal environment.
1029                                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
1030                                                 unsigned long position = 0;
1031                                                 gint64 pos_msec = 0;
1032
1033                                                 LOGD("[RTSP] seek to the buffering start point\n");
1034
1035                                                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
1036                                                         LOGE("failed to get position\n");
1037                                                         break;
1038                                                 }
1039
1040                                                 /* key unit seek */
1041                                                 pos_msec = position * G_GINT64_CONSTANT(1000000);
1042
1043                                                 __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1044                                                                         GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1045                                                                         pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1046                                         }
1047                                 }
1048                         }
1049                         break;
1050
1051                 case MM_PLAYER_STATE_PLAYING:
1052                         __gst_pause(player, TRUE);
1053                         break;
1054
1055                 case MM_PLAYER_STATE_PAUSED:
1056                         break;
1057
1058                 case MM_PLAYER_STATE_NULL:
1059                 case MM_PLAYER_STATE_READY:
1060                 default:
1061                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1062                         break;
1063                 }
1064         }
1065
1066 exit:
1067         return ret;
1068 }
1069
1070 static void
1071 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1072 {
1073         MMPlayerGstElement *textbin;
1074         MMPLAYER_FENTER();
1075
1076         MMPLAYER_RETURN_IF_FAIL(player &&
1077                                         player->pipeline &&
1078                                         player->pipeline->textbin);
1079
1080         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1081
1082         textbin = player->pipeline->textbin;
1083
1084         if (is_drop) {
1085                 LOGD("Drop subtitle text after getting EOS\n");
1086
1087                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1088                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1089
1090                 player->is_subtitle_force_drop = TRUE;
1091         } else {
1092                 if (player->is_subtitle_force_drop == TRUE) {
1093                         LOGD("Enable subtitle data path without drop\n");
1094
1095                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1096                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1097
1098                         LOGD("non-connected with external display");
1099
1100                         player->is_subtitle_force_drop = FALSE;
1101                 }
1102         }
1103 }
1104
1105 static gboolean
1106 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1107 {
1108         mm_player_t* player = (mm_player_t*) data;
1109         gboolean ret = TRUE;
1110         static gboolean async_done = FALSE;
1111
1112         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1113         MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1114
1115         switch (GST_MESSAGE_TYPE(msg)) {
1116         case GST_MESSAGE_UNKNOWN:
1117                 LOGD("unknown message received\n");
1118                 break;
1119
1120         case GST_MESSAGE_EOS:
1121                 {
1122                         MMHandleType attrs = 0;
1123                         gint count = 0;
1124
1125                         LOGD("GST_MESSAGE_EOS received\n");
1126
1127                         /* NOTE : EOS event is comming multiple time. watch out it */
1128                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1129                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1130                                 LOGD("EOS received on non-playing state. ignoring it\n");
1131                                 break;
1132                         }
1133
1134                         if (player->pipeline) {
1135                                 if (player->pipeline->textbin)
1136                                         __mmplayer_drop_subtitle(player, TRUE);
1137
1138                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1139                                         GstPad *pad = NULL;
1140
1141                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1142
1143                                         LOGD("release audio callback\n");
1144
1145                                         /* release audio callback */
1146                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1147                                         player->audio_cb_probe_id = 0;
1148                                         /* audio callback should be free because it can be called even though probe remove.*/
1149                                         player->audio_stream_cb = NULL;
1150                                         player->audio_stream_cb_user_param = NULL;
1151
1152                                 }
1153                         }
1154                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1155                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1156
1157                         /* rewind if repeat count is greater then zero */
1158                         /* get play count */
1159                         attrs = MMPLAYER_GET_ATTRS(player);
1160
1161                         if (attrs) {
1162                                 gboolean smooth_repeat = FALSE;
1163
1164                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1165                                 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1166
1167                                 player->play_count = count;
1168
1169                                 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1170
1171                                 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1172                                         if (smooth_repeat) {
1173                                                 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1174
1175                                                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1176
1177                                                 break;
1178                                         } else {
1179                                                 gint ret_value = 0;
1180
1181                                                 if (player->section_repeat) {
1182                                                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1183                                                 } else {
1184                                                         if (player->playback_rate < 0.0) {
1185                                                                 player->resumed_by_rewind = TRUE;
1186                                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1187                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1188                                                         }
1189
1190                                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1191
1192                                                         /* initialize */
1193                                                         player->sent_bos = FALSE;
1194                                                 }
1195
1196                                                 if (MM_ERROR_NONE != ret_value)
1197                                                         LOGE("failed to set position to zero for rewind\n");
1198
1199                                                 /* not posting eos when repeating */
1200                                                 break;
1201                                         }
1202                                 }
1203                         }
1204
1205                         if (player->pipeline)
1206                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1207
1208                         /* post eos message to application */
1209                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1210
1211                         /* reset last position */
1212                         player->last_position = 0;
1213                 }
1214                 break;
1215
1216         case GST_MESSAGE_ERROR:
1217                 {
1218                         GError *error = NULL;
1219                         gchar* debug = NULL;
1220
1221                         /* generating debug info before returning error */
1222                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1223
1224                         /* get error code */
1225                         gst_message_parse_error(msg, &error, &debug);
1226
1227                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1228                                 /* Note : the streaming error from the streaming source is handled
1229                                  *   using __mmplayer_handle_streaming_error.
1230                                  */
1231                                 __mmplayer_handle_streaming_error(player, msg);
1232
1233                                 /* dump state of all element */
1234                                 __mmplayer_dump_pipeline_state(player);
1235                         } else {
1236                                 /* traslate gst error code to msl error code. then post it
1237                                  * to application if needed
1238                                  */
1239                                 __mmplayer_handle_gst_error(player, msg, error);
1240
1241                                 if (debug)
1242                                         LOGE("error debug : %s", debug);
1243                         }
1244
1245                         if (MMPLAYER_IS_HTTP_PD(player))
1246                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1247
1248                         MMPLAYER_FREEIF(debug);
1249                         g_error_free(error);
1250                 }
1251                 break;
1252
1253         case GST_MESSAGE_WARNING:
1254                 {
1255                         char* debug = NULL;
1256                         GError* error = NULL;
1257
1258                         gst_message_parse_warning(msg, &error, &debug);
1259
1260                         LOGD("warning : %s\n", error->message);
1261                         LOGD("debug : %s\n", debug);
1262
1263                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1264
1265                         MMPLAYER_FREEIF(debug);
1266                         g_error_free(error);
1267                 }
1268                 break;
1269
1270         case GST_MESSAGE_TAG:
1271                 {
1272                         LOGD("GST_MESSAGE_TAG\n");
1273                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1274                                 LOGW("failed to extract tags from gstmessage\n");
1275                 }
1276                 break;
1277
1278         case GST_MESSAGE_BUFFERING:
1279                 {
1280                         MMMessageParamType msg_param = {0, };
1281
1282                         if (!MMPLAYER_IS_STREAMING(player))
1283                                 break;
1284
1285                         /* ignore the buffering messages during building pipeline, *
1286                          * not to block the main loop                              */
1287                         if (MMPLAYER_CURRENT_STATE(player) <= MM_PLAYER_STATE_READY) {
1288                                 LOGW("ignore the buffering msg(state:%d)", MMPLAYER_CURRENT_STATE(player));
1289                                 break;
1290                         }
1291
1292                         /* ignore the prev buffering message */
1293                         if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1294                                 gint buffer_percent = 0;
1295
1296                                 gst_message_parse_buffering(msg, &buffer_percent);
1297
1298                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1299                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1300                                         player->streamer->is_buffering_done = FALSE;
1301                                 }
1302
1303                                 break;
1304                         }
1305
1306                         MMPLAYER_CMD_LOCK(player);
1307                         __mmplayer_update_buffer_setting(player, msg);
1308
1309                         if (__mmplayer_handle_buffering_message(player) == MM_ERROR_NONE) {
1310                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1311                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1312                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1313                                                 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1314                                         if (player->doing_seek) {
1315                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1316                                                         player->doing_seek = FALSE;
1317                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1318                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1319                                                         async_done = TRUE;
1320                                         }
1321                                 }
1322                         }
1323                         MMPLAYER_CMD_UNLOCK(player);
1324                 }
1325                 break;
1326
1327         case GST_MESSAGE_STATE_CHANGED:
1328                 {
1329                         MMPlayerGstElement *mainbin;
1330                         const GValue *voldstate, *vnewstate, *vpending;
1331                         GstState oldstate = GST_STATE_NULL;
1332                         GstState newstate = GST_STATE_NULL;
1333                         GstState pending = GST_STATE_NULL;
1334
1335                         if (!(player->pipeline && player->pipeline->mainbin)) {
1336                                 LOGE("player pipeline handle is null");
1337                                 break;
1338                         }
1339
1340                         mainbin = player->pipeline->mainbin;
1341
1342                         /* we only handle messages from pipeline */
1343                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1344                                 break;
1345
1346                         /* get state info from msg */
1347                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1348                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1349                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1350
1351                         if (!voldstate || !vnewstate) {
1352                                 LOGE("received msg has wrong format.");
1353                                 break;
1354                         }
1355
1356                         oldstate = (GstState)voldstate->data[0].v_int;
1357                         newstate = (GstState)vnewstate->data[0].v_int;
1358                         if (vpending)
1359                                 pending = (GstState)vpending->data[0].v_int;
1360
1361                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1362                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1363                                 gst_element_state_get_name((GstState)oldstate),
1364                                 gst_element_state_get_name((GstState)newstate),
1365                                 gst_element_state_get_name((GstState)pending));
1366
1367                         if (oldstate == newstate) {
1368                                 LOGD("pipeline reports state transition to old state");
1369                                 break;
1370                         }
1371
1372                         switch (newstate) {
1373                         case GST_STATE_VOID_PENDING:
1374                                 break;
1375
1376                         case GST_STATE_NULL:
1377                                 break;
1378
1379                         case GST_STATE_READY:
1380                                 break;
1381
1382                         case GST_STATE_PAUSED:
1383                                 {
1384                                         gboolean prepare_async = FALSE;
1385
1386                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1387                                                 __mmplayer_configure_audio_callback(player);
1388
1389                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1390                                                 // managed prepare async case
1391                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1392                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1393                                         }
1394
1395                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1396                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1397
1398                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1399                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1400                                                                 player->total_maximum_bitrate, player->total_bitrate);
1401                                         }
1402                                 }
1403                                 break;
1404
1405                         case GST_STATE_PLAYING:
1406                                 {
1407                                         if (MMPLAYER_IS_STREAMING(player)) {
1408                                                 // managed prepare async case when buffering is completed
1409                                                 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1410                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1411                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1412                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1413                                         }
1414
1415                                         if (player->gapless.stream_changed) {
1416                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1417                                                 player->gapless.stream_changed = FALSE;
1418                                         }
1419
1420                                         if (player->doing_seek && async_done) {
1421                                                 player->doing_seek = FALSE;
1422                                                 async_done = FALSE;
1423                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1424                                         }
1425                                 }
1426                                 break;
1427
1428                         default:
1429                                 break;
1430                         }
1431                 }
1432                 break;
1433
1434         case GST_MESSAGE_CLOCK_LOST:
1435                         {
1436                                 GstClock *clock = NULL;
1437                                 gboolean need_new_clock = FALSE;
1438
1439                                 gst_message_parse_clock_lost(msg, &clock);
1440                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1441
1442                                 if (!player->videodec_linked)
1443                                         need_new_clock = TRUE;
1444                                 else if (!player->ini.use_system_clock)
1445                                         need_new_clock = TRUE;
1446
1447                                 if (need_new_clock) {
1448                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1449                                         __gst_pause(player, FALSE);
1450                                         __gst_resume(player, FALSE);
1451                                 }
1452                         }
1453                         break;
1454
1455         case GST_MESSAGE_NEW_CLOCK:
1456                         {
1457                                 GstClock *clock = NULL;
1458                                 gst_message_parse_new_clock(msg, &clock);
1459                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1460                         }
1461                         break;
1462
1463         case GST_MESSAGE_ELEMENT:
1464                         {
1465                                 const gchar *structure_name;
1466                                 gint count = 0;
1467                                 MMHandleType attrs = 0;
1468
1469                                 attrs = MMPLAYER_GET_ATTRS(player);
1470                                 if (!attrs) {
1471                                         LOGE("cannot get content attribute");
1472                                         ret = FALSE;
1473                                         break;
1474                                 }
1475
1476                                 if (gst_message_get_structure(msg) == NULL)
1477                                         break;
1478
1479                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1480                                 if (!structure_name)
1481                                         break;
1482
1483                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1484                                         gint num_buffers = 0;
1485                                         gint extra_num_buffers = 0;
1486
1487                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1488                                                 player->video_num_buffers = num_buffers;
1489                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1490                                         }
1491
1492                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1493                                                 player->video_extra_num_buffers = extra_num_buffers;
1494                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1495                                         }
1496                                         break;
1497                                 }
1498
1499                                 if (!strcmp(structure_name, "Language_list")) {
1500                                         const GValue *lang_list = NULL;
1501                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1502                                         if (lang_list != NULL) {
1503                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1504                                                 if (count > 1)
1505                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1506                                         }
1507                                 }
1508
1509                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1510                                         const GValue *lang_list = NULL;
1511                                         MMPlayerLangStruct *temp = NULL;
1512
1513                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1514                                         if (lang_list != NULL) {
1515                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1516                                                 if (count) {
1517                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1518                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1519                                                         if (mmf_attrs_commit(attrs))
1520                                                           LOGE("failed to commit.\n");
1521                                                         LOGD("Total subtitle tracks = %d \n", count);
1522                                                 }
1523                                                 while (count) {
1524                                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1525                                                         if (temp)
1526                                                                 LOGD("value of lang_key is %s and lang_code is %s",
1527                                                                                         temp->language_key, temp->language_code);
1528                                                         count--;
1529                                                 }
1530                                         }
1531                                 }
1532
1533                                 /* custom message */
1534                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1535                                         MMMessageParamType msg_param = {0,};
1536                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1537                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1538                                 }
1539                         }
1540                         break;
1541
1542         case GST_MESSAGE_DURATION_CHANGED:
1543                 {
1544                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1545                         ret = __mmplayer_gst_handle_duration(player, msg);
1546                         if (!ret)
1547                                 LOGW("failed to update duration");
1548                 }
1549
1550                 break;
1551
1552         case GST_MESSAGE_ASYNC_START:
1553                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1554                 break;
1555
1556         case GST_MESSAGE_ASYNC_DONE:
1557                 {
1558                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1559
1560                         /* we only handle messages from pipeline */
1561                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1562                                 break;
1563
1564                         if (player->doing_seek) {
1565                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1566                                         player->doing_seek = FALSE;
1567                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1568                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1569                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1570                                                 (player->streamer) &&
1571                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1572                                                 (player->streamer->is_buffering == FALSE)) {
1573                                                 GstQuery *query = NULL;
1574                                                 gboolean busy = FALSE;
1575                                                 gint percent = 0;
1576
1577                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1578                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1579                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1580                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1581                                                         gst_query_unref(query);
1582
1583                                                         LOGD("buffered percent(%s): %d\n",
1584                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1585                                                 }
1586
1587                                                 if (percent >= 100) {
1588                                                         player->streamer->is_buffering = FALSE;
1589                                                         __mmplayer_handle_buffering_message(player);
1590                                                 }
1591                                         }
1592
1593                                         async_done = TRUE;
1594                                 }
1595                         }
1596                 }
1597                 break;
1598
1599         #if 0 /* delete unnecessary logs */
1600         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1601         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1602         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1603         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1604         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1605         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1606         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1607         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1608         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1609         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1610         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1611         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1612         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1613         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1614         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1615         #endif
1616
1617         default:
1618                 break;
1619         }
1620
1621         /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1622          * gst_element_post_message api takes ownership of the message.
1623          */
1624         //gst_message_unref(msg);
1625
1626         return ret;
1627 }
1628
1629 static gboolean
1630 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1631 {
1632         gint64 bytes = 0;
1633
1634         MMPLAYER_FENTER();
1635
1636         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1637         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1638
1639         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1640                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1641                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1642
1643                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1644                         LOGD("data total size of http content: %lld", bytes);
1645                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1646                 }
1647         } else
1648                 /* handling audio clip which has vbr. means duration is keep changing */
1649                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1650
1651         MMPLAYER_FLEAVE();
1652
1653         return TRUE;
1654 }
1655
1656
1657 static gboolean
1658 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1659 {
1660
1661 /* macro for better code readability */
1662 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1663 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1664         if (string != NULL) {\
1665                 SECURE_LOGD("update tag string : %s\n", string); \
1666                 mm_attrs_set_string_by_name(attribute, playertag, string); \
1667                 g_free(string);\
1668                 string = NULL;\
1669         } \
1670 }
1671
1672 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1673 GstSample *sample = NULL;\
1674 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1675         GstMapInfo info = GST_MAP_INFO_INIT;\
1676         buffer = gst_sample_get_buffer(sample);\
1677         if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1678                 LOGD("failed to get image data from tag");\
1679                 return FALSE;\
1680         } \
1681         SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1682         MMPLAYER_FREEIF(player->album_art);\
1683         player->album_art = (gchar *)g_malloc(info.size);\
1684         if (player->album_art) {\
1685                 memcpy(player->album_art, info.data, info.size);\
1686                 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1687                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1688                         msg_param.data = (void *)player->album_art;\
1689                         msg_param.size = info.size;\
1690                         MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1691                         SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1692                 } \
1693         } \
1694         gst_buffer_unmap(buffer, &info);\
1695 }
1696
1697 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1698 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1699         if (v_uint) {\
1700                 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1701                         if (player->updated_bitrate_count == 0) \
1702                                 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1703                         if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1704                                 player->bitrate[player->updated_bitrate_count] = v_uint;\
1705                                 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1706                                 player->updated_bitrate_count++; \
1707                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1708                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1709                         } \
1710                 } \
1711                 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1712                         if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1713                                 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1714                                 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1715                                 player->updated_maximum_bitrate_count++; \
1716                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1717                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1718                         } \
1719                 } else\
1720                         mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1721                 v_uint = 0;\
1722         } \
1723 }
1724
1725 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1726 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1727         if (date != NULL) {\
1728                 string = g_strdup_printf("%d", g_date_get_year(date));\
1729                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1730                 SECURE_LOGD("metainfo year : %s\n", string);\
1731                 MMPLAYER_FREEIF(string);\
1732                 g_date_free(date);\
1733         } \
1734 }
1735
1736 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1737 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1738         if (v_uint64) {\
1739                 /* FIXIT : don't know how to store date */\
1740                 g_assert(1);\
1741                 v_uint64 = 0;\
1742         } \
1743 }
1744
1745 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1746 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1747         if (v_double) {\
1748                 /* FIXIT : don't know how to store date */\
1749                 g_assert(1);\
1750                 v_double = 0;\
1751         } \
1752 }
1753
1754         /* function start */
1755         GstTagList* tag_list = NULL;
1756
1757         MMHandleType attrs = 0;
1758
1759         char *string = NULL;
1760         guint v_uint = 0;
1761         GDate *date = NULL;
1762         /* album cover */
1763         GstBuffer *buffer = NULL;
1764         gint index = 0;
1765         MMMessageParamType msg_param = {0, };
1766
1767         /* currently not used. but those are needed for above macro */
1768         //guint64 v_uint64 = 0;
1769         //gdouble v_double = 0;
1770
1771         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1772
1773         attrs = MMPLAYER_GET_ATTRS(player);
1774
1775         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1776
1777         /* get tag list from gst message */
1778         gst_message_parse_tag(msg, &tag_list);
1779
1780         /* store tags to player attributes */
1781         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1782         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1783         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1784         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1785         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1786         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1787         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1788         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1789         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1790         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1791         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1792         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1793         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1794         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1795         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1796         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1797         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1798         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1799         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1800         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1801         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1802         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1803         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1804         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1805         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1806         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1807         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1808         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1809         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1810         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1811         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1812         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1813         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1814         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1815         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1816         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1817         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1818         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1819         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1820         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1821         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1822         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1823         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1824         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1825         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1826         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1827
1828         if (mmf_attrs_commit(attrs))
1829                 LOGE("failed to commit.\n");
1830
1831         gst_tag_list_free(tag_list);
1832
1833         return TRUE;
1834 }
1835
1836 static void
1837 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)  // @
1838 {
1839         mm_player_t* player = (mm_player_t*) data;
1840
1841         MMPLAYER_FENTER();
1842
1843         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1844           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1845           * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1846           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1847
1848           * [1] audio and video will be dumped with filesink.
1849           * [2] autoplugging is done by just using pad caps.
1850           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1851           * and the video will be dumped via filesink.
1852           */
1853         if (player->num_dynamic_pad == 0) {
1854                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1855
1856                 if (!__mmplayer_gst_remove_fakesink(player,
1857                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1858                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1859                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1860                          * source element are not same. To overcome this situation, this function will called
1861                          * several places and several times. Therefore, this is not an error case.
1862                          */
1863                         return;
1864         }
1865
1866         /* create dot before error-return. for debugging */
1867         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1868
1869         player->no_more_pad = TRUE;
1870
1871         MMPLAYER_FLEAVE();
1872 }
1873
1874 static gboolean
1875 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1876 {
1877         GstElement* parent = NULL;
1878
1879         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1880
1881         /* if we have no fakesink. this meas we are using decodebin which doesn'
1882         t need to add extra fakesink */
1883         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
1884
1885         /* lock */
1886         MMPLAYER_FSINK_LOCK(player);
1887
1888         if (!fakesink->gst)
1889                 goto ERROR;
1890
1891         /* get parent of fakesink */
1892         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
1893         if (!parent) {
1894                 LOGD("fakesink already removed\n");
1895                 goto ERROR;
1896         }
1897
1898         gst_element_set_locked_state(fakesink->gst, TRUE);
1899
1900         /* setting the state to NULL never returns async
1901          * so no need to wait for completion of state transiton
1902          */
1903         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
1904                 LOGE("fakesink state change failure!\n");
1905                 /* FIXIT : should I return here? or try to proceed to next? */
1906                 /* return FALSE; */
1907
1908         /* remove fakesink from it's parent */
1909         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
1910                 LOGE("failed to remove fakesink\n");
1911
1912                 gst_object_unref(parent);
1913
1914                 goto ERROR;
1915         }
1916
1917         gst_object_unref(parent);
1918
1919         LOGD("state-holder removed\n");
1920
1921         gst_element_set_locked_state(fakesink->gst, FALSE);
1922
1923         MMPLAYER_FSINK_UNLOCK(player);
1924         return TRUE;
1925
1926 ERROR:
1927         if (fakesink->gst)
1928                 gst_element_set_locked_state(fakesink->gst, FALSE);
1929
1930         MMPLAYER_FSINK_UNLOCK(player);
1931         return FALSE;
1932 }
1933
1934
1935 static void
1936 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
1937 {
1938         GstPad *sinkpad = NULL;
1939         GstCaps* caps = NULL;
1940         GstElement* new_element = NULL;
1941         GstStructure* str = NULL;
1942         const gchar* name = NULL;
1943
1944         mm_player_t* player = (mm_player_t*) data;
1945
1946         MMPLAYER_FENTER();
1947
1948         MMPLAYER_RETURN_IF_FAIL(element && pad);
1949         MMPLAYER_RETURN_IF_FAIL(player &&
1950                                         player->pipeline &&
1951                                         player->pipeline->mainbin);
1952
1953
1954         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
1955          * num_dynamic_pad will decreased after creating a sinkbin.
1956          */
1957         player->num_dynamic_pad++;
1958         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
1959
1960         caps = gst_pad_query_caps(pad, NULL);
1961
1962         MMPLAYER_CHECK_NULL(caps);
1963
1964         /* clear  previous result*/
1965         player->have_dynamic_pad = FALSE;
1966
1967         str = gst_caps_get_structure(caps, 0);
1968
1969         if (!str) {
1970                 LOGE("cannot get structure from caps.\n");
1971                 goto ERROR;
1972         }
1973
1974         name = gst_structure_get_name(str);
1975         if (!name) {
1976                 LOGE("cannot get mimetype from structure.\n");
1977                 goto ERROR;
1978         }
1979
1980         if (strstr(name, "video")) {
1981                 gint stype = 0;
1982                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1983
1984                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
1985                         if (player->v_stream_caps) {
1986                                 gst_caps_unref(player->v_stream_caps);
1987                                 player->v_stream_caps = NULL;
1988                         }
1989
1990                         new_element = gst_element_factory_make("fakesink", NULL);
1991                         player->num_dynamic_pad--;
1992                         goto NEW_ELEMENT;
1993                 }
1994         }
1995
1996         /* clear  previous result*/
1997         player->have_dynamic_pad = FALSE;
1998
1999         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2000                 LOGE("failed to autoplug for caps");
2001                 goto ERROR;
2002         }
2003
2004         /* check if there's dynamic pad*/
2005         if (player->have_dynamic_pad) {
2006                 LOGE("using pad caps assums there's no dynamic pad !\n");
2007                 goto ERROR;
2008         }
2009
2010         gst_caps_unref(caps);
2011         caps = NULL;
2012
2013 NEW_ELEMENT:
2014
2015         /* excute new_element if created*/
2016         if (new_element) {
2017                 LOGD("adding new element to pipeline\n");
2018
2019                 /* set state to READY before add to bin */
2020                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2021
2022                 /* add new element to the pipeline */
2023                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2024                         LOGE("failed to add autoplug element to bin\n");
2025                         goto ERROR;
2026                 }
2027
2028                 /* get pad from element */
2029                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2030                 if (!sinkpad) {
2031                         LOGE("failed to get sinkpad from autoplug element\n");
2032                         goto ERROR;
2033                 }
2034
2035                 /* link it */
2036                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2037                         LOGE("failed to link autoplug element\n");
2038                         goto ERROR;
2039                 }
2040
2041                 gst_object_unref(sinkpad);
2042                 sinkpad = NULL;
2043
2044                 /* run. setting PLAYING here since streamming source is live source */
2045                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2046         }
2047
2048         MMPLAYER_FLEAVE();
2049
2050         return;
2051
2052 STATE_CHANGE_FAILED:
2053 ERROR:
2054         /* FIXIT : take care if new_element has already added to pipeline */
2055         if (new_element)
2056                 gst_object_unref(GST_OBJECT(new_element));
2057
2058         if (sinkpad)
2059                 gst_object_unref(GST_OBJECT(sinkpad));
2060
2061         if (caps)
2062                 gst_object_unref(GST_OBJECT(caps));
2063
2064         /* FIXIT : how to inform this error to MSL ????? */
2065         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2066          * then post an error to application
2067          */
2068 }
2069
2070
2071
2072 /* FIXIT : check indent */
2073 #if 0
2074 static void
2075 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2076 {
2077         GstPad *sinkpad = NULL;
2078         GstCaps* caps = NULL;
2079         GstElement* new_element = NULL;
2080         enum MainElementID element_id = MMPLAYER_M_NUM;
2081
2082         mm_player_t* player = (mm_player_t*) data;
2083
2084         MMPLAYER_FENTER();
2085
2086         MMPLAYER_RETURN_IF_FAIL(element && pad);
2087         MMPLAYER_RETURN_IF_FAIL(player &&
2088                 player->pipeline &&
2089                 player->pipeline->mainbin);
2090
2091         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2092
2093         {
2094                 LOGD("using pad caps to autopluging instead of doing typefind\n");
2095                 caps = gst_pad_query_caps(pad);
2096                 MMPLAYER_CHECK_NULL(caps);
2097                 /* clear  previous result*/
2098                 player->have_dynamic_pad = FALSE;
2099                 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2100                 if (!new_element) {
2101                         LOGE("failed to create wfd rtp depay element\n");
2102                         goto ERROR;
2103                 }
2104                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2105                 /* add new element to the pipeline */
2106                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2107                         LOGD("failed to add autoplug element to bin\n");
2108                         goto ERROR;
2109                 }
2110                 /* get pad from element */
2111                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2112                 if (!sinkpad) {
2113                         LOGD("failed to get sinkpad from autoplug element\n");
2114                         goto ERROR;
2115                 }
2116                 /* link it */
2117                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2118                         LOGD("failed to link autoplug element\n");
2119                         goto ERROR;
2120                 }
2121                 gst_object_unref(sinkpad);
2122                 sinkpad = NULL;
2123                 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2124                 caps = gst_pad_query_caps(pad);
2125                 MMPLAYER_CHECK_NULL(caps);
2126                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2127                 /* create typefind */
2128                 new_element = gst_element_factory_make("typefind", NULL);
2129                 if (!new_element) {
2130                         LOGD("failed to create typefind\n");
2131                         goto ERROR;
2132                 }
2133
2134                 MMPLAYER_SIGNAL_CONNECT(player,
2135                         G_OBJECT(new_element),
2136                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2137                         "have-type",
2138                         G_CALLBACK(__mmplayer_typefind_have_type),
2139                         (gpointer)player);
2140
2141                 player->have_dynamic_pad = FALSE;
2142         }
2143
2144         /* excute new_element if created*/
2145         if (new_element) {
2146                 LOGD("adding new element to pipeline\n");
2147
2148                 /* set state to READY before add to bin */
2149                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2150
2151                 /* add new element to the pipeline */
2152                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2153                         LOGD("failed to add autoplug element to bin\n");
2154                         goto ERROR;
2155                 }
2156
2157                 /* get pad from element */
2158                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2159                 if (!sinkpad) {
2160                         LOGD("failed to get sinkpad from autoplug element\n");
2161                         goto ERROR;
2162                 }
2163
2164                 /* link it */
2165                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2166                         LOGD("failed to link autoplug element\n");
2167                         goto ERROR;
2168                 }
2169
2170                 gst_object_unref(sinkpad);
2171                 sinkpad = NULL;
2172
2173                 /* run. setting PLAYING here since streamming source is live source */
2174                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2175         }
2176
2177         /* store handle to futher manipulation */
2178         player->pipeline->mainbin[element_id].id = element_id;
2179         player->pipeline->mainbin[element_id].gst = new_element;
2180
2181         MMPLAYER_FLEAVE();
2182
2183         return;
2184
2185 STATE_CHANGE_FAILED:
2186 ERROR:
2187         /* FIXIT : take care if new_element has already added to pipeline */
2188         if (new_element)
2189                 gst_object_unref(GST_OBJECT(new_element));
2190
2191         if (sinkpad)
2192                 gst_object_unref(GST_OBJECT(sinkpad));
2193
2194         if (caps)
2195                 gst_object_unref(GST_OBJECT(caps));
2196
2197         /* FIXIT : how to inform this error to MSL ????? */
2198         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2199          * then post an error to application
2200          */
2201 }
2202 #endif
2203
2204 static GstPadProbeReturn
2205 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2206 {
2207         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2208         return GST_PAD_PROBE_OK;
2209 }
2210
2211 static GstPadProbeReturn
2212 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2213 {
2214         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2215         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2216         mm_player_t* player = (mm_player_t*)data;
2217         GstCaps* caps = NULL;
2218         GstStructure* str = NULL;
2219         const gchar* name = NULL;
2220         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2221
2222         if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2223                 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2224                 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT)
2225                 return ret;
2226
2227         caps = gst_pad_query_caps(pad, NULL);
2228         if (!caps) {
2229                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2230                 goto ERROR;
2231         }
2232
2233         str = gst_caps_get_structure(caps, 0);
2234         if (!str) {
2235                 LOGE("failed to get structure from caps");
2236                 goto ERROR;
2237         }
2238
2239         name = gst_structure_get_name(str);
2240         if (!name) {
2241                 LOGE("failed to get name from str");
2242                 goto ERROR;
2243         }
2244
2245         if (strstr(name, "audio")) {
2246                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2247         } else if (strstr(name, "video")) {
2248                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2249         } else {
2250                 /* text track is not supportable */
2251                 LOGE("invalid name %s", name);
2252                 goto ERROR;
2253         }
2254
2255         LOGD("stream type is %d", stream_type);
2256
2257         switch (GST_EVENT_TYPE(event)) {
2258         case GST_EVENT_STREAM_START:
2259                 {
2260                         gint64 stop_running_time = 0;
2261                         gint64 position_running_time = 0;
2262                         gint64 position = 0;
2263                         gint idx = 0;
2264
2265                         LOGD("[%d] GST_EVENT_STREAM_START", stream_type);
2266
2267                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2268                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2269                                         !(player->selector[idx].event_probe_id)) {
2270                                         LOGW("[%d] skip", idx);
2271                                         continue;
2272                                 }
2273
2274                                 if (player->gapless.segment[idx].stop != -1)
2275                                         stop_running_time =
2276                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2277                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2278                                 else
2279                                         stop_running_time =
2280                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2281                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2282
2283                                 position_running_time =
2284                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2285                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2286
2287                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2288                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2289                                         idx,
2290                                         GST_TIME_ARGS(stop_running_time),
2291                                         GST_TIME_ARGS(position_running_time),
2292                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2293                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2294
2295                                 position_running_time = MAX(position_running_time, stop_running_time);
2296                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2297                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2298                                 position_running_time = MAX(0, position_running_time);
2299                                 position = MAX(position, position_running_time);
2300                         }
2301
2302                         LOGD("start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2303                                 GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2304                                 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2305
2306                         player->gapless.start_time[stream_type] += position;
2307                         break;
2308                 }
2309         case GST_EVENT_FLUSH_STOP:
2310                 {
2311                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2312                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2313                         player->gapless.start_time[stream_type] = 0;
2314                         break;
2315                 }
2316         case GST_EVENT_SEGMENT:
2317                 {
2318                         GstSegment segment;
2319                         GstEvent *tmpev;
2320
2321                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2322                         gst_event_copy_segment(event, &segment);
2323
2324                         if (segment.format == GST_FORMAT_TIME) {
2325                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2326                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2327                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2328                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2329                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2330                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2331
2332                                 /* keep the all the segment ev to cover the seeking */
2333                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2334                                 player->gapless.update_segment[stream_type] = TRUE;
2335
2336                                 if (!player->gapless.running)
2337                                         break;
2338
2339                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2340
2341                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2342
2343                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2344                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2345                                 gst_event_unref(event);
2346                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2347                         }
2348                         break;
2349                 }
2350         default:
2351                 break;
2352         }
2353
2354 ERROR:
2355         if (caps)
2356                 gst_caps_unref(caps);
2357         return ret;
2358 }
2359
2360 static void
2361 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2362 {
2363         mm_player_t* player = NULL;
2364         GstElement* pipeline = NULL;
2365         GstElement* selector = NULL;
2366         GstElement* fakesink = NULL;
2367         GstCaps* caps = NULL;
2368         GstStructure* str = NULL;
2369         const gchar* name = NULL;
2370         GstPad* sinkpad = NULL;
2371         GstPad* srcpad = NULL;
2372         gboolean first_track = FALSE;
2373
2374         enum MainElementID elemId = MMPLAYER_M_NUM;
2375         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2376
2377         /* check handles */
2378         player = (mm_player_t*)data;
2379
2380         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2381         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2382
2383         //LOGD("pad-added signal handling\n");
2384
2385         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2386
2387         /* get mimetype from caps */
2388         caps = gst_pad_query_caps(pad, NULL);
2389         if (!caps) {
2390                 LOGE("cannot get caps from pad.\n");
2391                 goto ERROR;
2392         }
2393
2394         str = gst_caps_get_structure(caps, 0);
2395         if (!str) {
2396                 LOGE("cannot get structure from caps.\n");
2397                 goto ERROR;
2398         }
2399
2400         name = gst_structure_get_name(str);
2401         if (!name) {
2402                 LOGE("cannot get mimetype from structure.\n");
2403                 goto ERROR;
2404         }
2405
2406         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2407         //LOGD("detected mimetype : %s\n", name);
2408
2409         if (strstr(name, "video")) {
2410                 gint stype = 0;
2411                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2412
2413                 /* don't make video because of not required, and not support multiple track */
2414                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2415                         LOGD("no video sink by null surface");
2416                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2417                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2418                                         == MM_ERROR_NONE) {
2419                                 /* acquire resources for video playing */
2420                                 if (resource_state == RESOURCE_STATE_PREPARED) {
2421                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2422                                                         != MM_ERROR_NONE) {
2423                                                 LOGE("could not acquire resources for video playing\n");
2424                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2425                                                 goto ERROR;
2426                                         }
2427                                 }
2428                         }
2429
2430                         gchar *caps_str = gst_caps_to_string(caps);
2431                         if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2432                                 player->set_mode.video_zc = TRUE;
2433
2434                         MMPLAYER_FREEIF(caps_str);
2435
2436                         if (player->v_stream_caps) {
2437                                 gst_caps_unref(player->v_stream_caps);
2438                                 player->v_stream_caps = NULL;
2439                         }
2440
2441                         LOGD("create fakesink instead of videobin");
2442
2443                         /* fake sink */
2444                         fakesink = gst_element_factory_make("fakesink", NULL);
2445                         if (fakesink == NULL) {
2446                                 LOGE("ERROR : fakesink create error\n");
2447                                 goto ERROR;
2448                         }
2449
2450                         if (player->ini.set_dump_element_flag)
2451                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2452
2453                         player->video_fakesink = fakesink;
2454
2455                         /* store it as it's sink element */
2456                         __mmplayer_add_sink(player, player->video_fakesink);
2457
2458                         gst_bin_add(GST_BIN(pipeline), fakesink);
2459
2460                         // link
2461                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2462
2463                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2464                                 LOGW("failed to link fakesink\n");
2465                                 gst_object_unref(GST_OBJECT(fakesink));
2466                                 goto ERROR;
2467                         }
2468
2469                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2470                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2471                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2472                         }
2473
2474                         if (player->set_mode.media_packet_video_stream) {
2475                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2476
2477                                 MMPLAYER_SIGNAL_CONNECT(player,
2478                                                                                 G_OBJECT(fakesink),
2479                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2480                                                                                 "handoff",
2481                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2482                                                                                 (gpointer)player);
2483
2484                                 MMPLAYER_SIGNAL_CONNECT(player,
2485                                                                                 G_OBJECT(fakesink),
2486                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2487                                                                                 "preroll-handoff",
2488                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2489                                                                                 (gpointer)player);
2490                         }
2491
2492                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2493                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2494                         goto DONE;
2495                 }
2496
2497                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2498                         __mmplayer_gst_decode_callback(elem, pad, player);
2499                         return;
2500                 }
2501
2502                 LOGD("video selector \n");
2503                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2504                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2505         } else {
2506                 if (strstr(name, "audio")) {
2507                         gint samplerate = 0;
2508                         gint channels = 0;
2509
2510                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2511                                 __mmplayer_gst_decode_callback(elem, pad, player);
2512                                 return;
2513                         }
2514
2515                         LOGD("audio selector \n");
2516                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2517                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2518
2519                         gst_structure_get_int(str, "rate", &samplerate);
2520                         gst_structure_get_int(str, "channels", &channels);
2521
2522                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2523                                 /* fake sink */
2524                                 fakesink = gst_element_factory_make("fakesink", NULL);
2525                                 if (fakesink == NULL) {
2526                                         LOGE("ERROR : fakesink create error\n");
2527                                         goto ERROR;
2528                                 }
2529
2530                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2531
2532                                 /* link */
2533                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2534
2535                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2536                                         LOGW("failed to link fakesink\n");
2537                                         gst_object_unref(GST_OBJECT(fakesink));
2538                                         goto ERROR;
2539                                 }
2540
2541                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2542                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2543                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2544
2545                                 goto DONE;
2546                         }
2547                 } else if (strstr(name, "text")) {
2548                         LOGD("text selector \n");
2549                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2550                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2551                 } else {
2552                         LOGE("wrong elem id \n");
2553                         goto ERROR;
2554                 }
2555         }
2556
2557         selector = player->pipeline->mainbin[elemId].gst;
2558         if (selector == NULL) {
2559                 selector = gst_element_factory_make("input-selector", NULL);
2560                 LOGD("Creating input-selector\n");
2561                 if (selector == NULL) {
2562                         LOGE("ERROR : input-selector create error\n");
2563                         goto ERROR;
2564                 }
2565                 g_object_set(selector, "sync-streams", TRUE, NULL);
2566
2567                 player->pipeline->mainbin[elemId].id = elemId;
2568                 player->pipeline->mainbin[elemId].gst = selector;
2569
2570                 first_track = TRUE;
2571                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2572
2573                 srcpad = gst_element_get_static_pad(selector, "src");
2574
2575                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2576                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2577                         __mmplayer_gst_selector_blocked, NULL, NULL);
2578                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2579                         __mmplayer_gst_selector_event_probe, player, NULL);
2580
2581                 gst_element_set_state(selector, GST_STATE_PAUSED);
2582                 gst_bin_add(GST_BIN(pipeline), selector);
2583         } else
2584                 LOGD("input-selector is already created.\n");
2585
2586         // link
2587         LOGD("Calling request pad with selector %p \n", selector);
2588         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2589
2590         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2591
2592         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2593                 LOGW("failed to link selector\n");
2594                 gst_object_unref(GST_OBJECT(selector));
2595                 goto ERROR;
2596         }
2597
2598         if (first_track) {
2599                 LOGD("this is first track --> active track \n");
2600                 g_object_set(selector, "active-pad", sinkpad, NULL);
2601         }
2602
2603         _mmplayer_track_update_info(player, stream_type, sinkpad);
2604
2605
2606 DONE:
2607 ERROR:
2608
2609         if (caps)
2610                 gst_caps_unref(caps);
2611
2612         if (sinkpad) {
2613                 gst_object_unref(GST_OBJECT(sinkpad));
2614                 sinkpad = NULL;
2615         }
2616
2617         if (srcpad) {
2618                 gst_object_unref(GST_OBJECT(srcpad));
2619                 srcpad = NULL;
2620         }
2621
2622         return;
2623 }
2624
2625 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2626 {
2627         GstPad* srcpad = NULL;
2628         MMHandleType attrs = 0;
2629         gint active_index = 0;
2630
2631         // [link] input-selector :: textbin
2632         srcpad = gst_element_get_static_pad(text_selector, "src");
2633         if (!srcpad) {
2634                 LOGE("failed to get srcpad from selector\n");
2635                 return;
2636         }
2637
2638         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2639
2640         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2641         if ((active_index != DEFAULT_TRACK) &&
2642                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2643                 LOGW("failed to change text track\n");
2644                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2645         }
2646
2647         player->no_more_pad = TRUE;
2648         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2649
2650         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2651         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2652                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2653                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2654         }
2655
2656         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2657
2658         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2659                 player->has_closed_caption = TRUE;
2660
2661         attrs = MMPLAYER_GET_ATTRS(player);
2662         if (attrs) {
2663                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2664                 if (mmf_attrs_commit(attrs))
2665                         LOGE("failed to commit.\n");
2666         } else
2667                 LOGE("cannot get content attribute");
2668
2669         if (srcpad) {
2670                 gst_object_unref(GST_OBJECT(srcpad));
2671                 srcpad = NULL;
2672         }
2673 }
2674
2675 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2676 {
2677         int result = MM_ERROR_NONE;
2678
2679         mm_player_t* player = (mm_player_t*)hplayer;
2680         MMPlayerGstElement* mainbin = NULL;
2681         gchar* change_pad_name = NULL;
2682         GstPad* sinkpad = NULL;
2683         GstCaps* caps = NULL;
2684
2685         MMPLAYER_FENTER();
2686
2687         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2688
2689         LOGD("Change Audio mode to %d\n", ch_idx);
2690         player->use_deinterleave = TRUE;
2691
2692         if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2693                 LOGD("pre setting : %d\n", ch_idx);
2694
2695                 player->audio_mode.active_pad_index = ch_idx;
2696                 return result;
2697         }
2698
2699         mainbin = player->pipeline->mainbin;
2700
2701         if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2702                 if (player->max_audio_channels < 2) {
2703                         LOGD("mono channel track only\n");
2704                         return result;
2705                 }
2706
2707                 LOGW("selector doesn't exist\n");
2708                 return result;  /* keep playing */
2709         }
2710
2711         LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2712
2713         if (player->audio_mode.total_track_num < 2) {
2714                 LOGW("there is no another audio path\n");
2715                 return result;  /* keep playing */
2716         }
2717
2718         if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2719                 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2720                 return result;  /* keep playing */
2721         }
2722
2723         /*To get the new pad from the selector*/
2724         change_pad_name = g_strdup_printf("sink%d", ch_idx);
2725         if (change_pad_name == NULL) {
2726                 LOGW("Pad does not exists\n");
2727                 goto ERROR;     /* keep playing */
2728         }
2729
2730         LOGD("new active pad name: %s\n", change_pad_name);
2731
2732         sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2733         if (sinkpad == NULL)
2734                 //result = MM_ERROR_PLAYER_INTERNAL;
2735                 goto ERROR;     /* keep playing */
2736
2737         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2738         g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2739
2740         caps = gst_pad_get_current_caps(sinkpad);
2741         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2742
2743         __mmplayer_set_audio_attrs(player, caps);
2744         player->audio_mode.active_pad_index = ch_idx;
2745
2746 ERROR:
2747
2748         if (sinkpad)
2749                 gst_object_unref(sinkpad);
2750
2751         MMPLAYER_FREEIF(change_pad_name);
2752
2753         MMPLAYER_FLEAVE();
2754         return result;
2755 }
2756
2757
2758
2759 static void
2760 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2761 {
2762         mm_player_t* player = (mm_player_t*)data;
2763         GstElement* selector = NULL;
2764         GstElement* queue = NULL;
2765
2766         GstPad* srcpad = NULL;
2767         GstPad* sinkpad = NULL;
2768         gchar* caps_str = NULL;
2769
2770         MMPLAYER_FENTER();
2771         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2772
2773         caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2774         LOGD("deinterleave new caps : %s\n", caps_str);
2775         MMPLAYER_FREEIF(caps_str);
2776
2777         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2778                 LOGE("ERROR : queue create error\n");
2779                 goto ERROR;
2780         }
2781
2782         g_object_set(G_OBJECT(queue),
2783                                 "max-size-buffers", 10,
2784                                 "max-size-bytes", 0,
2785                                 "max-size-time", (guint64)0,
2786                                 NULL);
2787
2788         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2789
2790         if (!selector) {
2791                 LOGE("there is no audio channel selector.\n");
2792                 goto ERROR;
2793         }
2794
2795         srcpad = gst_element_get_static_pad(queue, "src");
2796         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2797
2798         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2799
2800         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2801                 LOGW("failed to link deinterleave - selector\n");
2802                 goto ERROR;
2803         }
2804
2805         gst_element_set_state(queue, GST_STATE_PAUSED);
2806         player->audio_mode.total_track_num++;
2807
2808 ERROR:
2809
2810         if (srcpad) {
2811                 gst_object_unref(GST_OBJECT(srcpad));
2812                 srcpad = NULL;
2813         }
2814
2815         if (sinkpad) {
2816                 gst_object_unref(GST_OBJECT(sinkpad));
2817                 sinkpad = NULL;
2818         }
2819
2820         MMPLAYER_FLEAVE();
2821         return;
2822 }
2823
2824 static void
2825 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2826 {
2827         mm_player_t* player = NULL;
2828         GstElement* selector = NULL;
2829         GstPad* sinkpad = NULL;
2830         gint active_index = 0;
2831         gchar* change_pad_name = NULL;
2832         GstCaps* caps = NULL;   // no need to unref
2833         gint default_audio_ch = 0;
2834
2835         MMPLAYER_FENTER();
2836         player = (mm_player_t*) data;
2837
2838         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2839
2840         if (!selector) {
2841                 LOGE("there is no audio channel selector.\n");
2842                 goto ERROR;
2843         }
2844
2845         active_index = player->audio_mode.active_pad_index;
2846
2847         if (active_index != default_audio_ch) {
2848                 gint audio_ch = default_audio_ch;
2849
2850                 /*To get the new pad from the selector*/
2851                 change_pad_name = g_strdup_printf("sink%d", active_index);
2852                 if (change_pad_name != NULL) {
2853                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2854                         if (sinkpad != NULL) {
2855                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2856                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2857
2858                                 audio_ch = active_index;
2859
2860                                 caps = gst_pad_get_current_caps(sinkpad);
2861                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2862
2863                                 __mmplayer_set_audio_attrs(player, caps);
2864                         }
2865                         MMPLAYER_FREEIF(change_pad_name);
2866                 }
2867
2868                 player->audio_mode.active_pad_index = audio_ch;
2869                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2870         }
2871
2872 ERROR:
2873
2874         if (sinkpad)
2875                 gst_object_unref(sinkpad);
2876
2877         MMPLAYER_FLEAVE();
2878         return;
2879 }
2880
2881 static void
2882 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2883 {
2884         mm_player_t* player = NULL;
2885         MMPlayerGstElement *mainbin = NULL;
2886
2887         GstElement* tee = NULL;
2888         GstElement* stereo_queue = NULL;
2889         GstElement* mono_queue = NULL;
2890         GstElement* conv = NULL;
2891         GstElement* filter = NULL;
2892         GstElement* deinterleave = NULL;
2893         GstElement* selector = NULL;
2894
2895         GstPad* srcpad = NULL;
2896         GstPad* selector_srcpad = NULL;
2897         GstPad* sinkpad = NULL;
2898         GstCaps* caps = NULL;
2899         gulong block_id = 0;
2900
2901         MMPLAYER_FENTER();
2902
2903         /* check handles */
2904         player = (mm_player_t*) data;
2905
2906         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2907         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2908
2909         mainbin = player->pipeline->mainbin;
2910
2911         /* tee */
2912         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2913                 LOGE("ERROR : tee create error\n");
2914                 goto ERROR;
2915         }
2916
2917         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2918         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2919
2920         gst_element_set_state(tee, GST_STATE_PAUSED);
2921
2922         /* queue */
2923         srcpad = gst_element_get_request_pad(tee, "src_%u");
2924         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2925                 LOGE("ERROR : stereo queue create error\n");
2926                 goto ERROR;
2927         }
2928
2929         g_object_set(G_OBJECT(stereo_queue),
2930                                 "max-size-buffers", 10,
2931                                 "max-size-bytes", 0,
2932                                 "max-size-time", (guint64)0,
2933                                 NULL);
2934
2935         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2936         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2937
2938         if (srcpad) {
2939                 gst_object_unref(GST_OBJECT(srcpad));
2940                 srcpad = NULL;
2941         }
2942
2943         srcpad = gst_element_get_request_pad(tee, "src_%u");
2944
2945         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2946                 LOGE("ERROR : mono queue create error\n");
2947                 goto ERROR;
2948         }
2949
2950         g_object_set(G_OBJECT(mono_queue),
2951                                 "max-size-buffers", 10,
2952                                 "max-size-bytes", 0,
2953                                 "max-size-time", (guint64)0,
2954                                 NULL);
2955
2956         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2957         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2958
2959         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2960         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2961
2962         /* audioconvert */
2963         srcpad = gst_element_get_static_pad(mono_queue, "src");
2964         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2965                 LOGE("ERROR : audioconvert create error\n");
2966                 goto ERROR;
2967         }
2968
2969         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2970         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2971
2972         /* caps filter */
2973         if (srcpad) {
2974                 gst_object_unref(GST_OBJECT(srcpad));
2975                 srcpad = NULL;
2976         }
2977         srcpad = gst_element_get_static_pad(conv, "src");
2978
2979         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2980                 LOGE("ERROR : capsfilter create error\n");
2981                 goto ERROR;
2982         }
2983
2984         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2985         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2986
2987         caps = gst_caps_from_string("audio/x-raw-int, "
2988                                 "width = (int) 16, "
2989                                 "depth = (int) 16, "
2990                                 "channels = (int) 2");
2991
2992         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
2993         gst_caps_unref(caps);
2994
2995         gst_element_set_state(conv, GST_STATE_PAUSED);
2996         gst_element_set_state(filter, GST_STATE_PAUSED);
2997
2998         /* deinterleave */
2999         if (srcpad) {
3000                 gst_object_unref(GST_OBJECT(srcpad));
3001                 srcpad = NULL;
3002         }
3003         srcpad = gst_element_get_static_pad(filter, "src");
3004
3005         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3006                 LOGE("ERROR : deinterleave create error\n");
3007                 goto ERROR;
3008         }
3009
3010         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3011
3012         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3013                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3014
3015         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3016                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3017
3018         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3019         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3020
3021         /* selector */
3022         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3023         if (selector == NULL) {
3024                 LOGE("ERROR : audio-selector create error\n");
3025                 goto ERROR;
3026         }
3027
3028         g_object_set(selector, "sync-streams", TRUE, NULL);
3029         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3030
3031         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3032         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3033
3034         selector_srcpad = gst_element_get_static_pad(selector, "src");
3035
3036         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3037         block_id =
3038                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3039                         __mmplayer_gst_selector_blocked, NULL, NULL);
3040
3041         if (srcpad) {
3042                 gst_object_unref(GST_OBJECT(srcpad));
3043                 srcpad = NULL;
3044         }
3045
3046         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3047         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3048
3049         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3050                 LOGW("failed to link queue_stereo - selector\n");
3051                 goto ERROR;
3052         }
3053
3054         player->audio_mode.total_track_num++;
3055
3056         g_object_set(selector, "active-pad", sinkpad, NULL);
3057         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3058         gst_element_set_state(selector, GST_STATE_PAUSED);
3059
3060         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3061
3062 ERROR:
3063
3064         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3065         if (block_id != 0) {
3066                 gst_pad_remove_probe(selector_srcpad, block_id);
3067                 block_id = 0;
3068         }
3069
3070         if (sinkpad) {
3071                 gst_object_unref(GST_OBJECT(sinkpad));
3072                 sinkpad = NULL;
3073         }
3074
3075         if (srcpad) {
3076                 gst_object_unref(GST_OBJECT(srcpad));
3077                 srcpad = NULL;
3078         }
3079
3080         if (selector_srcpad) {
3081                 gst_object_unref(GST_OBJECT(selector_srcpad));
3082                 selector_srcpad = NULL;
3083         }
3084
3085         MMPLAYER_FLEAVE();
3086         return;
3087 }
3088
3089 static void
3090 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3091 {
3092         mm_player_t* player = NULL;
3093         GstPad* srcpad = NULL;
3094         GstElement* video_selector = NULL;
3095         GstElement* audio_selector = NULL;
3096         GstElement* text_selector = NULL;
3097         MMHandleType attrs = 0;
3098         gint active_index = 0;
3099         gint64 dur_bytes = 0L;
3100
3101         player = (mm_player_t*) data;
3102
3103         LOGD("no-more-pad signal handling\n");
3104
3105         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3106                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3107                 LOGW("no need to go more");
3108
3109                 if (player->gapless.reconfigure) {
3110                         player->gapless.reconfigure = FALSE;
3111                         MMPLAYER_PLAYBACK_UNLOCK(player);
3112                 }
3113
3114                 return;
3115         }
3116
3117         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3118                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3119                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3120                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3121                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3122
3123                 if (NULL == player->streamer) {
3124                         LOGW("invalid state for buffering");
3125                         goto ERROR;
3126                 }
3127
3128                 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3129                 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3130
3131                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3132                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3133
3134                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3135
3136                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3137                         LOGE("fail to get duration.\n");
3138
3139                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3140                 // use file information was already set on Q2 when it was created.
3141                 __mm_player_streaming_set_queue2(player->streamer,
3142                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3143                                                 TRUE,                                                           // use_buffering
3144                                                 buffer_bytes,
3145                                                 init_buffering_time,
3146                                                 1.0,                                                            // low percent
3147                                                 player->ini.http_buffering_limit,       // high percent
3148                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3149                                                 NULL,
3150                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3151         }
3152
3153         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3154         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3155         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3156         if (video_selector) {
3157                 // [link] input-selector :: videobin
3158                 srcpad = gst_element_get_static_pad(video_selector, "src");
3159                 if (!srcpad) {
3160                         LOGE("failed to get srcpad from video selector\n");
3161                         goto ERROR;
3162                 }
3163
3164                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3165                 if (!text_selector && !audio_selector)
3166                         player->no_more_pad = TRUE;
3167
3168                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3169
3170                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3171                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3172                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3173                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3174                 }
3175         }
3176
3177         if (audio_selector) {
3178                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3179                 if ((active_index != DEFAULT_TRACK) &&
3180                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3181                         LOGW("failed to change audio track\n");
3182                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3183                 }
3184
3185                 // [link] input-selector :: audiobin
3186                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3187                 if (!srcpad) {
3188                         LOGE("failed to get srcpad from selector\n");
3189                         goto ERROR;
3190                 }
3191
3192                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3193                 if (!text_selector)
3194                         player->no_more_pad = TRUE;
3195
3196                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3197                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3198                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3199                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3200                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3201                         }
3202
3203                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3204                 } else {
3205                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3206
3207                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3208                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3209                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3210                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3211                         }
3212                 }
3213
3214                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3215
3216                 attrs = MMPLAYER_GET_ATTRS(player);
3217                 if (attrs) {
3218                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3219                         if (mmf_attrs_commit(attrs))
3220                                 LOGE("failed to commit.\n");
3221                 } else
3222                         LOGE("cannot get content attribute");
3223         } else {
3224                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3225                         LOGD("There is no audio track : remove audiobin");
3226
3227                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3228                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3229
3230                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3231                         MMPLAYER_FREEIF(player->pipeline->audiobin)
3232                 }
3233
3234                 if (player->num_dynamic_pad == 0)
3235                         __mmplayer_pipeline_complete(NULL, player);
3236         }
3237
3238         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3239                 if (text_selector)
3240                         __mmplayer_handle_text_decode_path(player, text_selector);
3241         }
3242
3243         MMPLAYER_FLEAVE();
3244
3245 ERROR:
3246         if (srcpad) {
3247                 gst_object_unref(GST_OBJECT(srcpad));
3248                 srcpad = NULL;
3249         }
3250
3251         if (player->gapless.reconfigure) {
3252                 player->gapless.reconfigure = FALSE;
3253                 MMPLAYER_PLAYBACK_UNLOCK(player);
3254         }
3255 }
3256
3257 static void
3258 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3259 {
3260         mm_player_t* player = NULL;
3261         MMHandleType attrs = 0;
3262         GstElement* pipeline = NULL;
3263         GstCaps* caps = NULL;
3264         gchar* caps_str = NULL;
3265         GstStructure* str = NULL;
3266         const gchar* name = NULL;
3267         GstPad* sinkpad = NULL;
3268         GstElement* sinkbin = NULL;
3269         gboolean reusing = FALSE;
3270         GstElement *text_selector = NULL;
3271         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3272
3273         /* check handles */
3274         player = (mm_player_t*) data;
3275
3276         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3277         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3278
3279         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3280
3281         attrs = MMPLAYER_GET_ATTRS(player);
3282         if (!attrs) {
3283                 LOGE("cannot get content attribute\n");
3284                 goto ERROR;
3285         }
3286
3287         /* get mimetype from caps */
3288         caps = gst_pad_query_caps(pad, NULL);
3289         if (!caps) {
3290                 LOGE("cannot get caps from pad.\n");
3291                 goto ERROR;
3292         }
3293         caps_str = gst_caps_to_string(caps);
3294
3295         str = gst_caps_get_structure(caps, 0);
3296         if (!str) {
3297                 LOGE("cannot get structure from caps.\n");
3298                 goto ERROR;
3299         }
3300
3301         name = gst_structure_get_name(str);
3302         if (!name) {
3303                 LOGE("cannot get mimetype from structure.\n");
3304                 goto ERROR;
3305         }
3306
3307         //LOGD("detected mimetype : %s\n", name);
3308
3309         if (strstr(name, "audio")) {
3310                 if (player->pipeline->audiobin == NULL) {
3311                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3312                                 LOGE("failed to create audiobin. continuing without audio\n");
3313                                 goto ERROR;
3314                         }
3315
3316                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3317                         LOGD("creating audiosink bin success\n");
3318                 } else {
3319                         reusing = TRUE;
3320                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3321                         LOGD("reusing audiobin\n");
3322                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3323                 }
3324
3325                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3326                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3327
3328                 player->audiosink_linked  = 1;
3329
3330                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3331                 if (!sinkpad) {
3332                         LOGE("failed to get pad from sinkbin\n");
3333                         goto ERROR;
3334                 }
3335         } else if (strstr(name, "video")) {
3336                 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3337                         player->set_mode.video_zc = TRUE;
3338
3339                 if (player->pipeline->videobin == NULL) {
3340                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3341                         /* get video surface type */
3342                         int surface_type = 0;
3343                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3344                         LOGD("display_surface_type(%d)\n", surface_type);
3345
3346                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3347                                 LOGD("not make videobin because it dose not want\n");
3348                                 goto ERROR;
3349                         }
3350
3351                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3352                                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3353                                         /* prepare resource manager for video overlay */
3354                                         if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3355                                                 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3356                                                         != MM_ERROR_NONE) {
3357                                                         LOGE("could not prepare for video_overlay resource\n");
3358                                                         goto ERROR;
3359                                                 }
3360                                         }
3361                                 }
3362                         }
3363
3364                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3365                                 == MM_ERROR_NONE) {
3366                                 /* acquire resources for video playing */
3367                                 if (resource_state == RESOURCE_STATE_PREPARED) {
3368                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3369                                                 != MM_ERROR_NONE) {
3370                                                 LOGE("could not acquire resources for video playing\n");
3371                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3372                                                 goto ERROR;
3373                                         }
3374                                 }
3375                         }
3376
3377                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3378                                 LOGE("failed to create videobin. continuing without video\n");
3379                                 goto ERROR;
3380                         }
3381
3382                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3383                         LOGD("creating videosink bin success\n");
3384                 } else {
3385                         reusing = TRUE;
3386                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3387                         LOGD("re-using videobin\n");
3388                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3389                 }
3390
3391                 /* FIXIT : track number shouldn't be hardcoded */
3392                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3393                 player->videosink_linked  = 1;
3394
3395                 /* NOTE : intermediate code before doing H/W subtitle compositon */
3396                 if (player->use_textoverlay && player->play_subtitle) {
3397                         LOGD("using textoverlay for external subtitle");
3398                         /* check text bin has created well */
3399                         if (player->pipeline && player->pipeline->textbin) {
3400                                 /* get sinkpad from textoverlay */
3401                                 sinkpad = gst_element_get_static_pad(
3402                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3403                                         "video_sink");
3404                                 if (!sinkpad) {
3405                                         LOGE("failed to get sink pad from textoverlay");
3406                                         goto ERROR;
3407                                 }
3408
3409                                 /* link new pad with textoverlay first */
3410                                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3411                                         LOGE("failed to get pad from sinkbin\n");
3412                                         goto ERROR;
3413                                 }
3414
3415                                 gst_object_unref(sinkpad);
3416                                 sinkpad = NULL;
3417
3418                                 /* alright, override pad to textbin.src for futher link */
3419                                 pad = gst_element_get_static_pad(
3420                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3421                                         "src");
3422                                 if (!pad) {
3423                                         LOGE("failed to get sink pad from textoverlay");
3424                                         goto ERROR;
3425                                 }
3426                         } else {
3427                                 LOGE("should not reach here.");
3428                                 goto ERROR;
3429                         }
3430                 }
3431
3432                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3433                 if (!sinkpad) {
3434                         LOGE("failed to get pad from sinkbin\n");
3435                         goto ERROR;
3436                 }
3437         } else if (strstr(name, "text")) {
3438                 if (player->pipeline->textbin == NULL) {
3439                         MMPlayerGstElement* mainbin = NULL;
3440
3441                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
3442                                 LOGE("failed to create textbin. continuing without text\n");
3443                                 goto ERROR;
3444                         }
3445
3446                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3447                         LOGD("creating textsink bin success\n");
3448
3449                         /* FIXIT : track number shouldn't be hardcoded */
3450                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3451
3452                         player->textsink_linked  = 1;
3453                         LOGI("player->textsink_linked set to 1\n");
3454
3455                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3456                         if (!sinkpad) {
3457                                 LOGE("failed to get pad from sinkbin\n");
3458                                 goto ERROR;
3459                         }
3460
3461                         mainbin = player->pipeline->mainbin;
3462
3463                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3464                                 /* input selector */
3465                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3466                                 if (!text_selector) {
3467                                         LOGE("failed to create subtitle input selector element\n");
3468                                         goto ERROR;
3469                                 }
3470                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3471
3472                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3473                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3474
3475                                 /* warm up */
3476                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3477                                         LOGE("failed to set state(READY) to sinkbin\n");
3478                                         goto ERROR;
3479                                 }
3480
3481                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3482                                         LOGW("failed to add subtitle input selector\n");
3483                                         goto ERROR;
3484                                 }
3485
3486                                 LOGD("created element input-selector");
3487
3488                         } else {
3489                                 LOGD("already having subtitle input selector");
3490                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3491                         }
3492                 } else {
3493                         if (!player->textsink_linked) {
3494                                 LOGD("re-using textbin\n");
3495
3496                                 reusing = TRUE;
3497                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3498
3499                                 player->textsink_linked  = 1;
3500                                 LOGI("player->textsink_linked set to 1\n");
3501                         } else
3502                                 LOGD("ignoring internal subtutle since external subtitle is available");
3503                 }
3504         } else {
3505                 LOGW("unknown type of elementary stream!ignoring it...\n");
3506                 goto ERROR;
3507         }
3508
3509         if (sinkbin) {
3510                 if (!reusing) {
3511                         /* warm up */
3512                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3513                                 LOGE("failed to set state(READY) to sinkbin\n");
3514                                 goto ERROR;
3515                         }
3516
3517                         /* Added for multi audio support to avoid adding audio bin again*/
3518                         /* add */
3519                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3520                                 LOGE("failed to add sinkbin to pipeline\n");
3521                                 goto ERROR;
3522                         }
3523                 }
3524
3525                 /* link */
3526                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3527                         LOGE("failed to get pad from sinkbin\n");
3528                         goto ERROR;
3529                 }
3530
3531                 if (!reusing) {
3532                         /* run */
3533                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3534                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3535                                 goto ERROR;
3536                         }
3537
3538                         if (text_selector) {
3539                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3540                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3541                                         goto ERROR;
3542                                 }
3543                         }
3544                 }
3545
3546                 gst_object_unref(sinkpad);
3547                 sinkpad = NULL;
3548         }
3549
3550         LOGD("linking sink bin success\n");
3551
3552         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3553          * streaming task. if the task blocked, then buffer will not flow to the next element
3554          *(autoplugging element). so this is special hack for streaming. please try to remove it
3555          */
3556         /* dec stream count. we can remove fakesink if it's zero */
3557         if (player->num_dynamic_pad)
3558                 player->num_dynamic_pad--;
3559
3560         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3561
3562         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3563                 __mmplayer_pipeline_complete(NULL, player);
3564
3565         /* FIXIT : please leave a note why this code is needed */
3566         if (MMPLAYER_IS_WFD_STREAMING(player))
3567                 player->no_more_pad = TRUE;
3568
3569 ERROR:
3570
3571         MMPLAYER_FREEIF(caps_str);
3572
3573         if (caps)
3574                 gst_caps_unref(caps);
3575
3576         if (sinkpad)
3577                 gst_object_unref(GST_OBJECT(sinkpad));
3578
3579         /* flusing out new attributes */
3580         if (mmf_attrs_commit(attrs))
3581                 LOGE("failed to comit attributes\n");
3582
3583         return;
3584 }
3585
3586 static gboolean
3587 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3588 {
3589         int pro_value = 0; // in the case of expection, default will be returned.
3590         int dest_angle = rotation_angle;
3591         int rotation_type = -1;
3592
3593         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3594         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3595         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3596
3597         if (rotation_angle >= 360)
3598                 dest_angle = rotation_angle - 360;
3599
3600         /* chech if supported or not */
3601         if (dest_angle % 90) {
3602                 LOGD("not supported rotation angle = %d", rotation_angle);
3603                 return FALSE;
3604         }
3605
3606         /*
3607           * xvimagesink only    (A)
3608           * custom_convert - no xv(e.g. memsink, evasimagesink  (B)
3609           * videoflip - avsysmemsink(C)
3610           */
3611         if (player->set_mode.video_zc) {
3612                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3613                         rotation_type = ROTATION_USING_CUSTOM;
3614                 else // A
3615                         rotation_type = ROTATION_USING_SINK;
3616         } else {
3617                 int surface_type = 0;
3618                 rotation_type = ROTATION_USING_FLIP;
3619
3620                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3621                 LOGD("check display surface type attribute: %d", surface_type);
3622
3623                 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) ||
3624                         (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink")))
3625                         rotation_type = ROTATION_USING_SINK;
3626                 else
3627                         rotation_type = ROTATION_USING_FLIP; //C
3628
3629                 LOGD("using %d type for rotation", rotation_type);
3630         }
3631
3632         /* get property value for setting */
3633         switch (rotation_type) {
3634         case ROTATION_USING_SINK: // xvimagesink, pixmap
3635                 {
3636                         switch (dest_angle) {
3637                         case 0:
3638                                 break;
3639                         case 90:
3640                                 pro_value = 3; // clockwise 90
3641                                 break;
3642                         case 180:
3643                                 pro_value = 2;
3644                                 break;
3645                         case 270:
3646                                 pro_value = 1; // counter-clockwise 90
3647                                 break;
3648                         }
3649                 }
3650                 break;
3651         case ROTATION_USING_CUSTOM:
3652                 {
3653                         gchar *ename = NULL;
3654                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3655
3656                         if (g_strrstr(ename, "fimcconvert")) {
3657                                 switch (dest_angle) {
3658                                 case 0:
3659                                         break;
3660                                 case 90:
3661                                         pro_value = 90; // clockwise 90
3662                                         break;
3663                                 case 180:
3664                                         pro_value = 180;
3665                                         break;
3666                                 case 270:
3667                                         pro_value = 270; // counter-clockwise 90
3668                                         break;
3669                                 }
3670                         }
3671                 }
3672                 break;
3673         case ROTATION_USING_FLIP: // videoflip
3674                 {
3675                                 switch (dest_angle) {
3676                                 case 0:
3677                                         break;
3678                                 case 90:
3679                                         pro_value = 1; // clockwise 90
3680                                         break;
3681                                 case 180:
3682                                         pro_value = 2;
3683                                         break;
3684                                 case 270:
3685                                         pro_value = 3; // counter-clockwise 90
3686                                         break;
3687                                 }
3688                 }
3689                 break;
3690         }
3691
3692         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3693
3694         *value = pro_value;
3695
3696         return TRUE;
3697 }
3698
3699 int
3700 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3701 {
3702         /* check video sinkbin is created */
3703         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3704                 player->pipeline &&
3705                 player->pipeline->videobin &&
3706                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3707                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3708                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3709
3710         return MM_ERROR_NONE;
3711 }
3712
3713 void
3714 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3715 {
3716         int rotation_value = 0;
3717         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3718         int user_angle = 0;
3719         MMPLAYER_FENTER();
3720
3721         /* check video sinkbin is created */
3722         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3723                 return;
3724
3725         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3726
3727         /* get rotation value to set */
3728         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3729         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3730         LOGD("set video param : rotate %d", rotation_value);
3731 }
3732
3733 void
3734 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3735 {
3736         MMHandleType attrs = 0;
3737         int visible = 0;
3738         MMPLAYER_FENTER();
3739
3740         /* check video sinkbin is created */
3741         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3742                 return;
3743
3744         attrs = MMPLAYER_GET_ATTRS(player);
3745         MMPLAYER_RETURN_IF_FAIL(attrs);
3746
3747         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3748         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3749         LOGD("set video param : visible %d", visible);
3750 }
3751
3752 void
3753 __mmplayer_video_param_set_display_method(mm_player_t* player)
3754 {
3755         MMHandleType attrs = 0;
3756         int display_method = 0;
3757         MMPLAYER_FENTER();
3758
3759         /* check video sinkbin is created */
3760         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3761                 return;
3762
3763         attrs = MMPLAYER_GET_ATTRS(player);
3764         MMPLAYER_RETURN_IF_FAIL(attrs);
3765
3766         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3767         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3768         LOGD("set video param : method %d", display_method);
3769 }
3770
3771 void
3772 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3773 {
3774         MMHandleType attrs = 0;
3775         int display_method = 0;
3776         void *handle = NULL;
3777         /*set wl_display*/
3778         int wl_window_x = 0;
3779         int wl_window_y = 0;
3780         int wl_window_width = 0;
3781         int wl_window_height = 0;
3782         MMPLAYER_FENTER();
3783
3784         /* check video sinkbin is created */
3785         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3786                 return;
3787
3788         attrs = MMPLAYER_GET_ATTRS(player);
3789         MMPLAYER_RETURN_IF_FAIL(attrs);
3790
3791         /* check roi mode is set */
3792         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3793         if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3794                 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3795                 return;
3796         }
3797         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3798
3799         if (handle) {
3800                 /*It should be set after setting window*/
3801                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3802                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3803                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3804                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3805
3806                 /* After setting window handle, set render      rectangle */
3807                 gst_video_overlay_set_render_rectangle(
3808                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3809                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3810                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3811                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3812
3813         }
3814 }
3815 void
3816 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3817 {
3818         MMHandleType attrs = 0;
3819         void *handle = NULL;
3820         /*use wl_surface*/
3821         gboolean use_wl_surface = 0;
3822         void * wl_display = NULL;
3823         GstContext *context = NULL;
3824
3825         /* check video sinkbin is created */
3826         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3827                 return;
3828
3829         attrs = MMPLAYER_GET_ATTRS(player);
3830         MMPLAYER_RETURN_IF_FAIL(attrs);
3831
3832         /* common case if using overlay surface */
3833         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3834         mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
3835
3836         if (handle && !use_wl_surface) {
3837                 /* default is using wl_surface_id */
3838                 unsigned int wl_surface_id      = 0;
3839                 wl_surface_id = *(int*)handle;
3840                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3841                 gst_video_overlay_set_wl_window_wl_surface_id(
3842                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3843                                 *(int*)handle);
3844         } else if (handle && use_wl_surface) {
3845                 /* use wl_surface for legacy_player_test */
3846                 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
3847                 if (wl_display)
3848                         context = gst_wayland_display_handle_context_new(wl_display);
3849                 if (context)
3850                         gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
3851
3852                 guintptr wl_surface = (guintptr)handle;
3853                 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
3854                 gst_video_overlay_set_window_handle(
3855                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3856                                 wl_surface);
3857         } else
3858                 /* FIXIT : is it error case? */
3859                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3860 }
3861
3862
3863 int
3864 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3865 {
3866         bool update_all_param = FALSE;
3867         MMPLAYER_FENTER();
3868
3869         /* check video sinkbin is created */
3870         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3871                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3872
3873         if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
3874                 LOGE("can not find waylandsink");
3875                 return MM_ERROR_PLAYER_INTERNAL;
3876         }
3877
3878         LOGD("param_name : %s", param_name);
3879         if (!g_strcmp0(param_name, "update_all_param"))
3880                 update_all_param = TRUE;
3881
3882         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3883                 __mmplayer_video_param_set_display_overlay(player);
3884         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3885                 __mmplayer_video_param_set_display_method(player);
3886         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3887                 __mmplayer_video_param_set_render_rectangle(player);
3888         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3889                 __mmplayer_video_param_set_display_visible(player);
3890         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3891                 __mmplayer_video_param_set_display_rotation(player);
3892
3893         return MM_ERROR_NONE;
3894 }
3895
3896 int
3897 __mmplayer_update_evas_videosink_video_param(mm_player_t* player)
3898 {
3899         MMHandleType attrs = 0;
3900         void *object = NULL;
3901         int scaling = 0;
3902         gboolean visible = TRUE;
3903         int display_method = 0;
3904         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3905         int user_angle = 0;
3906         int rotation_value = 0;
3907         MMPLAYER_FENTER();
3908
3909         /* check video sinkbin is created */
3910         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3911                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3912
3913         attrs = MMPLAYER_GET_ATTRS(player);
3914         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3915
3916         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3917
3918         /* common case if using evas surface */
3919         mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
3920         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3921         mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
3922         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3923
3924         /* if evasimagesink */
3925         if (!strcmp(player->ini.videosink_element_evas, "evasimagesink")) {
3926                 if (object) {
3927                         /* if it is evasimagesink, we are not supporting rotation */
3928                         if (user_angle != 0) {
3929                                 mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE);
3930                                 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3931                                         LOGE("failed to commit\n");
3932                                 LOGW("unsupported feature");
3933                                 return MM_ERROR_NOT_SUPPORT_API;
3934                         }
3935                         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3936                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3937                                         "evas-object", object,
3938                                         "visible", visible,
3939                                         "display-geometry-method", display_method,
3940                                         "rotate", rotation_value,
3941                                         NULL);
3942                         LOGD("set video param : method %d", display_method);
3943                         LOGD("set video param : evas-object %x, visible %d", object, visible);
3944                         LOGD("set video param : evas-object %x, rotate %d", object, rotation_value);
3945                 } else {
3946                         LOGE("no evas object");
3947                         return MM_ERROR_PLAYER_INTERNAL;
3948                 }
3949
3950
3951                 /* if evasimagesink using converter */
3952                 if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst) {
3953                         int width = 0;
3954                         int height = 0;
3955                         int no_scaling = !scaling;
3956
3957                         mm_attrs_get_int_by_name(attrs, "display_width", &width);
3958                         mm_attrs_get_int_by_name(attrs, "display_height", &height);
3959
3960                         /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
3961                         g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
3962                         g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL);
3963
3964                         if (no_scaling) {
3965                                 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
3966                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
3967                                                 "dst-width", 0, /* setting 0, output video width will be media src's width */
3968                                                 "dst-height", 0, /* setting 0, output video height will be media src's height */
3969                                                 NULL);
3970                         } else {
3971                                 /* scaling order to fimcconvert */
3972                                 if (width)
3973                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
3974                                 if (height)
3975                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
3976                                 LOGD("set video param : video frame scaling down to width(%d) height(%d)", width, height);
3977                         }
3978                         LOGD("set video param : display_evas_do_scaling %d", scaling);
3979                 }
3980         }
3981         return MM_ERROR_NONE;
3982 }
3983
3984 int
3985 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
3986 {
3987         MMHandleType attrs = 0;
3988         int surface_type = 0;
3989         int ret = MM_ERROR_NONE;
3990
3991         MMPLAYER_FENTER();
3992
3993         /* check video sinkbin is created */
3994         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3995                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3996
3997         attrs = MMPLAYER_GET_ATTRS(player);
3998         if (!attrs) {
3999                 LOGE("cannot get content attribute");
4000                 return MM_ERROR_PLAYER_INTERNAL;
4001         }
4002         LOGD("param_name : %s", param_name);
4003
4004         /* update display surface */
4005         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4006         LOGD("check display surface type attribute: %d", surface_type);
4007
4008         /* configuring display */
4009         switch (surface_type) {
4010         case MM_DISPLAY_SURFACE_OVERLAY:
4011                 {
4012                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4013                         if (ret != MM_ERROR_NONE)
4014                                 return ret;
4015                 }
4016                 break;
4017         case MM_DISPLAY_SURFACE_EVAS:
4018                 {
4019                         ret = __mmplayer_update_evas_videosink_video_param(player);
4020                         if (ret != MM_ERROR_NONE)
4021                                 return ret;
4022                 }
4023                 break;
4024         case MM_DISPLAY_SURFACE_NULL:
4025                 {
4026                         /* do nothing */
4027                 }
4028                 break;
4029         case MM_DISPLAY_SURFACE_REMOTE:
4030                 {
4031                         /* do nothing */
4032                 }
4033                 break;
4034         }
4035
4036         MMPLAYER_FLEAVE();
4037
4038         return MM_ERROR_NONE;
4039 }
4040
4041 static int
4042 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4043 {
4044         GList* bucket = element_bucket;
4045         MMPlayerGstElement* element = NULL;
4046         MMPlayerGstElement* prv_element = NULL;
4047         gint successful_link_count = 0;
4048
4049         MMPLAYER_FENTER();
4050
4051         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4052
4053         prv_element = (MMPlayerGstElement*)bucket->data;
4054         bucket = bucket->next;
4055
4056         for (; bucket; bucket = bucket->next) {
4057                 element = (MMPlayerGstElement*)bucket->data;
4058
4059                 if (element && element->gst) {
4060                         /* If next element is audio appsrc then make a separate audio pipeline */
4061                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4062                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4063                                 prv_element = element;
4064                                 continue;
4065                         }
4066
4067                         if (prv_element && prv_element->gst) {
4068                                 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4069                                         LOGD("linking [%s] to [%s] success\n",
4070                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4071                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4072                                         successful_link_count++;
4073                                 } else {
4074                                         LOGD("linking [%s] to [%s] failed\n",
4075                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4076                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4077                                         return -1;
4078                                 }
4079                         }
4080                 }
4081
4082                 prv_element = element;
4083         }
4084
4085         MMPLAYER_FLEAVE();
4086
4087         return successful_link_count;
4088 }
4089
4090 static int
4091 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4092 {
4093         GList* bucket = element_bucket;
4094         MMPlayerGstElement* element = NULL;
4095         int successful_add_count = 0;
4096
4097         MMPLAYER_FENTER();
4098
4099         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4100         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4101
4102         for (; bucket; bucket = bucket->next) {
4103                 element = (MMPlayerGstElement*)bucket->data;
4104
4105                 if (element && element->gst) {
4106                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4107                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4108                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4109                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4110                                 return 0;
4111                         }
4112                         successful_add_count++;
4113                 }
4114         }
4115
4116         MMPLAYER_FLEAVE();
4117
4118         return successful_add_count;
4119 }
4120
4121 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4122 {
4123         mm_player_t* player = (mm_player_t*) data;
4124         GstCaps *caps = NULL;
4125         GstStructure *str = NULL;
4126         const char *name;
4127
4128         MMPLAYER_FENTER();
4129
4130         MMPLAYER_RETURN_IF_FAIL(pad)
4131         MMPLAYER_RETURN_IF_FAIL(unused)
4132         MMPLAYER_RETURN_IF_FAIL(data)
4133
4134         caps = gst_pad_get_current_caps(pad);
4135         if (!caps)
4136                 return;
4137
4138         str = gst_caps_get_structure(caps, 0);
4139         if (!str)
4140                 goto ERROR;
4141
4142         name = gst_structure_get_name(str);
4143         if (!name)
4144                 goto ERROR;
4145
4146         LOGD("name = %s\n", name);
4147
4148         if (strstr(name, "audio")) {
4149                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4150
4151                 if (player->audio_stream_changed_cb) {
4152                         LOGE("call the audio stream changed cb\n");
4153                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4154                 }
4155         } else if (strstr(name, "video")) {
4156                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4157
4158                 if (player->video_stream_changed_cb) {
4159                         LOGE("call the video stream changed cb\n");
4160                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4161                 }
4162         } else
4163                 goto ERROR;
4164
4165 ERROR:
4166
4167         gst_caps_unref(caps);
4168
4169         MMPLAYER_FLEAVE();
4170
4171         return;
4172 }
4173
4174
4175
4176 /**
4177  * This function is to create audio pipeline for playing.
4178  *
4179  * @param       player          [in]    handle of player
4180  *
4181  * @return      This function returns zero on success.
4182  * @remark
4183  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4184  */
4185 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4186 x_bin[x_id].id = x_id;\
4187 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4188 if (!x_bin[x_id].gst) {\
4189         LOGE("failed to create %s \n", x_factory);\
4190         goto ERROR;\
4191 } \
4192
4193 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4194 x_bin[x_id].id = x_id;\
4195 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4196 if (!x_bin[x_id].gst) {\
4197         LOGE("failed to create %s \n", x_factory);\
4198         goto ERROR;\
4199 } else {\
4200         if (x_player->ini.set_dump_element_flag)\
4201                 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4202 } \
4203 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4204         LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",\
4205                 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4206                 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4207         goto ERROR;\
4208 } \
4209
4210 /* macro for code readability. just for sinkbin-creation functions */
4211 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4212 do {\
4213         x_bin[x_id].id = x_id;\
4214         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4215         if (!x_bin[x_id].gst) {\
4216                 LOGE("failed to create %s \n", x_factory);\
4217                 goto ERROR;\
4218         } else {\
4219                 if (x_player->ini.set_dump_element_flag)\
4220                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4221         } \
4222         if (x_add_bucket)\
4223                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4224 } while (0);
4225
4226 static void
4227 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4228 {
4229         GList *l = NULL;
4230
4231         MMPLAYER_FENTER();
4232         MMPLAYER_RETURN_IF_FAIL(player);
4233
4234         if (player->audio_stream_buff_list) {
4235                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4236                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4237                         if (tmp) {
4238                                 if (send_all) {
4239                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4240                                         __mmplayer_audio_stream_send_data(player, tmp);
4241                                 }
4242                                 if (tmp->pcm_data)
4243                                         g_free(tmp->pcm_data);
4244                                 g_free(tmp);
4245                         }
4246                 }
4247                 g_list_free(player->audio_stream_buff_list);
4248                 player->audio_stream_buff_list = NULL;
4249         }
4250
4251         MMPLAYER_FLEAVE();
4252 }
4253
4254 static void
4255 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4256 {
4257         MMPlayerAudioStreamDataType audio_stream = { 0, };
4258
4259         MMPLAYER_FENTER();
4260         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4261
4262         audio_stream.bitrate = a_buffer->bitrate;
4263         audio_stream.channel = a_buffer->channel;
4264         audio_stream.depth = a_buffer->depth;
4265         audio_stream.is_little_endian = a_buffer->is_little_endian;
4266         audio_stream.channel_mask = a_buffer->channel_mask;
4267         audio_stream.data_size = a_buffer->data_size;
4268         audio_stream.data = a_buffer->pcm_data;
4269
4270         LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param);
4271         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4272
4273         MMPLAYER_FLEAVE();
4274 }
4275
4276 static void
4277 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4278 {
4279         mm_player_t* player = (mm_player_t*) data;
4280
4281         gint channel = 0;
4282         gint rate = 0;
4283         gint depth = 0;
4284         gint endianness = 0;
4285         guint64 channel_mask = 0;
4286         void *a_data = NULL;
4287         gint a_size = 0;
4288         mm_player_audio_stream_buff_t *a_buffer = NULL;
4289         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4290         GList *l = NULL;
4291
4292         MMPLAYER_FENTER();
4293         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4294
4295         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4296         a_data = mapinfo.data;
4297         a_size = mapinfo.size;
4298
4299         GstCaps *caps = gst_pad_get_current_caps(pad);
4300         GstStructure *structure = gst_caps_get_structure(caps, 0);
4301
4302         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4303         gst_structure_get_int(structure, "rate", &rate);
4304         gst_structure_get_int(structure, "channels", &channel);
4305         gst_structure_get_int(structure, "depth", &depth);
4306         gst_structure_get_int(structure, "endianness", &endianness);
4307         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4308         gst_caps_unref(GST_CAPS(caps));
4309
4310         /* In case of the sync is false, use buffer list.              *
4311          * The num of buffer list depends on the num of audio channels */
4312         if (player->audio_stream_buff_list) {
4313                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4314                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4315                         if (tmp) {
4316                                 if (channel_mask == tmp->channel_mask) {
4317                                         LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
4318
4319                                         if (tmp->data_size + a_size < tmp->buff_size) {
4320                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4321                                                 tmp->data_size += a_size;
4322                                         } else {
4323                                                 /* send data to client */
4324                                                 __mmplayer_audio_stream_send_data(player, tmp);
4325
4326                                                 if (a_size > tmp->buff_size) {
4327                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4328                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4329                                                         if (tmp->pcm_data == NULL) {
4330                                                                 LOGE("failed to realloc data.");
4331                                                                 goto DONE;
4332                                                         }
4333                                                         tmp->buff_size = a_size;
4334                                                 }
4335                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4336                                                 memcpy(tmp->pcm_data, a_data, a_size);
4337                                                 tmp->data_size = a_size;
4338                                         }
4339                                         goto DONE;
4340                                 }
4341                         } else {
4342                                 LOGE("data is empty in list.");
4343                                 goto DONE;
4344                         }
4345                 }
4346         }
4347
4348         /* create new audio stream data */
4349         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4350         if (a_buffer == NULL) {
4351                 LOGE("failed to alloc data.");
4352                 goto DONE;
4353         }
4354         a_buffer->bitrate = rate;
4355         a_buffer->channel = channel;
4356         a_buffer->depth = depth;
4357         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4358         a_buffer->channel_mask = channel_mask;
4359         a_buffer->data_size = a_size;
4360
4361         if (!player->audio_stream_sink_sync) {
4362                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4363                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4364                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4365                 if (a_buffer->pcm_data == NULL) {
4366                         LOGE("failed to alloc data.");
4367                         g_free(a_buffer);
4368                         goto DONE;
4369                 }
4370                 memcpy(a_buffer->pcm_data, a_data, a_size);
4371                 LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
4372                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4373         } else {
4374                 /* If sync is TRUE, send data directly. */
4375                 a_buffer->pcm_data = a_data;
4376                 __mmplayer_audio_stream_send_data(player, a_buffer);
4377                 g_free(a_buffer);
4378         }
4379
4380 DONE:
4381         gst_buffer_unmap(buffer, &mapinfo);
4382         MMPLAYER_FLEAVE();
4383 }
4384
4385 static void
4386 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4387 {
4388         mm_player_t* player = (mm_player_t*)data;
4389         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4390         GstPad* sinkpad = NULL;
4391         GstElement *queue = NULL, *sink = NULL;
4392
4393         MMPLAYER_FENTER();
4394         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4395
4396         queue = gst_element_factory_make("queue", NULL);
4397         if (queue == NULL) {
4398                 LOGD("fail make queue\n");
4399                 goto ERROR;
4400         }
4401
4402         sink = gst_element_factory_make("fakesink", NULL);
4403         if (sink == NULL) {
4404                 LOGD("fail make fakesink\n");
4405                 goto ERROR;
4406         }
4407
4408         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4409
4410         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4411                 LOGW("failed to link queue & sink\n");
4412                 goto ERROR;
4413         }
4414
4415         sinkpad = gst_element_get_static_pad(queue, "sink");
4416
4417         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4418                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4419                 goto ERROR;
4420         }
4421
4422         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4423
4424         gst_object_unref(sinkpad);
4425         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4426         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4427
4428         gst_element_set_state(sink, GST_STATE_PAUSED);
4429         gst_element_set_state(queue, GST_STATE_PAUSED);
4430
4431         MMPLAYER_SIGNAL_CONNECT(player,
4432                 G_OBJECT(sink),
4433                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4434                 "handoff",
4435                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4436                 (gpointer)player);
4437
4438         MMPLAYER_FLEAVE();
4439         return ;
4440
4441 ERROR:
4442         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4443         if (queue) {
4444                 gst_object_unref(GST_OBJECT(queue));
4445                 queue = NULL;
4446         }
4447         if (sink) {
4448                 gst_object_unref(GST_OBJECT(sink));
4449                 sink = NULL;
4450         }
4451         if (sinkpad) {
4452                 gst_object_unref(GST_OBJECT(sinkpad));
4453                 sinkpad = NULL;
4454         }
4455
4456         return;
4457 }
4458
4459 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4460 {
4461         #define MAX_PROPS_LEN 64
4462         gint latency_mode = 0;
4463         gchar *stream_type = NULL;
4464         gchar *latency = NULL;
4465         gint stream_id = 0;
4466         gchar stream_props[MAX_PROPS_LEN] = {0,};
4467         GstStructure *props = NULL;
4468
4469         /* set volume table
4470          * It should be set after player creation through attribute.
4471          * But, it can not be changed during playing.
4472          */
4473         MMPLAYER_FENTER();
4474         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4475         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4476
4477         if (!stream_type) {
4478                 LOGE("stream_type is null.\n");
4479         } else {
4480                 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4481                 props = gst_structure_from_string(stream_props, NULL);
4482                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4483                 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4484         }
4485
4486         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4487
4488         switch (latency_mode) {
4489         case AUDIO_LATENCY_MODE_LOW:
4490                 latency = g_strndup("low", 3);
4491                 break;
4492         case AUDIO_LATENCY_MODE_MID:
4493                 latency = g_strndup("mid", 3);
4494                 break;
4495         case AUDIO_LATENCY_MODE_HIGH:
4496                 latency = g_strndup("high", 4);
4497                 break;
4498         };
4499
4500 #if 0 //need to check
4501         if (player->sound_focus.user_route_policy != 0)
4502                 route_path = player->sound_focus.user_route_policy;
4503
4504         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4505                         "latency", latency_mode,
4506                         NULL);
4507
4508         LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4509                 volume_type, route_path, latency_mode);
4510         MMPLAYER_FLEAVE();
4511
4512 #endif
4513
4514         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4515                         "latency", latency,
4516                         NULL);
4517
4518         LOGD("audiosink property - latency=%s \n", latency);
4519
4520         g_free(latency);
4521
4522         MMPLAYER_FLEAVE();
4523 }
4524
4525 static int
4526 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4527 {
4528         MMPlayerGstElement* first_element = NULL;
4529         MMPlayerGstElement* audiobin = NULL;
4530         MMHandleType attrs = 0;
4531         GstPad *pad = NULL;
4532         GstPad *ghostpad = NULL;
4533         GList* element_bucket = NULL;
4534         gboolean link_audio_sink_now = TRUE;
4535         int i = 0;
4536
4537         MMPLAYER_FENTER();
4538
4539         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4540
4541         /* alloc handles */
4542         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4543         if (!audiobin) {
4544                 LOGE("failed to allocate memory for audiobin\n");
4545                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4546         }
4547
4548         attrs = MMPLAYER_GET_ATTRS(player);
4549
4550         /* create bin */
4551         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4552         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4553         if (!audiobin[MMPLAYER_A_BIN].gst) {
4554                 LOGE("failed to create audiobin\n");
4555                 goto ERROR;
4556         }
4557
4558         /* take it */
4559         player->pipeline->audiobin = audiobin;
4560
4561         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4562
4563         /* Adding audiotp plugin for reverse trickplay feature */
4564 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4565
4566         /* converter */
4567         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4568
4569         /* resampler */
4570         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4571
4572         if (player->set_mode.pcm_extraction) {
4573                 // pcm extraction only and no sound output
4574                 if (player->audio_stream_render_cb_ex) {
4575                         char *caps_str = NULL;
4576                         GstCaps* caps = NULL;
4577                         gchar *format = NULL;
4578
4579                         /* capsfilter */
4580                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4581
4582                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4583
4584                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4585
4586                         caps = gst_caps_new_simple("audio/x-raw",
4587                                         "format", G_TYPE_STRING, format,
4588                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4589                                         "channels", G_TYPE_INT, player->pcm_channel,
4590                                         NULL);
4591                         caps_str = gst_caps_to_string(caps);
4592                         LOGD("new caps : %s\n", caps_str);
4593
4594                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4595
4596                         /* clean */
4597                         gst_caps_unref(caps);
4598                         MMPLAYER_FREEIF(caps_str);
4599
4600                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4601
4602                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4603                         /* raw pad handling signal */
4604                         MMPLAYER_SIGNAL_CONNECT(player,
4605                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4606                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4607                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4608                 } else {
4609                         int dst_samplerate = 0;
4610                         int dst_channels = 0;
4611                         int dst_depth = 0;
4612                         char *caps_str = NULL;
4613                         GstCaps* caps = NULL;
4614
4615                         /* get conf. values */
4616                         mm_attrs_multiple_get(player->attrs,
4617                                                 NULL,
4618                                                 "pcm_extraction_samplerate", &dst_samplerate,
4619                                                 "pcm_extraction_channels", &dst_channels,
4620                                                 "pcm_extraction_depth", &dst_depth,
4621                                                 NULL);
4622
4623                         /* capsfilter */
4624                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4625                         caps = gst_caps_new_simple("audio/x-raw",
4626                                         "rate", G_TYPE_INT, dst_samplerate,
4627                                         "channels", G_TYPE_INT, dst_channels,
4628                                         "depth", G_TYPE_INT, dst_depth,
4629                                         NULL);
4630                         caps_str = gst_caps_to_string(caps);
4631                         LOGD("new caps : %s\n", caps_str);
4632
4633                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4634
4635                         /* clean */
4636                         gst_caps_unref(caps);
4637                         MMPLAYER_FREEIF(caps_str);
4638
4639                         /* fake sink */
4640                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4641
4642                         /* set sync */
4643                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4644                 }
4645         } else {
4646                 // normal playback
4647                 //GstCaps* caps = NULL;
4648                 gint channels = 0;
4649
4650                 /* for logical volume control */
4651                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4652                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4653
4654                 if (player->sound.mute) {
4655                         LOGD("mute enabled\n");
4656                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4657                 }
4658
4659 #if 0
4660                 /*capsfilter */
4661                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4662                 caps = gst_caps_from_string("audio/x-raw-int, "
4663                                         "endianness = (int) LITTLE_ENDIAN, "
4664                                         "signed = (boolean) true, "
4665                                         "width = (int) 16, "
4666                                         "depth = (int) 16");
4667                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4668                 gst_caps_unref(caps);
4669 #endif
4670
4671                 /* chech if multi-chennels */
4672                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4673                         GstPad *srcpad = NULL;
4674                         GstCaps *caps = NULL;
4675
4676                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4677                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4678                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4679                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4680                                         if (str)
4681                                                 gst_structure_get_int(str, "channels", &channels);
4682                                         gst_caps_unref(caps);
4683                                 }
4684                                 gst_object_unref(srcpad);
4685                         }
4686                 }
4687
4688                 /* audio effect element. if audio effect is enabled */
4689                 if ((strcmp(player->ini.audioeffect_element, ""))
4690                         && (channels <= 2)
4691                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4692                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4693
4694                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4695
4696                         if ((!player->bypass_audio_effect)
4697                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4698                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4699                                         if (!_mmplayer_audio_effect_custom_apply(player))
4700                                                 LOGI("apply audio effect(custom) setting success\n");
4701                                 }
4702                         }
4703
4704                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4705                                 && (player->set_mode.rich_audio))
4706                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4707                 }
4708                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4709                         if (player->set_mode.rich_audio && channels <= 2)
4710                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4711                 }
4712
4713                 /* create audio sink */
4714                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4715
4716                 /* qos on */
4717                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4718                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4719
4720                 if (player->videodec_linked && player->ini.use_system_clock) {
4721                         LOGD("system clock will be used.\n");
4722                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4723                 }
4724
4725                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4726                         __mmplayer_gst_set_audiosink_property(player, attrs);
4727         }
4728
4729         if (audiobin[MMPLAYER_A_SINK].gst) {
4730                 GstPad *sink_pad = NULL;
4731                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4732                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4733                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4734                 gst_object_unref(GST_OBJECT(sink_pad));
4735         }
4736
4737         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4738
4739         /* adding created elements to bin */
4740         LOGD("adding created elements to bin\n");
4741         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4742                 LOGE("failed to add elements\n");
4743                 goto ERROR;
4744         }
4745
4746         /* linking elements in the bucket by added order. */
4747         LOGD("Linking elements in the bucket by added order.\n");
4748         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4749                 LOGE("failed to link elements\n");
4750                 goto ERROR;
4751         }
4752
4753         /* get first element's sinkpad for creating ghostpad */
4754         first_element = (MMPlayerGstElement *)element_bucket->data;
4755         if (!first_element) {
4756                 LOGE("failed to get first elem\n");
4757                 goto ERROR;
4758         }
4759
4760         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4761         if (!pad) {
4762                 LOGE("failed to get pad from first element of audiobin\n");
4763                 goto ERROR;
4764         }
4765
4766         ghostpad = gst_ghost_pad_new("sink", pad);
4767         if (!ghostpad) {
4768                 LOGE("failed to create ghostpad\n");
4769                 goto ERROR;
4770         }
4771
4772         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4773                 LOGE("failed to add ghostpad to audiobin\n");
4774                 goto ERROR;
4775         }
4776
4777         gst_object_unref(pad);
4778
4779         g_list_free(element_bucket);
4780
4781         mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4782
4783         MMPLAYER_FLEAVE();
4784
4785         return MM_ERROR_NONE;
4786
4787 ERROR:
4788
4789         LOGD("ERROR : releasing audiobin\n");
4790
4791         if (pad)
4792                 gst_object_unref(GST_OBJECT(pad));
4793
4794         if (ghostpad)
4795                 gst_object_unref(GST_OBJECT(ghostpad));
4796
4797         if (element_bucket)
4798                 g_list_free(element_bucket);
4799
4800         /* release element which are not added to bin */
4801         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4802                 /* NOTE : skip bin */
4803                 if (audiobin[i].gst) {
4804                         GstObject* parent = NULL;
4805                         parent = gst_element_get_parent(audiobin[i].gst);
4806
4807                         if (!parent) {
4808                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4809                                 audiobin[i].gst = NULL;
4810                         } else
4811                                 gst_object_unref(GST_OBJECT(parent));
4812                 }
4813         }
4814
4815         /* release audiobin with it's childs */
4816         if (audiobin[MMPLAYER_A_BIN].gst)
4817                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4818
4819         MMPLAYER_FREEIF(audiobin);
4820
4821         player->pipeline->audiobin = NULL;
4822
4823         return MM_ERROR_PLAYER_INTERNAL;
4824 }
4825
4826 static GstPadProbeReturn
4827 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4828 {
4829         mm_player_t* player = (mm_player_t*) u_data;
4830         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4831         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4832
4833         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4834
4835         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4836                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4837
4838         return GST_PAD_PROBE_OK;
4839 }
4840
4841 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4842 {
4843         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4844 }
4845
4846 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4847 {
4848         int ret = MM_ERROR_NONE;
4849         GList *l = NULL;
4850         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4851         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4852
4853         MMPLAYER_VIDEO_BO_LOCK(player);
4854
4855         if (player->video_bo_list) {
4856                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4857                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4858                         if (tmp && tmp->bo == bo) {
4859                                 tmp->using = FALSE;
4860                                 LOGD("release bo %p", bo);
4861                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4862                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4863                                 return ret;
4864                         }
4865                 }
4866         } else {
4867                 /* hw codec is running or the list was reset for DRC. */
4868                 LOGW("there is no bo list.");
4869         }
4870         MMPLAYER_VIDEO_BO_UNLOCK(player);
4871
4872         LOGW("failed to find bo %p", bo);
4873         return ret;
4874 }
4875
4876 static void
4877 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4878 {
4879         GList *l = NULL;
4880
4881         MMPLAYER_FENTER();
4882         MMPLAYER_RETURN_IF_FAIL(player);
4883
4884         MMPLAYER_VIDEO_BO_LOCK(player);
4885         if (player->video_bo_list) {
4886                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4887                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4888                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4889                         if (tmp) {
4890                                 if (tmp->bo)
4891                                         tbm_bo_unref(tmp->bo);
4892                                 g_free(tmp);
4893                         }
4894                 }
4895                 g_list_free(player->video_bo_list);
4896                 player->video_bo_list = NULL;
4897         }
4898         player->video_bo_size = 0;
4899         MMPLAYER_VIDEO_BO_UNLOCK(player);
4900
4901         MMPLAYER_FLEAVE();
4902         return;
4903 }
4904
4905 static void*
4906 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4907 {
4908         GList *l = NULL;
4909         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4910         gboolean ret = TRUE;
4911
4912         /* check DRC, if it is, destroy the prev bo list to create again */
4913         if (player->video_bo_size != size) {
4914                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4915                 __mmplayer_video_stream_destroy_bo_list(player);
4916                 player->video_bo_size = size;
4917         }
4918
4919         MMPLAYER_VIDEO_BO_LOCK(player);
4920
4921         if ((!player->video_bo_list) ||
4922                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4923
4924                 /* create bo list */
4925                 int idx = 0;
4926                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4927
4928                 if (player->video_bo_list) {
4929                         /* if bo list did not created all, try it again. */
4930                         idx = g_list_length(player->video_bo_list);
4931                         LOGD("bo list exist(len: %d)", idx);
4932                 }
4933
4934                 for (; idx < player->ini.num_of_video_bo; idx++) {
4935                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4936                         if (!bo_info) {
4937                                 LOGE("Fail to alloc bo_info.");
4938                                 break;
4939                         }
4940                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4941                         if (!bo_info->bo) {
4942                                 LOGE("Fail to tbm_bo_alloc.");
4943                                 g_free(bo_info);
4944                                 break;
4945                         }
4946                         bo_info->using = FALSE;
4947                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4948                 }
4949
4950                 /* update video num buffers */
4951                 player->video_num_buffers = idx;
4952                 if (idx == player->ini.num_of_video_bo)
4953                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4954
4955                 if (idx == 0) {
4956                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4957                         return NULL;
4958                 }
4959
4960                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4961         }
4962
4963         while (TRUE) {
4964                 /* get bo from list*/
4965                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4966                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4967                         if (tmp && (tmp->using == FALSE)) {
4968                                 LOGD("found bo %p to use", tmp->bo);
4969                                 tmp->using = TRUE;
4970                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4971                                 return tmp->bo;
4972                         }
4973                 }
4974                 if (!ret) {
4975                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4976                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4977                         return NULL;
4978                 }
4979
4980                 if (player->ini.video_bo_timeout <= 0) {
4981                         MMPLAYER_VIDEO_BO_WAIT(player);
4982                 } else {
4983                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4984                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4985                 }
4986                 continue;
4987         }
4988 }
4989 static void
4990 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4991 {
4992         mm_player_t* player = (mm_player_t*)data;
4993         MMPLAYER_FENTER();
4994         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4995
4996         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4997
4998         /* not to send prerolled pkt again */
4999         player->video_stream_prerolled = TRUE;
5000 }
5001
5002 static void
5003 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5004 {
5005         mm_player_t* player = (mm_player_t*)data;
5006         GstCaps *caps = NULL;
5007         MMPlayerVideoStreamDataType stream;
5008         MMVideoBuffer *video_buffer = NULL;
5009         GstMemory *dataBlock = NULL;
5010         GstMemory *metaBlock = NULL;
5011         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5012         GstStructure *structure = NULL;
5013         const gchar *string_format = NULL;
5014         unsigned int fourcc = 0;
5015
5016         MMPLAYER_FENTER();
5017         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5018
5019         if (player->video_stream_prerolled) {
5020                 player->video_stream_prerolled = FALSE;
5021                 LOGD("skip the prerolled pkt not to send it again");
5022                 return;
5023         }
5024
5025         caps = gst_pad_get_current_caps(pad);
5026         if (caps == NULL) {
5027                 LOGE("Caps is NULL.");
5028                 return;
5029         }
5030
5031         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5032
5033         /* clear stream data structure */
5034         memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5035
5036         structure = gst_caps_get_structure(caps, 0);
5037         gst_structure_get_int(structure, "width", & (stream.width));
5038         gst_structure_get_int(structure, "height", & (stream.height));
5039         string_format = gst_structure_get_string(structure, "format");
5040         if (string_format)
5041                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5042         stream.format = util_get_pixtype(fourcc);
5043         gst_caps_unref(caps);
5044         caps = NULL;
5045
5046     /*
5047         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5048                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5049     */
5050
5051         if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5052                 LOGE("Wrong condition!!");
5053                 return;
5054         }
5055
5056         /* set size and timestamp */
5057         dataBlock = gst_buffer_peek_memory(buffer, 0);
5058         stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5059         stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5060
5061         /* check zero-copy */
5062         if (player->set_mode.video_zc &&
5063                 player->set_mode.media_packet_video_stream &&
5064                 gst_buffer_n_memory(buffer) > 1) {
5065                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5066                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5067                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5068         }
5069
5070         if (video_buffer) { /* hw codec */
5071                 /* set tbm bo */
5072                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5073                         /* copy pointer of tbm bo, stride, elevation */
5074                         memcpy(stream.bo, video_buffer->handle.bo,
5075                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5076                 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5077                         /* FIXME: need to check this path */
5078                         memcpy(stream.data, video_buffer->data,
5079                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5080                 }
5081                 memcpy(stream.stride, video_buffer->stride_width,
5082                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5083                 memcpy(stream.elevation, video_buffer->stride_height,
5084                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5085                 /* set gst buffer */
5086                 stream.internal_buffer = buffer;
5087         } else { /* sw codec */
5088                 tbm_bo_handle thandle;
5089                 int stride = GST_ROUND_UP_4(stream.width);
5090                 int elevation = GST_ROUND_UP_2(stream.height);
5091                 int size = 0;
5092
5093                 gboolean gst_ret;
5094                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5095                 if (!gst_ret) {
5096                         LOGE("fail to gst_memory_map");
5097                         return;
5098                 }
5099
5100                 stream.stride[0] = stride;
5101                 stream.elevation[0] = elevation;
5102                 if (stream.format == MM_PIXEL_FORMAT_I420) {
5103                         stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5104                         stream.elevation[1] = stream.elevation[2] = elevation / 2;
5105                 } else {
5106                         LOGE("Not support format %d", stream.format);
5107                         gst_memory_unmap(dataBlock, &mapinfo);
5108                         return;
5109                 }
5110
5111                 size = (stream.stride[0] + stream.stride[1]) * elevation;
5112                 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5113                 if (!stream.bo[0]) {
5114                         LOGE("Fail to tbm_bo_alloc!!");
5115                         gst_memory_unmap(dataBlock, &mapinfo);
5116                         return;
5117                 }
5118                 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5119                 if (thandle.ptr && mapinfo.data)
5120                         memcpy(thandle.ptr, mapinfo.data, size);
5121                 else
5122                         LOGE("data pointer is wrong. dest : %p, src : %p",
5123                                         thandle.ptr, mapinfo.data);
5124                 tbm_bo_unmap(stream.bo[0]);
5125         }
5126
5127         if (player->video_stream_cb)
5128                 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5129
5130         if (metaBlock)
5131                 gst_memory_unmap(metaBlock, &mapinfo);
5132         else
5133                 gst_memory_unmap(dataBlock, &mapinfo);
5134
5135         return;
5136 }
5137
5138 static int
5139 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5140 {
5141         MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5142         gchar* video_csc = "videoconvert"; // default colorspace converter
5143         GList* element_bucket = *bucket;
5144
5145         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5146
5147         MMPLAYER_FENTER();
5148
5149         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5150
5151         if (player->set_mode.video_zc) {
5152                 /* ST12 or SN12 , if player use omx, evasimagesink doesn't use videoconvert */
5153                 if ((surface_type == MM_DISPLAY_SURFACE_EVAS) && (!strcmp(player->ini.videosink_element_evas, "evasimagesink")))
5154                         video_csc = player->ini.videoconverter_element;
5155                 else
5156                         video_csc = ""; /* Videosinks don't use videoconvert except evasimagesink which use  normal video formats */
5157         } else {
5158                 /* sw codec, if player use libav,  waylandsink need videoconvert  to render shm wl-buffer which support RGB only */
5159                 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5160                         video_csc = "videoconvert";
5161         }
5162         if (video_csc && (strcmp(video_csc, ""))) {
5163                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5164                 LOGD("using video converter: %s", video_csc);
5165         }
5166
5167         /* set video rotator */
5168         if (!player->set_mode.video_zc)
5169                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5170
5171         /* videoscaler */
5172         #if !defined(__arm__)
5173         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player);
5174         #endif
5175
5176         *bucket = element_bucket;
5177         MMPLAYER_FLEAVE();
5178         return MM_ERROR_NONE;
5179
5180 ERROR:
5181         *bucket = NULL;
5182         MMPLAYER_FLEAVE();
5183         return MM_ERROR_PLAYER_INTERNAL;
5184 }
5185
5186 /**
5187  * This function is to create video pipeline.
5188  *
5189  * @param       player          [in]    handle of player
5190  *              caps            [in]    src caps of decoder
5191  *              surface_type    [in]    surface type for video rendering
5192  *
5193  * @return      This function returns zero on success.
5194  * @remark
5195  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5196  */
5197 /**
5198   * VIDEO PIPELINE
5199   * - video overlay surface(arm/x86) : waylandsink
5200   * - evas surface (arm) : evaspixmapsink
5201   *                         fimcconvert !evasimagesink
5202   * - evas surface (x86) : videoconvertor !videoflip !evasimagesink
5203   */
5204 static int
5205 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5206 {
5207         GstPad *pad = NULL;
5208         MMHandleType attrs;
5209         GList*element_bucket = NULL;
5210         MMPlayerGstElement* first_element = NULL;
5211         MMPlayerGstElement* videobin = NULL;
5212         gchar *videosink_element = NULL;
5213
5214         MMPLAYER_FENTER();
5215
5216         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5217
5218         /* alloc handles */
5219         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5220         if (!videobin)
5221                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5222
5223         player->pipeline->videobin = videobin;
5224
5225         attrs = MMPLAYER_GET_ATTRS(player);
5226         if (!attrs) {
5227                 LOGE("cannot get content attribute");
5228                 return MM_ERROR_PLAYER_INTERNAL;
5229         }
5230
5231         /* create bin */
5232         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5233         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5234         if (!videobin[MMPLAYER_V_BIN].gst) {
5235                 LOGE("failed to create videobin");
5236                 goto ERROR;
5237         }
5238
5239         if (!player->set_mode.media_packet_video_stream) {
5240                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5241                         goto ERROR;
5242         }
5243
5244         /* set video sink */
5245         switch (surface_type) {
5246         case MM_DISPLAY_SURFACE_OVERLAY:
5247                 if (strlen(player->ini.videosink_element_overlay) > 0)
5248                         videosink_element = player->ini.videosink_element_overlay;
5249                 else
5250                         goto ERROR;
5251                 break;
5252         case MM_DISPLAY_SURFACE_EVAS:
5253                 if (strlen(player->ini.videosink_element_evas) > 0)
5254                         videosink_element = player->ini.videosink_element_evas;
5255                 else
5256                         goto ERROR;
5257                 break;
5258         case MM_DISPLAY_SURFACE_NULL:
5259                 if (strlen(player->ini.videosink_element_fake) > 0)
5260                         videosink_element = player->ini.videosink_element_fake;
5261                 else
5262                         goto ERROR;
5263                 break;
5264         case MM_DISPLAY_SURFACE_REMOTE:
5265                 if (strlen(player->ini.videosink_element_fake) > 0)
5266                         videosink_element = player->ini.videosink_element_fake;
5267                 else
5268                         goto ERROR;
5269                 break;
5270         default:
5271                 LOGE("unidentified surface type");
5272                 goto ERROR;
5273         }
5274         LOGD("selected videosink name: %s", videosink_element);
5275
5276         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5277
5278         /* additional setting for sink plug-in */
5279         switch (surface_type) {
5280         case MM_DISPLAY_SURFACE_OVERLAY:
5281         {
5282                 bool use_tbm = player->set_mode.video_zc;
5283                 if (!use_tbm) {
5284                         LOGD("selected videosink name: %s", videosink_element);
5285
5286                         /* support shard memory with S/W codec on HawkP */
5287                         if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5288                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5289                                         "use-tbm", use_tbm, NULL);
5290                         }
5291                 } else {
5292                         if (attrs) {
5293                                 int gapless = 0;
5294
5295                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5296
5297                                 if (gapless > 0) {
5298                                         LOGD("disable last-sample");
5299                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5300                                 }
5301                         }
5302                 }
5303                 if (player->set_mode.media_packet_video_stream) {
5304                         int enable = 0;
5305                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5306                         if (enable)
5307                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5308
5309                         MMPLAYER_SIGNAL_CONNECT(player,
5310                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5311                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5312                                                                         "handoff",
5313                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5314                                                                         (gpointer)player);
5315
5316                         MMPLAYER_SIGNAL_CONNECT(player,
5317                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5318                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5319                                                                         "preroll-handoff",
5320                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5321                                                                         (gpointer)player);
5322                 }
5323                 break;
5324         }
5325         case MM_DISPLAY_SURFACE_REMOTE:
5326         {
5327                 if (player->set_mode.media_packet_video_stream) {
5328                         LOGE("add data probe at videosink");
5329                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5330                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5331
5332                         MMPLAYER_SIGNAL_CONNECT(player,
5333                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5334                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5335                                                                         "handoff",
5336                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5337                                                                         (gpointer)player);
5338
5339                         MMPLAYER_SIGNAL_CONNECT(player,
5340                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5341                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5342                                                                         "preroll-handoff",
5343                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5344                                                                         (gpointer)player);
5345                 }
5346                 break;
5347         }
5348         default:
5349                 break;
5350         }
5351
5352         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5353                 goto ERROR;
5354
5355         if (videobin[MMPLAYER_V_SINK].gst) {
5356                 GstPad *sink_pad = NULL;
5357                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5358                 if (sink_pad) {
5359                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5360                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5361                         gst_object_unref(GST_OBJECT(sink_pad));
5362                 } else
5363                         LOGW("failed to get sink pad from videosink\n");
5364         }
5365
5366         /* store it as it's sink element */
5367         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5368
5369         /* adding created elements to bin */
5370         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5371                 LOGE("failed to add elements\n");
5372                 goto ERROR;
5373         }
5374
5375         /* Linking elements in the bucket by added order */
5376         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5377                 LOGE("failed to link elements\n");
5378                 goto ERROR;
5379         }
5380
5381         /* get first element's sinkpad for creating ghostpad */
5382         if (element_bucket)
5383                 first_element = (MMPlayerGstElement *)element_bucket->data;
5384         if (!first_element) {
5385                 LOGE("failed to get first element from bucket\n");
5386                 goto ERROR;
5387         }
5388
5389         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5390         if (!pad) {
5391                 LOGE("failed to get pad from first element\n");
5392                 goto ERROR;
5393         }
5394
5395         /* create ghostpad */
5396         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5397         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5398                 LOGE("failed to add ghostpad to videobin\n");
5399                 goto ERROR;
5400         }
5401         gst_object_unref(pad);
5402
5403         /* done. free allocated variables */
5404         if (element_bucket)
5405                 g_list_free(element_bucket);
5406
5407         mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5408
5409         MMPLAYER_FLEAVE();
5410
5411         return MM_ERROR_NONE;
5412
5413 ERROR:
5414         LOGE("ERROR : releasing videobin\n");
5415
5416         g_list_free(element_bucket);
5417
5418         if (pad)
5419                 gst_object_unref(GST_OBJECT(pad));
5420
5421         /* release videobin with it's childs */
5422         if (videobin[MMPLAYER_V_BIN].gst)
5423                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5424
5425
5426         MMPLAYER_FREEIF(videobin);
5427
5428         player->pipeline->videobin = NULL;
5429
5430         return MM_ERROR_PLAYER_INTERNAL;
5431 }
5432
5433 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5434 {
5435         GList *element_bucket = NULL;
5436         MMPlayerGstElement *textbin = player->pipeline->textbin;
5437
5438         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5439         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5440         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5441                                                         "signal-handoffs", FALSE,
5442                                                         NULL);
5443
5444         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5445         MMPLAYER_SIGNAL_CONNECT(player,
5446                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5447                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5448                                                         "handoff",
5449                                                         G_CALLBACK(__mmplayer_update_subtitle),
5450                                                         (gpointer)player);
5451
5452         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5453         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5454         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5455
5456         if (!player->play_subtitle) {
5457                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5458                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5459         }
5460
5461         /* adding created elements to bin */
5462         LOGD("adding created elements to bin\n");
5463         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5464                 LOGE("failed to add elements\n");
5465                 goto ERROR;
5466         }
5467
5468         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5469         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5470         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5471
5472         /* linking elements in the bucket by added order. */
5473         LOGD("Linking elements in the bucket by added order.\n");
5474         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5475                 LOGE("failed to link elements\n");
5476                 goto ERROR;
5477         }
5478
5479         /* done. free allocated variables */
5480         g_list_free(element_bucket);
5481
5482         if (textbin[MMPLAYER_T_QUEUE].gst) {
5483                 GstPad *pad = NULL;
5484                 GstPad *ghostpad = NULL;
5485
5486                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5487                 if (!pad) {
5488                         LOGE("failed to get video pad of textbin\n");
5489                         return MM_ERROR_PLAYER_INTERNAL;
5490                 }
5491
5492                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5493                 gst_object_unref(pad);
5494
5495                 if (!ghostpad) {
5496                         LOGE("failed to create ghostpad of textbin\n");
5497                         goto ERROR;
5498                 }
5499
5500                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5501                         LOGE("failed to add ghostpad to textbin\n");
5502                         goto ERROR;
5503                 }
5504         }
5505
5506         return MM_ERROR_NONE;
5507
5508 ERROR:
5509         g_list_free(element_bucket);
5510
5511         return MM_ERROR_PLAYER_INTERNAL;
5512 }
5513
5514 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5515 {
5516         MMPlayerGstElement *textbin = NULL;
5517         GList *element_bucket = NULL;
5518         gint i = 0;
5519
5520         MMPLAYER_FENTER();
5521
5522         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5523
5524         /* alloc handles */
5525         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5526         if (!textbin) {
5527                 LOGE("failed to allocate memory for textbin\n");
5528                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5529         }
5530
5531         /* create bin */
5532         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5533         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5534         if (!textbin[MMPLAYER_T_BIN].gst) {
5535                 LOGE("failed to create textbin\n");
5536                 goto ERROR;
5537         }
5538
5539         /* take it */
5540         player->pipeline->textbin = textbin;
5541
5542         /* fakesink */
5543         if (player->use_textoverlay) {
5544                 LOGD("use textoverlay for displaying \n");
5545
5546                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5547
5548                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5549
5550                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5551
5552                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5553
5554                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5555                         LOGE("failed to link queue and converter\n");
5556                         goto ERROR;
5557                 }
5558
5559                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5560                         LOGE("failed to link queue and textoverlay\n");
5561                         goto ERROR;
5562                 }
5563
5564                 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5565                         LOGE("failed to link queue and textoverlay\n");
5566                         goto ERROR;
5567                 }
5568         } else {
5569                 int surface_type = 0;
5570
5571                 LOGD("use subtitle message for displaying \n");
5572
5573                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5574
5575                 switch (surface_type) {
5576                 case MM_DISPLAY_SURFACE_OVERLAY:
5577                 case MM_DISPLAY_SURFACE_EVAS:
5578                 case MM_DISPLAY_SURFACE_GL:
5579                 case MM_DISPLAY_SURFACE_NULL:
5580                 case MM_DISPLAY_SURFACE_REMOTE:
5581                         if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5582                                 LOGE("failed to make plain text elements\n");
5583                                 goto ERROR;
5584                         }
5585                         break;
5586
5587                 default:
5588                         break;
5589                 }
5590         }
5591
5592         MMPLAYER_FLEAVE();
5593
5594         return MM_ERROR_NONE;
5595
5596 ERROR:
5597
5598         LOGD("ERROR : releasing textbin\n");
5599
5600         g_list_free(element_bucket);
5601
5602         /* release element which are not added to bin */
5603         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5604                 /* NOTE : skip bin */
5605                 if (textbin[i].gst) {
5606                         GstObject* parent = NULL;
5607                         parent = gst_element_get_parent(textbin[i].gst);
5608
5609                         if (!parent) {
5610                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5611                                 textbin[i].gst = NULL;
5612                         } else
5613                                 gst_object_unref(GST_OBJECT(parent));
5614                 }
5615         }
5616
5617         /* release textbin with it's childs */
5618         if (textbin[MMPLAYER_T_BIN].gst)
5619                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5620
5621         MMPLAYER_FREEIF(textbin);
5622
5623         player->pipeline->textbin = NULL;
5624
5625         return MM_ERROR_PLAYER_INTERNAL;
5626 }
5627
5628
5629 static int
5630 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5631 {
5632         MMPlayerGstElement* mainbin = NULL;
5633         MMHandleType attrs = 0;
5634         GstElement *subsrc = NULL;
5635         GstElement *subparse = NULL;
5636         gchar *subtitle_uri = NULL;
5637         const gchar *charset = NULL;
5638         GstPad *pad = NULL;
5639
5640         MMPLAYER_FENTER();
5641
5642         /* get mainbin */
5643         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5644
5645         mainbin = player->pipeline->mainbin;
5646
5647         attrs = MMPLAYER_GET_ATTRS(player);
5648         if (!attrs) {
5649                 LOGE("cannot get content attribute\n");
5650                 return MM_ERROR_PLAYER_INTERNAL;
5651         }
5652
5653         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5654         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5655                 LOGE("subtitle uri is not proper filepath.\n");
5656                 return MM_ERROR_PLAYER_INVALID_URI;
5657         }
5658         LOGD("subtitle file path is [%s].\n", subtitle_uri);
5659
5660
5661         /* create the subtitle source */
5662         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5663         if (!subsrc) {
5664                 LOGE("failed to create filesrc element\n");
5665                 goto ERROR;
5666         }
5667         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5668
5669         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5670         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5671
5672         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5673                 LOGW("failed to add queue\n");
5674                 goto ERROR;
5675         }
5676
5677         /* subparse */
5678         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5679         if (!subparse) {
5680                 LOGE("failed to create subparse element\n");
5681                 goto ERROR;
5682         }
5683
5684         charset = util_get_charset(subtitle_uri);
5685         if (charset) {
5686                 LOGD("detected charset is %s\n", charset);
5687                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5688         }
5689
5690         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5691         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5692
5693         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5694                 LOGW("failed to add subparse\n");
5695                 goto ERROR;
5696         }
5697
5698         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5699                 LOGW("failed to link subsrc and subparse\n");
5700                 goto ERROR;
5701         }
5702
5703         player->play_subtitle = TRUE;
5704         player->adjust_subtitle_pos = 0;
5705
5706         LOGD("play subtitle using subtitle file\n");
5707
5708         if (player->pipeline->textbin == NULL) {
5709                 if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
5710                         LOGE("failed to create textbin. continuing without text\n");
5711                         goto ERROR;
5712                 }
5713
5714                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5715                         LOGW("failed to add textbin\n");
5716                         goto ERROR;
5717                 }
5718
5719                 LOGD("link text input selector and textbin ghost pad");
5720
5721                 player->textsink_linked = 1;
5722                 player->external_text_idx = 0;
5723                 LOGI("player->textsink_linked set to 1\n");
5724         } else {
5725                 LOGD("text bin has been created. reuse it.");
5726                 player->external_text_idx = 1;
5727         }
5728
5729         if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5730                 LOGW("failed to link subparse and textbin\n");
5731                 goto ERROR;
5732         }
5733
5734         pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5735
5736         if (!pad) {
5737                 LOGE("failed to get sink pad from textsink to probe data");
5738                 return MM_ERROR_PLAYER_INTERNAL;
5739         }
5740
5741         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5742                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5743
5744         gst_object_unref(pad);
5745         pad = NULL;
5746
5747         /* create dot. for debugging */
5748         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5749         MMPLAYER_FLEAVE();
5750
5751         return MM_ERROR_NONE;
5752
5753 ERROR:
5754         player->textsink_linked = 0;
5755         return MM_ERROR_PLAYER_INTERNAL;
5756 }
5757
5758 gboolean
5759 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5760 {
5761         mm_player_t* player = (mm_player_t*) data;
5762         MMMessageParamType msg = {0, };
5763         GstClockTime duration = 0;
5764         gpointer text = NULL;
5765         guint text_size = 0;
5766         gboolean ret = TRUE;
5767         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5768
5769         MMPLAYER_FENTER();
5770
5771         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5772         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5773
5774         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5775         text = mapinfo.data;
5776         text_size = mapinfo.size;
5777         duration = GST_BUFFER_DURATION(buffer);
5778
5779         if (player->set_mode.subtitle_off) {
5780                 LOGD("subtitle is OFF.\n");
5781                 return TRUE;
5782         }
5783
5784         if (!text || (text_size == 0)) {
5785                 LOGD("There is no subtitle to be displayed.\n");
5786                 return TRUE;
5787         }
5788
5789         msg.data = (void *) text;
5790         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5791
5792         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5793
5794         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5795         gst_buffer_unmap(buffer, &mapinfo);
5796
5797         MMPLAYER_FLEAVE();
5798
5799         return ret;
5800 }
5801
5802 static GstPadProbeReturn
5803 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5804
5805 {
5806         mm_player_t *player = (mm_player_t *) u_data;
5807         GstClockTime cur_timestamp = 0;
5808         gint64 adjusted_timestamp = 0;
5809         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5810
5811         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5812
5813         if (player->set_mode.subtitle_off) {
5814                 LOGD("subtitle is OFF.\n");
5815                 return TRUE;
5816         }
5817
5818         if (player->adjust_subtitle_pos == 0) {
5819                 LOGD("nothing to do");
5820                 return TRUE;
5821         }
5822
5823         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5824         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5825
5826         if (adjusted_timestamp < 0) {
5827                 LOGD("adjusted_timestamp under zero");
5828                 MMPLAYER_FLEAVE();
5829                 return FALSE;
5830         }
5831
5832         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5833         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5834                                 GST_TIME_ARGS(cur_timestamp),
5835                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5836
5837         return GST_PAD_PROBE_OK;
5838 }
5839 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5840 {
5841         MMPLAYER_FENTER();
5842
5843         /* check player and subtitlebin are created */
5844         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5845         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5846
5847         if (position == 0) {
5848                 LOGD("nothing to do\n");
5849                 MMPLAYER_FLEAVE();
5850                 return MM_ERROR_NONE;
5851         }
5852
5853         switch (format) {
5854         case MM_PLAYER_POS_FORMAT_TIME:
5855                 {
5856                         /* check current postion */
5857                         player->adjust_subtitle_pos = position;
5858
5859                         LOGD("save adjust_subtitle_pos in player") ;
5860                 }
5861                 break;
5862
5863         default:
5864                 {
5865                         LOGW("invalid format.\n");
5866                         MMPLAYER_FLEAVE();
5867                         return MM_ERROR_INVALID_ARGUMENT;
5868                 }
5869         }
5870
5871         MMPLAYER_FLEAVE();
5872
5873         return MM_ERROR_NONE;
5874 }
5875 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5876 {
5877         MMPLAYER_FENTER();
5878         LOGD("adjusting video_pos in player") ;
5879         int current_pos = 0;
5880         /* check player and videobin are created */
5881         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5882         if (!player->pipeline->videobin ||
5883                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5884                 LOGD("no video pipeline or sink is there");
5885                 return MM_ERROR_PLAYER_INVALID_STATE ;
5886         }
5887         if (offset == 0) {
5888                 LOGD("nothing to do\n");
5889                 MMPLAYER_FLEAVE();
5890                 return MM_ERROR_NONE;
5891         }
5892         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
5893                 LOGD("failed to get current position");
5894                 return MM_ERROR_PLAYER_INTERNAL;
5895         }
5896         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5897                 LOGD("enter video delay is valid");
5898         } else {
5899                 LOGD("enter video delay is crossing content boundary");
5900                 return MM_ERROR_INVALID_ARGUMENT ;
5901         }
5902         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5903         LOGD("video delay has been done");
5904         MMPLAYER_FLEAVE();
5905
5906         return MM_ERROR_NONE;
5907 }
5908
5909 static void
5910 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5911 {
5912         GstElement *appsrc = element;
5913         tBuffer *buf = (tBuffer *)user_data;
5914         GstBuffer *buffer = NULL;
5915         GstFlowReturn ret = GST_FLOW_OK;
5916         gint len = size;
5917
5918         MMPLAYER_RETURN_IF_FAIL(element);
5919         MMPLAYER_RETURN_IF_FAIL(buf);
5920
5921         buffer = gst_buffer_new();
5922
5923         if (buf->offset >= buf->len) {
5924                 LOGD("call eos appsrc\n");
5925                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
5926                 return;
5927         }
5928
5929         if (buf->len - buf->offset < size)
5930                 len = buf->len - buf->offset + buf->offset;
5931
5932         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));
5933         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
5934         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
5935
5936         //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
5937         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
5938
5939         buf->offset += len;
5940 }
5941
5942 static gboolean
5943 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
5944 {
5945         tBuffer *buf = (tBuffer *)user_data;
5946
5947         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
5948
5949         buf->offset  = (int)size;
5950
5951         return TRUE;
5952 }
5953
5954 static void
5955 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
5956 {
5957         mm_player_t *player  = (mm_player_t*)user_data;
5958         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5959         guint64 current_level_bytes = 0;
5960         MMPLAYER_RETURN_IF_FAIL(player);
5961
5962         LOGI("app-src: feed data\n");
5963
5964         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
5965         if (player->media_stream_buffer_status_cb[type])
5966                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
5967 }
5968
5969 static gboolean
5970 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
5971 {
5972         mm_player_t *player  = (mm_player_t*)user_data;
5973         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5974
5975         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5976
5977         LOGI("app-src: seek data, offset: %llu\n", offset);
5978
5979         if (player->media_stream_seek_data_cb[type])
5980                 player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param);
5981
5982         return TRUE;
5983 }
5984
5985
5986 static gboolean
5987 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
5988 {
5989         mm_player_t *player  = (mm_player_t*)user_data;
5990         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5991         guint64 current_level_bytes = 0;
5992
5993         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5994
5995         LOGI("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]);
5996
5997         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
5998
5999         if (player->media_stream_buffer_status_cb[type])
6000                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
6001
6002         return TRUE;
6003 }
6004
6005 int
6006 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
6007 {
6008         mm_player_t* player = (mm_player_t*)hplayer;
6009         GstBuffer *buffer = NULL;
6010         GstFlowReturn gst_ret = GST_FLOW_OK;
6011         int ret = MM_ERROR_NONE;
6012 //      gint len = size;
6013
6014         MMPLAYER_FENTER();
6015
6016         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6017
6018         /* check current state */
6019 //      MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
6020
6021
6022         /* NOTE : we should check and create pipeline again if not created as we destroy
6023          * whole pipeline when stopping in streamming playback
6024          */
6025         if (!player->pipeline) {
6026                 if (MM_ERROR_NONE != __gst_realize(player)) {
6027                         LOGE("failed to realize before starting. only in streamming\n");
6028                         return MM_ERROR_PLAYER_INTERNAL;
6029                 }
6030         }
6031
6032         LOGI("app-src: pushing data\n");
6033
6034         if (buf == NULL) {
6035                 LOGE("buf is null\n");
6036                 return MM_ERROR_NONE;
6037         }
6038
6039         buffer = gst_buffer_new();
6040
6041         if (size <= 0) {
6042                 LOGD("call eos appsrc\n");
6043                 g_signal_emit_by_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
6044                 return MM_ERROR_NONE;
6045         }
6046
6047         //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));
6048
6049         LOGD("feed buffer %p, length %u\n", buf, size);
6050         g_signal_emit_by_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
6051
6052         MMPLAYER_FLEAVE();
6053
6054         return ret;
6055 }
6056
6057 static GstBusSyncReply
6058 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6059 {
6060         mm_player_t *player = (mm_player_t *)data;
6061         GstBusSyncReply reply = GST_BUS_DROP;
6062
6063         if (!(player->pipeline && player->pipeline->mainbin)) {
6064                 LOGE("player pipeline handle is null");
6065                 return GST_BUS_PASS;
6066         }
6067
6068         if (!__mmplayer_check_useful_message(player, message)) {
6069                 gst_message_unref(message);
6070                 return GST_BUS_DROP;
6071         }
6072
6073         switch (GST_MESSAGE_TYPE(message)) {
6074         case GST_MESSAGE_STATE_CHANGED:
6075                 /* post directly for fast launch */
6076                 if (player->sync_handler) {
6077                         __mmplayer_gst_callback(NULL, message, player);
6078                         reply = GST_BUS_DROP;
6079                 } else
6080                         reply = GST_BUS_PASS;
6081                 break;
6082         case GST_MESSAGE_TAG:
6083                 __mmplayer_gst_extract_tag_from_msg(player, message);
6084
6085                 #if 0 // debug
6086                 {
6087                         GstTagList *tags = NULL;
6088
6089                         gst_message_parse_tag(message, &tags);
6090                         if (tags) {
6091                                 LOGE("TAGS received from element \"%s\".\n",
6092                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6093
6094                                 gst_tag_list_foreach(tags, print_tag, NULL);
6095                                 gst_tag_list_free(tags);
6096                                 tags = NULL;
6097                         }
6098                         break;
6099                 }
6100                 #endif
6101                 break;
6102
6103         case GST_MESSAGE_DURATION_CHANGED:
6104                 __mmplayer_gst_handle_duration(player, message);
6105                 break;
6106         case GST_MESSAGE_ASYNC_DONE:
6107                 /* NOTE:Don't call gst_callback directly
6108                  * because previous frame can be showed even though this message is received for seek.
6109                  */
6110         default:
6111                 reply = GST_BUS_PASS;
6112                 break;
6113         }
6114
6115         if (reply == GST_BUS_DROP)
6116                 gst_message_unref(message);
6117
6118         return reply;
6119 }
6120
6121 static gboolean
6122 __mmplayer_gst_create_decoder(mm_player_t *player,
6123                                                                 MMPlayerTrackType track,
6124                                                                 GstPad* srcpad,
6125                                                                 enum MainElementID elemId,
6126                                                                 const gchar* name)
6127 {
6128         gboolean ret = TRUE;
6129         GstPad *sinkpad = NULL;
6130
6131         MMPLAYER_FENTER();
6132
6133         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6134                                                 player->pipeline &&
6135                                                 player->pipeline->mainbin, FALSE);
6136         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6137         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6138         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6139
6140         GstElement *decodebin = NULL;
6141         GstCaps *dec_caps = NULL;
6142
6143         /* create decodebin */
6144         decodebin = gst_element_factory_make("decodebin", name);
6145
6146         if (!decodebin) {
6147                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6148                 ret = FALSE;
6149                 goto ERROR;
6150         }
6151
6152         /* raw pad handling signal */
6153         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6154                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6155
6156         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6157         before looking for any elements that can handle that stream.*/
6158         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6159                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6160
6161         /* This signal is emitted when a element is added to the bin.*/
6162         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6163                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6164
6165         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6166                 LOGE("failed to add new decodebin\n");
6167                 ret = FALSE;
6168                 goto ERROR;
6169         }
6170
6171         dec_caps = gst_pad_query_caps(srcpad, NULL);
6172         if (dec_caps) {
6173                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6174                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6175                 gst_caps_unref(dec_caps);
6176         }
6177
6178         player->pipeline->mainbin[elemId].id = elemId;
6179         player->pipeline->mainbin[elemId].gst = decodebin;
6180
6181         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6182
6183         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6184                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6185                 gst_object_unref(GST_OBJECT(decodebin));
6186         }
6187
6188         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6189                 LOGE("failed to sync second level decodebin state with parent\n");
6190
6191         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6192
6193 ERROR:
6194         if (sinkpad) {
6195                 gst_object_unref(GST_OBJECT(sinkpad));
6196                 sinkpad = NULL;
6197         }
6198         MMPLAYER_FLEAVE();
6199
6200         return ret;
6201 }
6202
6203 /**
6204  * This function is to create  audio or video pipeline for playing.
6205  *
6206  * @param       player          [in]    handle of player
6207  *
6208  * @return      This function returns zero on success.
6209  * @remark
6210  * @see
6211  */
6212 static int
6213 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6214 {
6215         GstBus  *bus = NULL;
6216         MMPlayerGstElement *mainbin = NULL;
6217         MMHandleType attrs = 0;
6218         GstElement* element = NULL;
6219         GstElement* elem_src_audio = NULL;
6220         GstElement* elem_src_subtitle = NULL;
6221         GstElement* es_video_queue = NULL;
6222         GstElement* es_audio_queue = NULL;
6223         GstElement* es_subtitle_queue = NULL;
6224         GList* element_bucket = NULL;
6225         gboolean need_state_holder = TRUE;
6226         gint i = 0;
6227 #ifdef SW_CODEC_ONLY
6228         int surface_type = 0;
6229 #endif
6230         MMPLAYER_FENTER();
6231
6232         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6233
6234         /* get profile attribute */
6235         attrs = MMPLAYER_GET_ATTRS(player);
6236         if (!attrs) {
6237                 LOGE("cannot get content attribute\n");
6238                 goto INIT_ERROR;
6239         }
6240
6241         /* create pipeline handles */
6242         if (player->pipeline) {
6243                 LOGW("pipeline should be released before create new one\n");
6244                 goto INIT_ERROR;
6245         }
6246
6247         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6248         if (player->pipeline == NULL)
6249                 goto INIT_ERROR;
6250
6251         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6252
6253
6254         /* create mainbin */
6255         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6256         if (mainbin == NULL)
6257                 goto INIT_ERROR;
6258
6259         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6260
6261         /* create pipeline */
6262         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6263         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6264         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6265                 LOGE("failed to create pipeline\n");
6266                 goto INIT_ERROR;
6267         }
6268         player->demux_pad_index = 0;
6269         player->subtitle_language_list = NULL;
6270
6271         player->is_subtitle_force_drop = FALSE;
6272         player->last_multiwin_status = FALSE;
6273
6274         _mmplayer_track_initialize(player);
6275
6276         /* create source element */
6277         switch (player->profile.uri_type) {
6278         /* rtsp streamming */
6279         case MM_PLAYER_URI_TYPE_URL_RTSP:
6280                 {
6281                         gint network_bandwidth;
6282                         gchar *user_agent, *wap_profile;
6283
6284                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6285
6286                         if (!element) {
6287                                 LOGE("failed to create streaming source element\n");
6288                                 break;
6289                         }
6290
6291                         /* make it zero */
6292                         network_bandwidth = 0;
6293                         user_agent = wap_profile = NULL;
6294
6295                         /* get attribute */
6296                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6297                         mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6298                         mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6299
6300                         SECURE_LOGD("user_agent : %s\n", user_agent);
6301                         SECURE_LOGD("wap_profile : %s\n", wap_profile);
6302
6303                         /* setting property to streaming source */
6304                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6305                         if (user_agent)
6306                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6307                         if (wap_profile)
6308                                 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6309
6310                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6311                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6312                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6313                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6314
6315                         player->use_decodebin = FALSE;
6316                 }
6317                 break;
6318
6319         /* http streaming*/
6320         case MM_PLAYER_URI_TYPE_URL_HTTP:
6321                 {
6322                         gchar *user_agent, *proxy, *cookies, **cookie_list;
6323                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6324                         user_agent = proxy = cookies = NULL;
6325                         cookie_list = NULL;
6326                         gint mode = MM_PLAYER_PD_MODE_NONE;
6327
6328                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6329
6330                         player->pd_mode = mode;
6331
6332                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6333
6334                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6335                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6336                                 if (!element) {
6337                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6338                                         break;
6339                                 }
6340                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6341
6342                                 /* get attribute */
6343                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6344                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6345                                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6346                                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6347
6348                                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6349                                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6350                                         LOGD("get timeout from ini\n");
6351                                         http_timeout = player->ini.http_timeout;
6352                                 }
6353
6354                                 /* get attribute */
6355                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6356                                 SECURE_LOGD("cookies : %s\n", cookies);
6357                                 SECURE_LOGD("proxy : %s\n", proxy);
6358                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6359                                 LOGD("timeout : %d\n",  http_timeout);
6360
6361                                 /* setting property to streaming source */
6362                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6363                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6364                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6365
6366                                 /* check if prosy is vailid or not */
6367                                 if (util_check_valid_url(proxy))
6368                                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6369                                 /* parsing cookies */
6370                                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6371                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6372                                 if (user_agent)
6373                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6374
6375                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6376                                         LOGW("it's dash. and it's still experimental feature.");
6377                         } else {
6378                                 // progressive download
6379                                 gchar* location = NULL;
6380
6381                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6382                                         gchar *path = NULL;
6383
6384                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6385
6386                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6387
6388                                         LOGD("PD Location : %s\n", path);
6389
6390                                         if (path) {
6391                                                 player->pd_file_save_path = g_strdup(path);
6392                                         } else {
6393                                                 LOGE("can't find pd location so, it should be set \n");
6394                                                 break;
6395                                         }
6396                                 }
6397
6398                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6399                                 if (!element) {
6400                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6401                                         break;
6402                                 }
6403
6404                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6405                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6406                                 else
6407                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6408
6409                                 g_object_get(element, "location", &location, NULL);
6410                                 LOGD("PD_LOCATION [%s].\n", location);
6411                                 if (location)
6412                                         g_free(location);
6413                         }
6414                 }
6415                 break;
6416
6417         /* file source */
6418         case MM_PLAYER_URI_TYPE_FILE:
6419                 {
6420
6421                         LOGD("using filesrc for 'file://' handler.\n");
6422
6423                         element = gst_element_factory_make("filesrc", "source");
6424
6425                         if (!element) {
6426                                 LOGE("failed to create filesrc\n");
6427                                 break;
6428                         }
6429
6430                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6431                         //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6432                 }
6433                 break;
6434
6435         case MM_PLAYER_URI_TYPE_SS:
6436                 {
6437                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6438                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6439                         if (!element) {
6440                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6441                                 break;
6442                         }
6443
6444                         mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6445
6446                         if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6447                                 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6448                                 LOGD("get timeout from ini\n");
6449                                 http_timeout = player->ini.http_timeout;
6450                         }
6451
6452                         /* setting property to streaming source */
6453                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6454                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6455                 }
6456                 break;
6457
6458         /* appsrc */
6459         case MM_PLAYER_URI_TYPE_BUFF:
6460                 {
6461                         guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
6462
6463                         LOGD("mem src is selected\n");
6464
6465                         element = gst_element_factory_make("appsrc", "buff-source");
6466                         if (!element) {
6467                                 LOGE("failed to create appsrc element\n");
6468                                 break;
6469                         }
6470
6471                         g_object_set(element, "stream-type", stream_type, NULL);
6472                         //g_object_set(element, "size", player->mem_buf.len, NULL);
6473                         //g_object_set(element, "blocksize", (guint64)20480, NULL);
6474
6475                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6476                                 G_CALLBACK(__gst_appsrc_seek_data), player);
6477                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6478                                 G_CALLBACK(__gst_appsrc_feed_data), player);
6479                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6480                                 G_CALLBACK(__gst_appsrc_enough_data), player);
6481                 }
6482                 break;
6483         case MM_PLAYER_URI_TYPE_MS_BUFF:
6484                 {
6485                         LOGD("MS buff src is selected\n");
6486
6487                         if (player->v_stream_caps) {
6488                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6489                                 if (!element) {
6490                                         LOGF("failed to create video app source element[appsrc].\n");
6491                                         break;
6492                                 }
6493
6494                                 if (player->a_stream_caps) {
6495                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6496                                         if (!elem_src_audio) {
6497                                                 LOGF("failed to create audio app source element[appsrc].\n");
6498                                                 break;
6499                                         }
6500                                 }
6501                         } else if (player->a_stream_caps) {
6502                                 /* no video, only audio pipeline*/
6503                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6504                                 if (!element) {
6505                                         LOGF("failed to create audio app source element[appsrc].\n");
6506                                         break;
6507                                 }
6508                         }
6509
6510                         if (player->s_stream_caps) {
6511                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6512                                 if (!elem_src_subtitle) {
6513                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6514                                         break;
6515                                 }
6516                         }
6517
6518                         LOGD("setting app sources properties.\n");
6519                         LOGD("location : %s\n", player->profile.uri);
6520
6521                         if (player->v_stream_caps && element) {
6522                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6523                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6524                                                                                                 "caps", player->v_stream_caps, NULL);
6525
6526                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6527                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6528                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6529                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6530
6531                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6532                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6533                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6534                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6535
6536                                 if (player->a_stream_caps && elem_src_audio) {
6537                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6538                                                                                                                         "caps", player->a_stream_caps, NULL);
6539
6540                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6541                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6542                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6543                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6544
6545                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6546                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6547                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6548                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6549                                 }
6550                         } else if (player->a_stream_caps && element) {
6551                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6552                                                                                                 "caps", player->a_stream_caps, NULL);
6553
6554                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6555                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558
6559                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6560                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6561                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6562                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6563                         }
6564
6565                         if (player->s_stream_caps && elem_src_subtitle) {
6566                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6567                                                                                                                  "caps", player->s_stream_caps, NULL);
6568
6569                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6570                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6571                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6572                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6573
6574                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6575
6576                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6577                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6578                         }
6579
6580                         if (player->v_stream_caps && element) {
6581                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6582                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6583                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6584                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6585
6586                                 if (player->a_stream_caps && elem_src_audio) {
6587                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6588                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6589                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6590                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6591                                 }
6592                         } else if (player->a_stream_caps && element) {
6593                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6594                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6595                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6596                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6597                         }
6598
6599                         if (player->s_stream_caps && elem_src_subtitle)
6600                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6601                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6602
6603                         need_state_holder = FALSE;
6604
6605                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6606                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6607                                 LOGE("failed to commit\n");
6608                 }
6609                 break;
6610         /* appsrc */
6611         case MM_PLAYER_URI_TYPE_MEM:
6612                 {
6613                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6614
6615                         LOGD("mem src is selected\n");
6616
6617                         element = gst_element_factory_make("appsrc", "mem-source");
6618                         if (!element) {
6619                                 LOGE("failed to create appsrc element\n");
6620                                 break;
6621                         }
6622
6623                         g_object_set(element, "stream-type", stream_type, NULL);
6624                         g_object_set(element, "size", player->mem_buf.len, NULL);
6625                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6626
6627                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6628                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6629                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6630                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6631                 }
6632                 break;
6633         case MM_PLAYER_URI_TYPE_URL:
6634                 break;
6635
6636         case MM_PLAYER_URI_TYPE_TEMP:
6637                 break;
6638
6639         case MM_PLAYER_URI_TYPE_NONE:
6640         default:
6641                 break;
6642         }
6643
6644         /* check source element is OK */
6645         if (!element) {
6646                 LOGE("no source element was created.\n");
6647                 goto INIT_ERROR;
6648         }
6649
6650         /* take source element */
6651         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6652         mainbin[MMPLAYER_M_SRC].gst = element;
6653         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6654
6655         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6656                 player->streamer = __mm_player_streaming_create();
6657                 __mm_player_streaming_initialize(player->streamer);
6658         }
6659
6660         if (MMPLAYER_IS_HTTP_PD(player)) {
6661                 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6662
6663                 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6664                 element = gst_element_factory_make("queue2", "queue2");
6665                 if (!element) {
6666                         LOGE("failed to create http streaming buffer element\n");
6667                         goto INIT_ERROR;
6668                 }
6669
6670                 /* take it */
6671                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6672                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6673                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6674
6675                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6676
6677                 __mm_player_streaming_set_queue2(player->streamer,
6678                                 element,
6679                                 TRUE,
6680                                 player->ini.http_max_size_bytes,
6681                                 pre_buffering_time,
6682                                 1.0,
6683                                 player->ini.http_buffering_limit,
6684                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6685                                 NULL,
6686                                 0);
6687         }
6688         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6689                 if (player->v_stream_caps) {
6690                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6691                         if (!es_video_queue) {
6692                                 LOGE("create es_video_queue for es player failed\n");
6693                                 goto INIT_ERROR;
6694                         }
6695                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6696                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6697                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6698                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6699
6700                         /* Adding audio appsrc to bucket */
6701                         if (player->a_stream_caps && elem_src_audio) {
6702                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6703                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6704                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6705
6706                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6707                                 if (!es_audio_queue) {
6708                                         LOGE("create es_audio_queue for es player failed\n");
6709                                         goto INIT_ERROR;
6710                                 }
6711                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6712
6713                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6714                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6715                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6716                         }
6717                 } else if (player->a_stream_caps) {
6718                         /* Only audio stream, no video */
6719                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6720                         if (!es_audio_queue) {
6721                                 LOGE("create es_audio_queue for es player failed\n");
6722                                 goto INIT_ERROR;
6723                         }
6724                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6725                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6726                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6727                 }
6728
6729                 if (player->s_stream_caps && elem_src_subtitle) {
6730                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6731                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6732                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6733
6734                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6735                         if (!es_subtitle_queue) {
6736                                 LOGE("create es_subtitle_queue for es player failed\n");
6737                                 goto INIT_ERROR;
6738                         }
6739                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6740                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6741                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6742                 }
6743         }
6744
6745         /* create autoplugging element if src element is not a rtsp src */
6746         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6747                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6748                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6749                 element = NULL;
6750                 enum MainElementID elemId = MMPLAYER_M_NUM;
6751
6752                 if ((player->use_decodebin) &&
6753                         ((MMPLAYER_IS_HTTP_PD(player)) ||
6754                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6755                         elemId = MMPLAYER_M_AUTOPLUG;
6756                         element = __mmplayer_create_decodebin(player);
6757                         need_state_holder = FALSE;
6758                 } else {
6759                         elemId = MMPLAYER_M_TYPEFIND;
6760                         element = gst_element_factory_make("typefind", "typefinder");
6761                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6762                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6763                 }
6764
6765
6766                 /* check autoplug element is OK */
6767                 if (!element) {
6768                         LOGE("can not create element(%d)\n", elemId);
6769                         goto INIT_ERROR;
6770                 }
6771
6772                 mainbin[elemId].id = elemId;
6773                 mainbin[elemId].gst = element;
6774
6775                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6776         }
6777
6778         /* add elements to pipeline */
6779         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6780                 LOGE("Failed to add elements to pipeline\n");
6781                 goto INIT_ERROR;
6782         }
6783
6784
6785         /* linking elements in the bucket by added order. */
6786         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6787                 LOGE("Failed to link some elements\n");
6788                 goto INIT_ERROR;
6789         }
6790
6791
6792         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6793         if (need_state_holder) {
6794                 /* create */
6795                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6796                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6797
6798                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6799                         LOGE("fakesink element could not be created\n");
6800                         goto INIT_ERROR;
6801                 }
6802                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6803
6804                 /* take ownership of fakesink. we are reusing it */
6805                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6806
6807                 /* add */
6808                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6809                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6810                         LOGE("failed to add fakesink to bin\n");
6811                         goto INIT_ERROR;
6812                 }
6813         }
6814
6815         /* now we have completed mainbin. take it */
6816         player->pipeline->mainbin = mainbin;
6817
6818         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6819                 GstPad *srcpad = NULL;
6820
6821                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6822                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6823                         if (srcpad) {
6824                                 __mmplayer_gst_create_decoder(player,
6825                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6826                                                                                                 srcpad,
6827                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6828                                                                                                 "video_decodebin");
6829
6830                                 gst_object_unref(GST_OBJECT(srcpad));
6831                                 srcpad = NULL;
6832                         }
6833                 }
6834
6835                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6836                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6837                         if (srcpad) {
6838                                 __mmplayer_gst_create_decoder(player,
6839                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6840                                                                                                 srcpad,
6841                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6842                                                                                                 "audio_decodebin");
6843
6844                                 gst_object_unref(GST_OBJECT(srcpad));
6845                                 srcpad = NULL;
6846                         } // else error
6847                 } //  else error
6848
6849                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6850                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6851         }
6852
6853         /* connect bus callback */
6854         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6855         if (!bus) {
6856                 LOGE("cannot get bus from pipeline.\n");
6857                 goto INIT_ERROR;
6858         }
6859
6860         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6861
6862         player->context.thread_default = g_main_context_get_thread_default();
6863
6864         if (NULL == player->context.thread_default) {
6865                 player->context.thread_default = g_main_context_default();
6866                 LOGD("thread-default context is the global default context");
6867         }
6868         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6869
6870         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6871         if (__mmplayer_check_subtitle(player)) {
6872                 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6873                         LOGE("fail to create subtitle src\n");
6874         }
6875
6876         /* set sync handler to get tag synchronously */
6877         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6878
6879         /* finished */
6880         gst_object_unref(GST_OBJECT(bus));
6881         g_list_free(element_bucket);
6882
6883         MMPLAYER_FLEAVE();
6884
6885         return MM_ERROR_NONE;
6886
6887 INIT_ERROR:
6888
6889         __mmplayer_gst_destroy_pipeline(player);
6890         g_list_free(element_bucket);
6891
6892         if (mainbin) {
6893                 /* release element which are not added to bin */
6894                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6895                         /* NOTE : skip pipeline */
6896                         if (mainbin[i].gst) {
6897                                 GstObject* parent = NULL;
6898                                 parent = gst_element_get_parent(mainbin[i].gst);
6899
6900                                 if (!parent) {
6901                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6902                                         mainbin[i].gst = NULL;
6903                                 } else
6904                                         gst_object_unref(GST_OBJECT(parent));
6905                         }
6906                 }
6907
6908                 /* release pipeline with it's childs */
6909                 if (mainbin[MMPLAYER_M_PIPE].gst)
6910                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6911
6912                 MMPLAYER_FREEIF(mainbin);
6913         }
6914
6915         MMPLAYER_FREEIF(player->pipeline);
6916         return MM_ERROR_PLAYER_INTERNAL;
6917 }
6918
6919 static void
6920 __mmplayer_reset_gapless_state(mm_player_t* player)
6921 {
6922         MMPLAYER_FENTER();
6923         MMPLAYER_RETURN_IF_FAIL(player
6924                 && player->pipeline
6925                 && player->pipeline->audiobin
6926                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6927
6928         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6929
6930         MMPLAYER_FLEAVE();
6931         return;
6932 }
6933
6934 static int
6935 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6936 {
6937         gint timeout = 0;
6938         int ret = MM_ERROR_NONE;
6939
6940         MMPLAYER_FENTER();
6941
6942         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6943
6944         /* cleanup stuffs */
6945         MMPLAYER_FREEIF(player->type);
6946         player->have_dynamic_pad = FALSE;
6947         player->no_more_pad = FALSE;
6948         player->num_dynamic_pad = 0;
6949         player->demux_pad_index = 0;
6950         player->subtitle_language_list = NULL;
6951         player->use_deinterleave = FALSE;
6952         player->max_audio_channels = 0;
6953         player->video_share_api_delta = 0;
6954         player->video_share_clock_delta = 0;
6955         player->video_hub_download_mode = 0;
6956         __mmplayer_reset_gapless_state(player);
6957
6958         if (player->streamer) {
6959                 __mm_player_streaming_deinitialize(player->streamer);
6960                 __mm_player_streaming_destroy(player->streamer);
6961                 player->streamer = NULL;
6962         }
6963
6964         /* cleanup unlinked mime type */
6965         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6966         MMPLAYER_FREEIF(player->unlinked_video_mime);
6967         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6968
6969         /* cleanup running stuffs */
6970         __mmplayer_cancel_eos_timer(player);
6971
6972         /* cleanup gst stuffs */
6973         if (player->pipeline) {
6974                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6975                 GstTagList* tag_list = player->pipeline->tag_list;
6976
6977                 /* first we need to disconnect all signal hander */
6978                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6979
6980                 /* disconnecting bus watch */
6981                 if (player->bus_watcher)
6982                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6983                 player->bus_watcher = 0;
6984
6985                 if (mainbin) {
6986                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6987                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6988                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6989                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6990                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6991                         gst_object_unref(bus);
6992
6993                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6994                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6995                         if (ret != MM_ERROR_NONE) {
6996                                 LOGE("fail to change state to NULL\n");
6997                                 return MM_ERROR_PLAYER_INTERNAL;
6998                         }
6999
7000                         LOGW("succeeded in chaning state to NULL\n");
7001
7002                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7003
7004                         /* free fakesink */
7005                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7006                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7007
7008                         /* free avsysaudiosink
7009                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7010                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7011                         */
7012                         MMPLAYER_FREEIF(audiobin);
7013                         MMPLAYER_FREEIF(videobin);
7014                         MMPLAYER_FREEIF(textbin);
7015                         MMPLAYER_FREEIF(mainbin);
7016                 }
7017
7018                 if (tag_list)
7019                         gst_tag_list_free(tag_list);
7020
7021                 MMPLAYER_FREEIF(player->pipeline);
7022         }
7023         MMPLAYER_FREEIF(player->album_art);
7024
7025         if (player->v_stream_caps) {
7026                 gst_caps_unref(player->v_stream_caps);
7027                 player->v_stream_caps = NULL;
7028         }
7029         if (player->a_stream_caps) {
7030                 gst_caps_unref(player->a_stream_caps);
7031                 player->a_stream_caps = NULL;
7032         }
7033
7034         if (player->s_stream_caps) {
7035                 gst_caps_unref(player->s_stream_caps);
7036                 player->s_stream_caps = NULL;
7037         }
7038         _mmplayer_track_destroy(player);
7039
7040         if (player->sink_elements)
7041                 g_list_free(player->sink_elements);
7042         player->sink_elements = NULL;
7043
7044         if (player->bufmgr) {
7045                 tbm_bufmgr_deinit(player->bufmgr);
7046                 player->bufmgr = NULL;
7047         }
7048
7049         LOGW("finished destroy pipeline\n");
7050
7051         MMPLAYER_FLEAVE();
7052
7053         return ret;
7054 }
7055
7056 static int __gst_realize(mm_player_t* player) // @
7057 {
7058         gint timeout = 0;
7059         int ret = MM_ERROR_NONE;
7060
7061         MMPLAYER_FENTER();
7062
7063         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7064
7065         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7066
7067         ret = __mmplayer_gst_create_pipeline(player);
7068         if (ret) {
7069                 LOGE("failed to create pipeline\n");
7070                 return ret;
7071         }
7072
7073         /* set pipeline state to READY */
7074         /* NOTE : state change to READY must be performed sync. */
7075         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7076         ret = __mmplayer_gst_set_state(player,
7077                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7078
7079         if (ret != MM_ERROR_NONE) {
7080                 /* return error if failed to set state */
7081                 LOGE("failed to set READY state");
7082                 return ret;
7083         } else
7084                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7085
7086         /* create dot before error-return. for debugging */
7087         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7088
7089         MMPLAYER_FLEAVE();
7090
7091         return ret;
7092 }
7093
7094 static int __gst_unrealize(mm_player_t* player) // @
7095 {
7096         int ret = MM_ERROR_NONE;
7097
7098         MMPLAYER_FENTER();
7099
7100         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7101
7102         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7103         MMPLAYER_PRINT_STATE(player);
7104
7105         /* release miscellaneous information */
7106         __mmplayer_release_misc(player);
7107
7108         /* destroy pipeline */
7109         ret = __mmplayer_gst_destroy_pipeline(player);
7110         if (ret != MM_ERROR_NONE) {
7111                 LOGE("failed to destory pipeline\n");
7112                 return ret;
7113         }
7114
7115         /* release miscellaneous information.
7116            these info needs to be released after pipeline is destroyed. */
7117         __mmplayer_release_misc_post(player);
7118
7119         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7120
7121         MMPLAYER_FLEAVE();
7122
7123         return ret;
7124 }
7125
7126 static int __gst_pending_seek(mm_player_t* player)
7127 {
7128         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7129         int ret = MM_ERROR_NONE;
7130
7131         MMPLAYER_FENTER();
7132
7133         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7134
7135         if (!player->pending_seek.is_pending) {
7136                 LOGD("pending seek is not reserved. nothing to do.\n");
7137                 return ret;
7138         }
7139
7140         /* check player state if player could pending seek or not. */
7141         current_state = MMPLAYER_CURRENT_STATE(player);
7142
7143         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7144                 LOGW("try to pending seek in %s state, try next time. \n",
7145                         MMPLAYER_STATE_GET_NAME(current_state));
7146                 return ret;
7147         }
7148
7149         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7150
7151         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7152
7153         if (MM_ERROR_NONE != ret)
7154                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7155
7156         player->pending_seek.is_pending = FALSE;
7157
7158         MMPLAYER_FLEAVE();
7159
7160         return ret;
7161 }
7162
7163 static int __gst_start(mm_player_t* player) // @
7164 {
7165         gboolean sound_extraction = 0;
7166         int ret = MM_ERROR_NONE;
7167         gboolean async = FALSE;
7168
7169         MMPLAYER_FENTER();
7170
7171         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7172
7173         /* get sound_extraction property */
7174         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7175
7176         /* NOTE : if SetPosition was called before Start. do it now */
7177         /* streaming doesn't support it. so it should be always sync */
7178         /* !!create one more api to check if there is pending seek rather than checking variables */
7179         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7180                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7181                 ret = __gst_pause(player, FALSE);
7182                 if (ret != MM_ERROR_NONE) {
7183                         LOGE("failed to set state to PAUSED for pending seek\n");
7184                         return ret;
7185                 }
7186
7187                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7188
7189                 if (sound_extraction) {
7190                         LOGD("setting pcm extraction\n");
7191
7192                         ret = __mmplayer_set_pcm_extraction(player);
7193                         if (MM_ERROR_NONE != ret) {
7194                                 LOGW("failed to set pcm extraction\n");
7195                                 return ret;
7196                         }
7197                 } else {
7198                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7199                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7200                 }
7201         }
7202
7203         LOGD("current state before doing transition");
7204         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7205         MMPLAYER_PRINT_STATE(player);
7206
7207         /* set pipeline state to PLAYING  */
7208         if (player->es_player_push_mode)
7209                 async = TRUE;
7210         /* set pipeline state to PLAYING  */
7211         ret = __mmplayer_gst_set_state(player,
7212                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7213
7214         if (ret == MM_ERROR_NONE) {
7215                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7216         } else {
7217                 LOGE("failed to set state to PLAYING");
7218                 return ret;
7219         }
7220
7221         /* generating debug info before returning error */
7222         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7223
7224         MMPLAYER_FLEAVE();
7225
7226         return ret;
7227 }
7228
7229 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7230 {
7231         MMPLAYER_FENTER();
7232
7233         MMPLAYER_RETURN_IF_FAIL(player
7234                 && player->pipeline
7235                 && player->pipeline->audiobin
7236                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7237
7238         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7239
7240         usleep(time);
7241
7242         MMPLAYER_FLEAVE();
7243 }
7244
7245 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7246 {
7247         MMPLAYER_FENTER();
7248
7249         MMPLAYER_RETURN_IF_FAIL(player
7250                 && player->pipeline
7251                 && player->pipeline->audiobin
7252                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7253
7254         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
7255
7256         MMPLAYER_FLEAVE();
7257 }
7258
7259 static int __gst_stop(mm_player_t* player) // @
7260 {
7261         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7262         MMHandleType attrs = 0;
7263         gboolean fadedown = FALSE;
7264         gboolean rewind = FALSE;
7265         gint timeout = 0;
7266         int ret = MM_ERROR_NONE;
7267         GstState state;
7268         gboolean async = FALSE;
7269
7270         MMPLAYER_FENTER();
7271
7272         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7273         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7274
7275         LOGD("current state before doing transition");
7276         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7277         MMPLAYER_PRINT_STATE(player);
7278
7279         attrs = MMPLAYER_GET_ATTRS(player);
7280         if (!attrs) {
7281                 LOGE("cannot get content attribute\n");
7282                 return MM_ERROR_PLAYER_INTERNAL;
7283         }
7284
7285         mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7286
7287         /* enable fadedown */
7288         if (fadedown || player->sound_focus.by_asm_cb)
7289                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7290
7291         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7292         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7293
7294         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF ||
7295                 player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) {
7296                 state = GST_STATE_READY;
7297         } else {
7298                 state = GST_STATE_PAUSED;
7299
7300                 if (!MMPLAYER_IS_STREAMING(player) ||
7301                         (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7302                         rewind = TRUE;
7303         }
7304
7305         if (player->es_player_push_mode)
7306                 async = TRUE;
7307         /* set gst state */
7308         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout);
7309
7310         /* disable fadeout */
7311         if (fadedown || player->sound_focus.by_asm_cb)
7312                 __mmplayer_undo_sound_fadedown(player);
7313
7314         /* return if set_state has failed */
7315         if (ret != MM_ERROR_NONE) {
7316                 LOGE("failed to set state.\n");
7317                 return ret;
7318         }
7319
7320         /* rewind */
7321         if (rewind) {
7322                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7323                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7324                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7325                         LOGW("failed to rewind\n");
7326                         ret = MM_ERROR_PLAYER_SEEK;
7327                 }
7328         }
7329
7330         /* initialize */
7331         player->sent_bos = FALSE;
7332
7333         if (player->es_player_push_mode) //for cloudgame
7334                 timeout = 0;
7335
7336         /* wait for seek to complete */
7337         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7338         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7339                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7340         } else {
7341                 LOGE("fail to stop player.\n");
7342                 ret = MM_ERROR_PLAYER_INTERNAL;
7343                 __mmplayer_dump_pipeline_state(player);
7344         }
7345
7346         /* generate dot file if enabled */
7347         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7348
7349         MMPLAYER_FLEAVE();
7350
7351         return ret;
7352 }
7353
7354 int __gst_pause(mm_player_t* player, gboolean async) // @
7355 {
7356         int ret = MM_ERROR_NONE;
7357
7358         MMPLAYER_FENTER();
7359
7360         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7361         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7362
7363         LOGD("current state before doing transition");
7364         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7365         MMPLAYER_PRINT_STATE(player);
7366
7367         /* set pipeline status to PAUSED */
7368         player->ignore_asyncdone = TRUE;
7369
7370         ret = __mmplayer_gst_set_state(player,
7371                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7372
7373         player->ignore_asyncdone = FALSE;
7374
7375         if (FALSE == async) {
7376                 if (ret != MM_ERROR_NONE) {
7377                         GstMessage *msg = NULL;
7378                         GTimer *timer = NULL;
7379                         gdouble MAX_TIMEOUT_SEC = 3;
7380
7381                         LOGE("failed to set state to PAUSED");
7382
7383                         timer = g_timer_new();
7384                         g_timer_start(timer);
7385
7386                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7387                         gboolean got_msg = FALSE;
7388                         /* check if gst error posted or not */
7389                         do {
7390                                 msg = gst_bus_timed_pop(bus, GST_SECOND / 2);
7391                                 if (msg) {
7392                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7393                                                 GError *error = NULL;
7394
7395                                                 /* parse error code */
7396                                                 gst_message_parse_error(msg, &error, NULL);
7397
7398                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7399                                                         /* Note : the streaming error from the streaming source is handled
7400                                                          *   using __mmplayer_handle_streaming_error.
7401                                                          */
7402                                                         __mmplayer_handle_streaming_error(player, msg);
7403
7404                                                 } else if (error) {
7405                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7406
7407                                                         if (error->domain == GST_STREAM_ERROR)
7408                                                                 ret = __gst_handle_stream_error(player, error, msg);
7409                                                         else if (error->domain == GST_RESOURCE_ERROR)
7410                                                                 ret = __gst_handle_resource_error(player, error->code);
7411                                                         else if (error->domain == GST_LIBRARY_ERROR)
7412                                                                 ret = __gst_handle_library_error(player, error->code);
7413                                                         else if (error->domain == GST_CORE_ERROR)
7414                                                                 ret = __gst_handle_core_error(player, error->code);
7415                                                 }
7416
7417                                                 got_msg = TRUE;
7418                                                 player->msg_posted = TRUE;
7419                                         }
7420                                         gst_message_unref(msg);
7421                                 }
7422                         } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7423                         /* clean */
7424                         gst_object_unref(bus);
7425                         g_timer_stop(timer);
7426                         g_timer_destroy(timer);
7427
7428                         return ret;
7429                 } else if (!player->video_stream_cb && (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7430                         if (MMPLAYER_IS_RTSP_STREAMING(player))
7431                                 return ret;
7432                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7433                 } else if (ret == MM_ERROR_NONE)
7434                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7435         }
7436
7437         /* generate dot file before returning error */
7438         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7439
7440         MMPLAYER_FLEAVE();
7441
7442         return ret;
7443 }
7444
7445 int __gst_resume(mm_player_t* player, gboolean async) // @
7446 {
7447         int ret = MM_ERROR_NONE;
7448         gint timeout = 0;
7449
7450         MMPLAYER_FENTER();
7451
7452         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7453                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7454
7455         LOGD("current state before doing transition");
7456         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7457         MMPLAYER_PRINT_STATE(player);
7458
7459         /* generate dot file before returning error */
7460         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7461
7462         if (async)
7463                 LOGD("do async state transition to PLAYING.\n");
7464
7465         /* set pipeline state to PLAYING */
7466         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7467
7468         ret = __mmplayer_gst_set_state(player,
7469                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7470         if (ret != MM_ERROR_NONE) {
7471                 LOGE("failed to set state to PLAYING\n");
7472                 return ret;
7473         } else {
7474                 if (async == FALSE) {
7475                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7476                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7477                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7478                 }
7479         }
7480
7481         /* generate dot file before returning error */
7482         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7483
7484         MMPLAYER_FLEAVE();
7485
7486         return ret;
7487 }
7488
7489 static int
7490 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7491 {
7492         unsigned long dur_msec = 0;
7493         gint64 dur_nsec = 0;
7494         gint64 pos_nsec = 0;
7495         gboolean ret = TRUE;
7496         gboolean accurated = FALSE;
7497         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7498
7499         MMPLAYER_FENTER();
7500         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7501         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7502
7503         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7504                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7505                 goto PENDING;
7506
7507         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7508                 /* check duration */
7509                 /* NOTE : duration cannot be zero except live streaming.
7510                  *              Since some element could have some timing problemn with quering duration, try again.
7511                  */
7512                 if (!player->duration) {
7513                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7514                                 goto SEEK_ERROR;
7515                         player->duration = dur_nsec;
7516                 }
7517
7518                 if (player->duration) {
7519                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7520                 } else {
7521                         LOGE("could not get the duration. fail to seek.\n");
7522                         goto SEEK_ERROR;
7523                 }
7524         }
7525         LOGD("playback rate: %f\n", player->playback_rate);
7526
7527         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7528         if (accurated)
7529                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7530         else
7531                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7532
7533         /* do seek */
7534         switch (format) {
7535         case MM_PLAYER_POS_FORMAT_TIME:
7536         {
7537                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7538                         /* check position is valid or not */
7539                         if (position > dur_msec)
7540                                 goto INVALID_ARGS;
7541
7542                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7543
7544                         if (player->doing_seek) {
7545                                 LOGD("not completed seek");
7546                                 return MM_ERROR_PLAYER_DOING_SEEK;
7547                         }
7548                 }
7549
7550                 if (!internal_called)
7551                         player->doing_seek = TRUE;
7552
7553                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7554
7555                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7556                         gint64 cur_time = 0;
7557
7558                         /* get current position */
7559                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7560
7561                         /* flush */
7562                         GstEvent *event = gst_event_new_seek(1.0,
7563                                                         GST_FORMAT_TIME,
7564                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7565                                                         GST_SEEK_TYPE_SET, cur_time,
7566                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7567                         if (event)
7568                                 __gst_send_event_to_sink(player, event);
7569
7570                         __gst_pause(player, FALSE);
7571                 }
7572
7573                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7574                                                 GST_FORMAT_TIME, seek_flags,
7575                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7576                 if (!ret) {
7577                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7578                         goto SEEK_ERROR;
7579                 }
7580         }
7581         break;
7582
7583         case MM_PLAYER_POS_FORMAT_PERCENT:
7584         {
7585                 LOGD("seeking to(%lu)%% \n", position);
7586
7587                 if (player->doing_seek) {
7588                         LOGD("not completed seek");
7589                         return MM_ERROR_PLAYER_DOING_SEEK;
7590                 }
7591
7592                 if (!internal_called)
7593                         player->doing_seek = TRUE;
7594
7595                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7596                 pos_nsec = (gint64)((position * player->duration) / 100);
7597                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7598                                                 GST_FORMAT_TIME, seek_flags,
7599                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7600                 if (!ret) {
7601                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7602                         goto SEEK_ERROR;
7603                 }
7604         }
7605         break;
7606
7607         default:
7608                 goto INVALID_ARGS;
7609         }
7610
7611         /* NOTE : store last seeking point to overcome some bad operation
7612           *     (returning zero when getting current position) of some elements
7613           */
7614         player->last_position = pos_nsec;
7615
7616         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7617         if (player->playback_rate > 1.0)
7618                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7619
7620         MMPLAYER_FLEAVE();
7621         return MM_ERROR_NONE;
7622
7623 PENDING:
7624         player->pending_seek.is_pending = TRUE;
7625         player->pending_seek.format = format;
7626         player->pending_seek.pos = position;
7627
7628         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7629                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7630
7631         return MM_ERROR_NONE;
7632
7633 INVALID_ARGS:
7634         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7635         return MM_ERROR_INVALID_ARGUMENT;
7636
7637 SEEK_ERROR:
7638         player->doing_seek = FALSE;
7639         return MM_ERROR_PLAYER_SEEK;
7640 }
7641
7642 #define TRICKPLAY_OFFSET GST_MSECOND
7643
7644 static int
7645 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7646 {
7647         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7648         gint64 pos_msec = 0;
7649         gboolean ret = TRUE;
7650
7651         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7652                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7653
7654         current_state = MMPLAYER_CURRENT_STATE(player);
7655
7656         /* NOTE : query position except paused state to overcome some bad operation
7657          * please refer to below comments in details
7658          */
7659         if (current_state != MM_PLAYER_STATE_PAUSED)
7660                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7661
7662         /* NOTE : get last point to overcome some bad operation of some elements
7663          *(returning zero when getting current position in paused state
7664          * and when failed to get postion during seeking
7665          */
7666         if ((current_state == MM_PLAYER_STATE_PAUSED)
7667                 || (!ret)) {
7668                 //|| (player->last_position != 0 && pos_msec == 0))
7669                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7670
7671                 if (player->playback_rate < 0.0)
7672                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7673                 else
7674                         pos_msec = player->last_position;
7675
7676                 if (!ret)
7677                         pos_msec = player->last_position;
7678                 else
7679                         player->last_position = pos_msec;
7680
7681                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7682
7683         } else {
7684                 if (player->duration > 0 && pos_msec > player->duration)
7685                         pos_msec = player->duration;
7686
7687                 if (player->sound_focus.keep_last_pos) {
7688                         LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7689                         pos_msec = player->last_position;
7690                 } else
7691                         player->last_position = pos_msec;
7692         }
7693
7694         switch (format) {
7695         case MM_PLAYER_POS_FORMAT_TIME:
7696                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7697                 break;
7698
7699         case MM_PLAYER_POS_FORMAT_PERCENT:
7700         {
7701                 gint64 dur = 0;
7702                 gint64 pos = 0;
7703
7704                 dur = player->duration / GST_SECOND;
7705                 if (dur <= 0) {
7706                         LOGD("duration is [%d], so returning position 0\n", dur);
7707                         *position = 0;
7708                 } else {
7709                         pos = pos_msec / GST_SECOND;
7710                         *position = pos * 100 / dur;
7711                 }
7712                 break;
7713         }
7714         default:
7715                 return MM_ERROR_PLAYER_INTERNAL;
7716         }
7717
7718         return MM_ERROR_NONE;
7719 }
7720
7721
7722 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7723 {
7724 #define STREAMING_IS_FINISHED   0
7725 #define BUFFERING_MAX_PER       100
7726 #define DEFAULT_PER_VALUE       -1
7727 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7728
7729         MMPlayerGstElement *mainbin = NULL;
7730         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7731         gint64 buffered_total = 0;
7732         unsigned long position = 0;
7733         gint buffered_sec = -1;
7734         GstBufferingMode mode = GST_BUFFERING_STREAM;
7735         gint64 content_size_time = player->duration;
7736         guint64 content_size_bytes = player->http_content_size;
7737
7738         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7739                                                 player->pipeline &&
7740                                                 player->pipeline->mainbin,
7741                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7742
7743         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7744
7745         *start_pos = 0;
7746         *stop_pos = 0;
7747
7748         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7749                 /* and rtsp is not ready yet. */
7750                 LOGW("it's only used for http streaming case.\n");
7751                 return MM_ERROR_PLAYER_NO_OP;
7752         }
7753
7754         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7755                 LOGW("Time format is not supported yet.\n");
7756                 return MM_ERROR_INVALID_ARGUMENT;
7757         }
7758
7759         if (content_size_time <= 0 || content_size_bytes <= 0) {
7760                 LOGW("there is no content size.");
7761                 return MM_ERROR_NONE;
7762         }
7763
7764         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7765                 LOGW("fail to get current position.");
7766                 return MM_ERROR_NONE;
7767         }
7768
7769         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7770                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7771
7772         mainbin = player->pipeline->mainbin;
7773         start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7774
7775         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7776                 GstQuery *query = NULL;
7777                 gint byte_in_rate = 0, byte_out_rate = 0;
7778                 gint64 estimated_total = 0;
7779
7780                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7781                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7782                         LOGW("fail to get buffering query from queue2");
7783                         if (query)
7784                                 gst_query_unref(query);
7785                         return MM_ERROR_NONE;
7786                 }
7787
7788                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7789                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7790
7791                 if (mode == GST_BUFFERING_STREAM) {
7792                         /* using only queue in case of push mode(ts / mp3) */
7793                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7794                                 GST_FORMAT_BYTES, &buffered_total)) {
7795                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7796                                 stop_per = 100 * buffered_total / content_size_bytes;
7797                         }
7798                 } else {
7799                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7800                         guint idx = 0;
7801                         guint num_of_ranges = 0;
7802                         gint64 start_byte = 0, stop_byte = 0;
7803
7804                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7805                         if (estimated_total != STREAMING_IS_FINISHED) {
7806                                 /* buffered size info from queue2 */
7807                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7808                                 for (idx = 0; idx < num_of_ranges; idx++) {
7809                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7810                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7811
7812                                         buffered_total += (stop_byte - start_byte);
7813                                 }
7814                         } else
7815                                 stop_per = BUFFERING_MAX_PER;
7816                 }
7817                 gst_query_unref(query);
7818         }
7819
7820         if (stop_per == DEFAULT_PER_VALUE) {
7821                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7822                 if (dur_sec > 0) {
7823                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7824
7825                         /* buffered size info from multiqueue */
7826                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7827                                 guint curr_size_bytes = 0;
7828                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7829                                         "curr-size-bytes", &curr_size_bytes, NULL);
7830                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7831                                 buffered_total += curr_size_bytes;
7832                         }
7833
7834                         if (avg_byterate > 0)
7835                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7836                         else if (player->total_maximum_bitrate > 0)
7837                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7838                         else if (player->total_bitrate > 0)
7839                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7840
7841                         if (buffered_sec >= 0)
7842                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7843                 }
7844         }
7845
7846         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7847         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7848
7849         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7850                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7851
7852         return MM_ERROR_NONE;
7853 }
7854
7855 static int
7856 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7857 {
7858         MMPLAYER_FENTER();
7859
7860         if (!player) {
7861                 LOGW("set_message_callback is called with invalid player handle\n");
7862                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7863         }
7864
7865         player->msg_cb = callback;
7866         player->msg_cb_param = user_param;
7867
7868         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7869
7870         MMPLAYER_FLEAVE();
7871
7872         return MM_ERROR_NONE;
7873 }
7874
7875 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7876 {
7877         int ret = MM_ERROR_PLAYER_INVALID_URI;
7878         char *path = NULL;
7879
7880         MMPLAYER_FENTER();
7881
7882         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7883         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7884         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7885
7886         memset(data, 0, sizeof(MMPlayerParseProfile));
7887
7888         if ((path = strstr(uri, "es_buff://"))) {
7889                 if (strlen(path)) {
7890                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7891                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7892                         ret = MM_ERROR_NONE;
7893                 }
7894         } else if ((path = strstr(uri, "buff://"))) {
7895                         data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
7896                         ret = MM_ERROR_NONE;
7897         } else if ((path = strstr(uri, "rtsp://"))) {
7898                 if (strlen(path)) {
7899                         if ((path = strstr(uri, "/wfd1.0/"))) {
7900                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7901                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7902                                 ret = MM_ERROR_NONE;
7903                                 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7904                         } else {
7905                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7906                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7907                                 ret = MM_ERROR_NONE;
7908                         }
7909                 }
7910         } else if ((path = strstr(uri, "http://"))) {
7911                 if (strlen(path)) {
7912                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7913
7914                         if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7915                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7916                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7917                         else
7918                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7919
7920                         ret = MM_ERROR_NONE;
7921                 }
7922         } else if ((path = strstr(uri, "https://"))) {
7923                 if (strlen(path)) {
7924                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7925
7926                 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7927                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7928                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7929
7930                         data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7931
7932                         ret = MM_ERROR_NONE;
7933                 }
7934         } else if ((path = strstr(uri, "rtspu://"))) {
7935                 if (strlen(path)) {
7936                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7937                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7938                         ret = MM_ERROR_NONE;
7939                 }
7940         } else if ((path = strstr(uri, "rtspr://"))) {
7941                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7942                 char *separater = strstr(path, "*");
7943
7944                 if (separater) {
7945                         int urgent_len = 0;
7946                         char *urgent = separater + strlen("*");
7947
7948                         if ((urgent_len = strlen(urgent))) {
7949                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7950                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7951                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7952                                 ret = MM_ERROR_NONE;
7953                         }
7954                 }
7955         } else if ((path = strstr(uri, "mms://"))) {
7956                 if (strlen(path)) {
7957                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7958                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7959                         ret = MM_ERROR_NONE;
7960                 }
7961         } else if ((path = strstr(uri, "mem://"))) {
7962                 if (strlen(path)) {
7963                         int mem_size = 0;
7964                         char *buffer = NULL;
7965                         char *seperator = strchr(path, ',');
7966                         char ext[100] = {0,}, size[100] = {0,};
7967
7968                         if (seperator) {
7969                                 if ((buffer = strstr(path, "ext="))) {
7970                                         buffer += strlen("ext=");
7971
7972                                         if (strlen(buffer)) {
7973                                                 strncpy(ext, buffer, 99);
7974
7975                                                 if ((seperator = strchr(ext, ','))
7976                                                         || (seperator = strchr(ext, ' '))
7977                                                         || (seperator = strchr(ext, '\0'))) {
7978                                                         seperator[0] = '\0';
7979                                                 }
7980                                         }
7981                                 }
7982
7983                                 if ((buffer = strstr(path, "size="))) {
7984                                         buffer += strlen("size=");
7985
7986                                         if (strlen(buffer) > 0) {
7987                                                 strncpy(size, buffer, 99);
7988
7989                                                 if ((seperator = strchr(size, ','))
7990                                                         || (seperator = strchr(size, ' '))
7991                                                         || (seperator = strchr(size, '\0'))) {
7992                                                         seperator[0] = '\0';
7993                                                 }
7994
7995                                                 mem_size = atoi(size);
7996                                         }
7997                                 }
7998                         }
7999
8000                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8001                         if (mem_size && param) {
8002                                 data->mem = param;
8003                                 data->mem_size = mem_size;
8004                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8005                                 ret = MM_ERROR_NONE;
8006                         }
8007                 }
8008         } else {
8009                 gchar *location = NULL;
8010                 GError *err = NULL;
8011
8012                 if ((path = strstr(uri, "file://"))) {
8013
8014                         location = g_filename_from_uri(uri, NULL, &err);
8015
8016                         if (!location || (err != NULL)) {
8017                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8018                                  (err != NULL) ? err->message : "unknown error");
8019
8020                           if (err) g_error_free(err);
8021                           if (location) g_free(location);
8022
8023                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8024                           goto exit;
8025                         }
8026
8027                         LOGD("path from uri: %s", location);
8028                 }
8029
8030                 path = (location != NULL) ? (location) : ((char*)uri);
8031                 int file_stat = MM_ERROR_NONE;
8032
8033                 file_stat = util_exist_file_path(path);
8034
8035                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8036                 if (file_stat == MM_ERROR_NONE) {
8037                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8038
8039                         if (util_is_sdp_file(path)) {
8040                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8041                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8042                         } else
8043                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8044                         ret = MM_ERROR_NONE;
8045                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8046                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8047                 } else {
8048                         LOGE("invalid uri, could not play..\n");
8049                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8050                 }
8051
8052                 if (location) g_free(location);
8053         }
8054
8055 exit:
8056         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8057                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8058         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8059                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8060
8061         /* dump parse result */
8062         SECURE_LOGW("incomming uri : %s\n", uri);
8063         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8064                 data->uri_type, data->mem, data->mem_size, data->urgent);
8065
8066         MMPLAYER_FLEAVE();
8067
8068         return ret;
8069 }
8070
8071 gboolean _asm_postmsg(gpointer *data)
8072 {
8073         mm_player_t* player = (mm_player_t*)data;
8074         MMMessageParamType msg = {0, };
8075
8076         MMPLAYER_FENTER();
8077         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8078         LOGW("get notified");
8079
8080         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8081                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8082                 LOGW("dispatched");
8083                 return FALSE;
8084         }
8085
8086
8087         msg.union_type = MM_MSG_UNION_CODE;
8088         msg.code = player->sound_focus.focus_changed_msg;
8089
8090         MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8091         player->resume_event_id = 0;
8092
8093         LOGW("dispatched");
8094         return FALSE;
8095 }
8096
8097 gboolean _asm_lazy_pause(gpointer *data)
8098 {
8099         mm_player_t* player = (mm_player_t*)data;
8100         int ret = MM_ERROR_NONE;
8101
8102         MMPLAYER_FENTER();
8103
8104         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8105
8106         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8107                 LOGD("Ready to proceed lazy pause\n");
8108                 ret = _mmplayer_pause((MMHandleType)player);
8109                 if (MM_ERROR_NONE != ret)
8110                         LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8111         } else
8112                 LOGD("Invalid state to proceed lazy pause\n");
8113
8114         /* unset mute */
8115         if (player->pipeline && player->pipeline->audiobin)
8116                 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8117
8118         player->sound_focus.by_asm_cb = FALSE; //should be reset here
8119
8120         MMPLAYER_FLEAVE();
8121
8122         return FALSE;
8123 }
8124
8125 gboolean
8126 __mmplayer_can_do_interrupt(mm_player_t *player)
8127 {
8128         if (!player || !player->pipeline || !player->attrs) {
8129                 LOGW("not initialized");
8130                 goto FAILED;
8131         }
8132
8133         if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8134                 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8135                 goto FAILED;
8136         }
8137
8138         /* check if seeking */
8139         if (player->doing_seek) {
8140                 MMMessageParamType msg_param;
8141                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8142                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8143                 player->doing_seek = FALSE;
8144                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8145                 goto FAILED;
8146         }
8147
8148         /* check other thread */
8149         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8150                 LOGW("locked already, cmd state : %d", player->cmd);
8151
8152                 /* check application command */
8153                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8154                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8155
8156                         /* lock will be released at mrp_resource_release_cb() */
8157                         MMPLAYER_CMD_LOCK(player);
8158                         goto INTERRUPT;
8159                 }
8160                 LOGW("nothing to do");
8161                 goto FAILED;
8162         } else {
8163                 LOGW("can interrupt immediately");
8164                 goto INTERRUPT;
8165         }
8166
8167 FAILED:    /* with CMD UNLOCKED */
8168         return FALSE;
8169
8170 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8171         return TRUE;
8172 }
8173
8174 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8175 static int
8176 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8177 {
8178         int ret = MM_ERROR_NONE;
8179         MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8180
8181         if (strstr(reason_for_change, "alarm")) {
8182                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8183
8184         } else if (strstr(reason_for_change, "notification")) {
8185                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8186
8187         } else if (strstr(reason_for_change, "emergency")) {
8188                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8189
8190         } else if (strstr(reason_for_change, "call-voice") ||
8191                                 strstr(reason_for_change, "call-video") ||
8192                                 strstr(reason_for_change, "voip") ||
8193                                 strstr(reason_for_change, "ringtone-voip") ||
8194                                 strstr(reason_for_change, "ringtone-call")) {
8195                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8196
8197         } else if (strstr(reason_for_change, "media") ||
8198                                 strstr(reason_for_change, "radio") ||
8199                                 strstr(reason_for_change, "loopback") ||
8200                                 strstr(reason_for_change, "system") ||
8201                                 strstr(reason_for_change, "voice-information") ||
8202                                 strstr(reason_for_change, "voice-recognition")) {
8203                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8204
8205         } else {
8206                 ret = MM_ERROR_INVALID_ARGUMENT;
8207                 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8208                 goto DONE;
8209         }
8210
8211         if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8212                 /* can acqurie */
8213                 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8214
8215         LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8216         *msg = focus_msg;
8217
8218 DONE:
8219         return ret;
8220 }
8221
8222 /* FIXME: will be updated with new funct */
8223 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8224                                        const char *reason_for_change, const char *additional_info, void *user_data)
8225 {
8226         mm_player_t* player = (mm_player_t*) user_data;
8227         int result = MM_ERROR_NONE;
8228         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8229
8230         LOGW("focus watch notified");
8231
8232         if (!__mmplayer_can_do_interrupt(player)) {
8233                 LOGW("no need to interrupt, so leave");
8234                 goto EXIT_WITHOUT_UNLOCK;
8235         }
8236
8237         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8238                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8239                 goto EXIT;
8240         }
8241
8242         LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8243                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8244
8245         player->sound_focus.cb_pending = TRUE;
8246         player->sound_focus.by_asm_cb = TRUE;
8247
8248         if (focus_state == FOCUS_IS_ACQUIRED) {
8249                 LOGW("watch: FOCUS_IS_ACQUIRED");
8250                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8251                         player->sound_focus.focus_changed_msg = (int)msg;
8252
8253                 if (strstr(reason_for_change, "call") ||
8254                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8255                         strstr(reason_for_change, "alarm") ||
8256                         strstr(reason_for_change, "media")) {
8257                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8258                                 // hold 0.7 second to excute "fadedown mute" effect
8259                                 LOGW("do fade down->pause->undo fade down");
8260
8261                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8262
8263                                 result = _mmplayer_pause((MMHandleType)player);
8264                                 if (result != MM_ERROR_NONE) {
8265                                         LOGW("fail to set Pause state by asm");
8266                                         goto EXIT;
8267                                 }
8268                                 __mmplayer_undo_sound_fadedown(player);
8269                         } else
8270                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8271                                 _mmplayer_unrealize((MMHandleType)player);
8272                 } else {
8273                         LOGW("pause immediately");
8274                         result = _mmplayer_pause((MMHandleType)player);
8275                         if (result != MM_ERROR_NONE) {
8276                                 LOGW("fail to set Pause state by asm");
8277                                 goto EXIT;
8278                         }
8279                 }
8280         } else if (focus_state == FOCUS_IS_RELEASED) {
8281                 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8282                 player->sound_focus.antishock = TRUE;
8283                 player->sound_focus.by_asm_cb = FALSE;
8284
8285                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8286                         player->sound_focus.focus_changed_msg = (int)msg;
8287
8288                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8289                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8290                 goto DONE;
8291         } else
8292                 LOGW("unknown focus state %d", focus_state);
8293
8294 DONE:
8295         player->sound_focus.by_asm_cb = FALSE;
8296         player->sound_focus.cb_pending = FALSE;
8297
8298 EXIT:
8299         MMPLAYER_CMD_UNLOCK(player);
8300         LOGW("dispatched");
8301         return;
8302
8303 EXIT_WITHOUT_UNLOCK:
8304         LOGW("dispatched");
8305         return;
8306 }
8307
8308 void
8309 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8310         const char *reason_for_change, int option, const char *additional_info, void *user_data)
8311 {
8312         mm_player_t* player = (mm_player_t*) user_data;
8313         int result = MM_ERROR_NONE;
8314         gboolean lazy_pause = FALSE;
8315         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8316
8317         LOGW("get focus notified");
8318
8319         if (!__mmplayer_can_do_interrupt(player)) {
8320                 LOGW("no need to interrupt, so leave");
8321                 goto EXIT_WITHOUT_UNLOCK;
8322         }
8323
8324         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8325                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8326                 goto EXIT;
8327         }
8328
8329         LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8330                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8331
8332         player->sound_focus.cb_pending = TRUE;
8333         player->sound_focus.by_asm_cb = TRUE;
8334 //      player->sound_focus.event_src = event_src;
8335
8336         if (focus_state == FOCUS_IS_RELEASED) {
8337                 LOGW("FOCUS_IS_RELEASED");
8338
8339                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8340                         player->sound_focus.focus_changed_msg = (int)msg;
8341
8342                 if (strstr(reason_for_change, "call") ||
8343                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8344                         strstr(reason_for_change, "alarm") ||
8345                         strstr(reason_for_change, "media")) {
8346                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8347                                 //hold 0.7 second to excute "fadedown mute" effect
8348                                 LOGW("do fade down->pause->undo fade down");
8349
8350                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8351
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                                 __mmplayer_undo_sound_fadedown(player);
8358                         } else
8359                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8360                                 _mmplayer_unrealize((MMHandleType)player);
8361                 } else {
8362                         LOGW("pause immediately");
8363                         result = _mmplayer_pause((MMHandleType)player);
8364                         if (result != MM_ERROR_NONE) {
8365                                 LOGW("fail to set Pause state by asm");
8366                                 goto EXIT;
8367                         }
8368                 }
8369         } else if (focus_state == FOCUS_IS_ACQUIRED) {
8370                 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8371                 player->sound_focus.antishock = TRUE;
8372                 player->sound_focus.by_asm_cb = FALSE;
8373
8374                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8375                         player->sound_focus.focus_changed_msg = (int)msg;
8376
8377                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8378                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8379                 goto DONE;
8380         } else
8381                 LOGW("unknown focus state %d", focus_state);
8382
8383 DONE:
8384         if (!lazy_pause)
8385                 player->sound_focus.by_asm_cb = FALSE;
8386         player->sound_focus.cb_pending = FALSE;
8387
8388 EXIT:
8389         MMPLAYER_CMD_UNLOCK(player);
8390         LOGW("dispatched");
8391         return;
8392
8393 EXIT_WITHOUT_UNLOCK:
8394         LOGW("dispatched");
8395         return;
8396 }
8397
8398
8399 int
8400 _mmplayer_create_player(MMHandleType handle) // @
8401 {
8402         int ret = MM_ERROR_PLAYER_INTERNAL;
8403         mm_player_t* player = MM_PLAYER_CAST(handle);
8404
8405         MMPLAYER_FENTER();
8406
8407         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8408
8409         /* initialize player state */
8410         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8411         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8412         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8413         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8414
8415         /* check current state */
8416         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8417
8418         /* construct attributes */
8419         player->attrs = _mmplayer_construct_attribute(handle);
8420
8421         if (!player->attrs) {
8422                 LOGE("Failed to construct attributes\n");
8423                 return ret;
8424         }
8425
8426         /* initialize gstreamer with configured parameter */
8427         if (!__mmplayer_init_gstreamer(player)) {
8428                 LOGE("Initializing gstreamer failed\n");
8429                 _mmplayer_deconstruct_attribute(handle);
8430                 return ret;
8431         }
8432
8433         /* initialize factories if not using decodebin */
8434         if (player->factories == NULL)
8435                 __mmplayer_init_factories(player);
8436
8437         /* create lock. note that g_tread_init() has already called in gst_init() */
8438         g_mutex_init(&player->fsink_lock);
8439
8440         /* create repeat mutex */
8441         g_mutex_init(&player->repeat_thread_mutex);
8442
8443         /* create repeat cond */
8444         g_cond_init(&player->repeat_thread_cond);
8445
8446         /* create repeat thread */
8447         player->repeat_thread =
8448                 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8449         if (!player->repeat_thread) {
8450                 LOGE("failed to create repeat_thread(%s)");
8451                 g_mutex_clear(&player->repeat_thread_mutex);
8452                 g_cond_clear(&player->repeat_thread_cond);
8453                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8454                 goto ERROR;
8455         }
8456
8457         /* create next play mutex */
8458         g_mutex_init(&player->next_play_thread_mutex);
8459
8460         /* create next play cond */
8461         g_cond_init(&player->next_play_thread_cond);
8462
8463         /* create next play thread */
8464         player->next_play_thread =
8465                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8466         if (!player->next_play_thread) {
8467                 LOGE("failed to create next play thread");
8468                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8469                 g_mutex_clear(&player->next_play_thread_mutex);
8470                 g_cond_clear(&player->next_play_thread_cond);
8471                 goto ERROR;
8472         }
8473
8474         ret = _mmplayer_initialize_video_capture(player);
8475         if (ret != MM_ERROR_NONE) {
8476                 LOGE("failed to initialize video capture\n");
8477                 goto ERROR;
8478         }
8479
8480         /* initialize resource manager */
8481         if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8482                 LOGE("failed to initialize resource manager\n");
8483                 goto ERROR;
8484         }
8485
8486         if (MMPLAYER_IS_HTTP_PD(player)) {
8487                 player->pd_downloader = NULL;
8488                 player->pd_file_save_path = NULL;
8489         }
8490
8491         /* create video bo lock and cond */
8492         g_mutex_init(&player->video_bo_mutex);
8493         g_cond_init(&player->video_bo_cond);
8494
8495         player->streaming_type = STREAMING_SERVICE_NONE;
8496
8497         /* give default value of audio effect setting */
8498         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8499         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8500
8501         player->play_subtitle = FALSE;
8502         player->use_textoverlay = FALSE;
8503         player->play_count = 0;
8504         player->use_decodebin = TRUE;
8505         player->ignore_asyncdone = FALSE;
8506         player->use_deinterleave = FALSE;
8507         player->max_audio_channels = 0;
8508         player->video_share_api_delta = 0;
8509         player->video_share_clock_delta = 0;
8510         player->has_closed_caption = FALSE;
8511         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8512         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8513         if (player->ini.dump_element_keyword[0][0] == '\0')
8514                 player->ini.set_dump_element_flag = FALSE;
8515         else
8516                 player->ini.set_dump_element_flag = TRUE;
8517
8518         /* set player state to null */
8519         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8520         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8521
8522         return MM_ERROR_NONE;
8523
8524 ERROR:
8525         /* free lock */
8526         g_mutex_clear(&player->fsink_lock);
8527
8528         /* free thread */
8529         if (player->repeat_thread) {
8530                 player->repeat_thread_exit = TRUE;
8531                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8532
8533                 g_thread_join(player->repeat_thread);
8534                 player->repeat_thread = NULL;
8535
8536                 g_mutex_clear(&player->repeat_thread_mutex);
8537                 g_cond_clear(&player->repeat_thread_cond);
8538         }
8539
8540         /* free next play thread */
8541         if (player->next_play_thread) {
8542                 player->next_play_thread_exit = TRUE;
8543                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8544
8545                 g_thread_join(player->next_play_thread);
8546                 player->next_play_thread = NULL;
8547
8548                 g_mutex_clear(&player->next_play_thread_mutex);
8549                 g_cond_clear(&player->next_play_thread_cond);
8550         }
8551
8552         /* release attributes */
8553         _mmplayer_deconstruct_attribute(handle);
8554
8555         MMPLAYER_FLEAVE();
8556
8557         return ret;
8558 }
8559
8560 static gboolean
8561 __mmplayer_init_gstreamer(mm_player_t* player) // @
8562 {
8563         static gboolean initialized = FALSE;
8564         static const int max_argc = 50;
8565         gint* argc = NULL;
8566         gchar** argv = NULL;
8567         gchar** argv2 = NULL;
8568         GError *err = NULL;
8569         int i = 0;
8570         int arg_count = 0;
8571
8572         if (initialized) {
8573                 LOGD("gstreamer already initialized.\n");
8574                 return TRUE;
8575         }
8576
8577         /* alloc */
8578         argc = malloc(sizeof(int));
8579         argv = malloc(sizeof(gchar*) * max_argc);
8580         argv2 = malloc(sizeof(gchar*) * max_argc);
8581
8582         if (!argc || !argv || !argv2)
8583                 goto ERROR;
8584
8585         memset(argv, 0, sizeof(gchar*) * max_argc);
8586         memset(argv2, 0, sizeof(gchar*) * max_argc);
8587
8588         /* add initial */
8589         *argc = 1;
8590         argv[0] = g_strdup("mmplayer");
8591
8592         /* add gst_param */
8593         for (i = 0; i < 5; i++) {
8594                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8595                 if (strlen(player->ini.gst_param[i]) > 0) {
8596                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8597                         (*argc)++;
8598                 }
8599         }
8600
8601         /* we would not do fork for scanning plugins */
8602         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8603         (*argc)++;
8604
8605         /* check disable registry scan */
8606         if (player->ini.skip_rescan) {
8607                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8608                 (*argc)++;
8609         }
8610
8611         /* check disable segtrap */
8612         if (player->ini.disable_segtrap) {
8613                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8614                 (*argc)++;
8615         }
8616
8617         LOGD("initializing gstreamer with following parameter\n");
8618         LOGD("argc : %d\n", *argc);
8619         arg_count = *argc;
8620
8621         for (i = 0; i < arg_count; i++) {
8622                 argv2[i] = argv[i];
8623                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8624         }
8625
8626
8627         /* initializing gstreamer */
8628         if (!gst_init_check(argc, &argv, &err)) {
8629                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8630                 if (err)
8631                         g_error_free(err);
8632
8633                 goto ERROR;
8634         }
8635         /* release */
8636         for (i = 0; i < arg_count; i++) {
8637                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8638                 MMPLAYER_FREEIF(argv2[i]);
8639         }
8640
8641         MMPLAYER_FREEIF(argv);
8642         MMPLAYER_FREEIF(argv2);
8643         MMPLAYER_FREEIF(argc);
8644
8645         /* done */
8646         initialized = TRUE;
8647
8648         return TRUE;
8649
8650 ERROR:
8651
8652         /* release */
8653         for (i = 0; i < arg_count; i++) {
8654                 LOGD("free[%d] : %s\n", i, argv2[i]);
8655                 MMPLAYER_FREEIF(argv2[i]);
8656         }
8657
8658         MMPLAYER_FREEIF(argv);
8659         MMPLAYER_FREEIF(argv2);
8660         MMPLAYER_FREEIF(argc);
8661
8662         return FALSE;
8663 }
8664
8665 int
8666 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8667 {
8668         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669
8670         if (player->pd_downloader) {
8671                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8672                 MMPLAYER_FREEIF(player->pd_downloader);
8673         }
8674
8675         if (MMPLAYER_IS_HTTP_PD(player)) {
8676                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8677                 MMPLAYER_FREEIF(player->pd_file_save_path);
8678         }
8679
8680         return MM_ERROR_NONE;
8681 }
8682
8683 int
8684 _mmplayer_destroy(MMHandleType handle) // @
8685 {
8686         mm_player_t* player = MM_PLAYER_CAST(handle);
8687
8688         MMPLAYER_FENTER();
8689
8690         /* check player handle */
8691         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8692
8693         /* destroy can called at anytime */
8694         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8695
8696         __mmplayer_destroy_streaming_ext(player);
8697
8698         /* release repeat thread */
8699         if (player->repeat_thread) {
8700                 player->repeat_thread_exit = TRUE;
8701                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8702
8703                 LOGD("waitting for repeat thread exit\n");
8704                 g_thread_join(player->repeat_thread);
8705                 g_mutex_clear(&player->repeat_thread_mutex);
8706                 g_cond_clear(&player->repeat_thread_cond);
8707                 LOGD("repeat thread released\n");
8708         }
8709
8710         /* release next play thread */
8711         if (player->next_play_thread) {
8712                 player->next_play_thread_exit = TRUE;
8713                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8714
8715                 LOGD("waitting for next play thread exit\n");
8716                 g_thread_join(player->next_play_thread);
8717                 g_mutex_clear(&player->next_play_thread_mutex);
8718                 g_cond_clear(&player->next_play_thread_cond);
8719                 LOGD("next play thread released\n");
8720         }
8721
8722         _mmplayer_release_video_capture(player);
8723
8724         /* flush any pending asm_cb */
8725         if (player->sound_focus.cb_pending) {
8726                 /* set a flag for make sure asm_cb to be returned immediately */
8727                 LOGW("asm cb has pending state");
8728                 player->sound_focus.exit_cb = TRUE;
8729
8730                 /* make sure to release any pending asm_cb which locked by cmd_lock */
8731                 MMPLAYER_CMD_UNLOCK(player);
8732                 sched_yield();
8733                 MMPLAYER_CMD_LOCK(player);
8734         }
8735
8736         /* withdraw asm */
8737         if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8738                 LOGE("failed to deregister asm server\n");
8739
8740         /* de-initialize resource manager */
8741         if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8742                 LOGE("failed to deinitialize resource manager\n");
8743
8744 #ifdef USE_LAZY_PAUSE
8745         if (player->lazy_pause_event_id) {
8746                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8747                 player->lazy_pause_event_id = 0;
8748         }
8749 #endif
8750
8751         if (player->resume_event_id) {
8752                 g_source_remove(player->resume_event_id);
8753                 player->resume_event_id = 0;
8754         }
8755
8756         if (player->resumable_cancel_id) {
8757                 g_source_remove(player->resumable_cancel_id);
8758                 player->resumable_cancel_id = 0;
8759         }
8760
8761         /* release pipeline */
8762         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8763                 LOGE("failed to destory pipeline\n");
8764                 return MM_ERROR_PLAYER_INTERNAL;
8765         }
8766
8767         if (player->is_external_subtitle_present && player->subtitle_language_list) {
8768           g_list_free(player->subtitle_language_list);
8769           player->subtitle_language_list = NULL;
8770         }
8771
8772         __mmplayer_release_dump_list(player->dump_list);
8773
8774         /* release miscellaneous information.
8775            these info needs to be released after pipeline is destroyed. */
8776         __mmplayer_release_misc_post(player);
8777
8778         /* release attributes */
8779         _mmplayer_deconstruct_attribute(handle);
8780
8781         /* release factories */
8782         __mmplayer_release_factories(player);
8783
8784         /* release lock */
8785         g_mutex_clear(&player->fsink_lock);
8786
8787         /* release video bo lock and cond */
8788         g_mutex_clear(&player->video_bo_mutex);
8789         g_cond_clear(&player->video_bo_cond);
8790
8791         MMPLAYER_FLEAVE();
8792
8793         return MM_ERROR_NONE;
8794 }
8795
8796 int
8797 __mmplayer_realize_streaming_ext(mm_player_t* player)
8798 {
8799         int ret = MM_ERROR_NONE;
8800
8801         MMPLAYER_FENTER();
8802         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8803
8804         if (MMPLAYER_IS_HTTP_PD(player)) {
8805                 gboolean bret = FALSE;
8806
8807                 player->pd_downloader = _mmplayer_create_pd_downloader();
8808                 if (!player->pd_downloader) {
8809                         LOGE("Unable to create PD Downloader...");
8810                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8811                 }
8812
8813                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8814
8815                 if (FALSE == bret) {
8816                         LOGE("Unable to create PD Downloader...");
8817                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8818                 }
8819         }
8820
8821         MMPLAYER_FLEAVE();
8822         return ret;
8823 }
8824
8825 int
8826 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8827 {
8828         mm_player_t* player = (mm_player_t*)hplayer;
8829         MMHandleType attrs = 0;
8830         int ret = MM_ERROR_NONE;
8831
8832         attrs = MMPLAYER_GET_ATTRS(player);
8833         if (!attrs) {
8834                 LOGE("fail to get attributes.\n");
8835                 return MM_ERROR_PLAYER_INTERNAL;
8836         }
8837
8838         player->sound_focus.pid = pid;
8839
8840         /* register to asm */
8841         if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8842                                                 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8843                                                 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8844                                                 (void*)player)) {
8845                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8846                 LOGE("failed to register asm server\n");
8847                 return MM_ERROR_POLICY_INTERNAL;
8848         }
8849         return ret;
8850 }
8851
8852 int
8853 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8854 {
8855         mm_player_t* player = (mm_player_t*) hplayer;
8856
8857         MMPLAYER_FENTER();
8858
8859         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8860
8861         *pid = player->sound_focus.pid;
8862
8863         LOGD("registered pid[%d] %p", *pid, player);
8864
8865         MMPLAYER_FLEAVE();
8866
8867         return MM_ERROR_NONE;
8868 }
8869
8870 int
8871 _mmplayer_realize(MMHandleType hplayer) // @
8872 {
8873         mm_player_t* player = (mm_player_t*)hplayer;
8874         char *uri = NULL;
8875         void *param = NULL;
8876         gboolean update_registry = FALSE;
8877         MMHandleType attrs = 0;
8878         int ret = MM_ERROR_NONE;
8879
8880         MMPLAYER_FENTER();
8881
8882         /* check player handle */
8883         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8884
8885         /* check current state */
8886         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8887
8888         attrs = MMPLAYER_GET_ATTRS(player);
8889         if (!attrs) {
8890                 LOGE("fail to get attributes.\n");
8891                 return MM_ERROR_PLAYER_INTERNAL;
8892         }
8893         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8894         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8895
8896         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8897                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8898
8899                 if (ret != MM_ERROR_NONE) {
8900                         LOGE("failed to parse profile\n");
8901                         return ret;
8902                 }
8903         }
8904
8905         /* FIXIT : we can use thouse in player->profile directly */
8906         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8907                 player->mem_buf.buf = (char *)player->profile.mem;
8908                 player->mem_buf.len = player->profile.mem_size;
8909                 player->mem_buf.offset = 0;
8910         }
8911
8912         if (uri && (strstr(uri, "es_buff://"))) {
8913                 if (strstr(uri, "es_buff://push_mode"))
8914                         player->es_player_push_mode = TRUE;
8915                 else
8916                         player->es_player_push_mode = FALSE;
8917         }
8918
8919         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8920                 LOGW("mms protocol is not supported format.\n");
8921                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8922         }
8923
8924         if (MMPLAYER_IS_STREAMING(player))
8925                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8926         else
8927                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8928
8929         player->smooth_streaming = FALSE;
8930         player->videodec_linked  = 0;
8931         player->videosink_linked = 0;
8932         player->audiodec_linked  = 0;
8933         player->audiosink_linked = 0;
8934         player->textsink_linked = 0;
8935         player->is_external_subtitle_present = FALSE;
8936         /* set the subtitle ON default */
8937         player->is_subtitle_off = FALSE;
8938
8939         /* registry should be updated for downloadable codec */
8940         mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8941
8942         if (update_registry) {
8943                 LOGD("updating registry...\n");
8944                 gst_update_registry();
8945
8946                 /* then we have to rebuild factories */
8947                 __mmplayer_release_factories(player);
8948                 __mmplayer_init_factories(player);
8949         }
8950
8951         /* realize pipeline */
8952         ret = __gst_realize(player);
8953         if (ret != MM_ERROR_NONE)
8954                 LOGE("fail to realize the player.\n");
8955         else
8956                 ret = __mmplayer_realize_streaming_ext(player);
8957
8958         MMPLAYER_FLEAVE();
8959
8960         return ret;
8961 }
8962
8963 int
8964 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8965 {
8966         MMPLAYER_FENTER();
8967         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8968
8969         /* destroy can called at anytime */
8970         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
8971                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8972                 MMPLAYER_FREEIF(player->pd_downloader);
8973         }
8974
8975         MMPLAYER_FLEAVE();
8976         return MM_ERROR_NONE;
8977 }
8978
8979 int
8980 _mmplayer_unrealize(MMHandleType hplayer)
8981 {
8982         mm_player_t* player = (mm_player_t*)hplayer;
8983         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
8984         int ret = MM_ERROR_NONE;
8985
8986         MMPLAYER_FENTER();
8987
8988         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8989
8990         /* check current state */
8991         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8992
8993         __mmplayer_unrealize_streaming_ext(player);
8994
8995         /* unrealize pipeline */
8996         ret = __gst_unrealize(player);
8997
8998         /* set asm stop if success */
8999         if (MM_ERROR_NONE == ret) {
9000                 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9001                 if (ret != MM_ERROR_NONE)
9002                         LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9003
9004                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9005                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9006                                 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9007                                 if (ret != MM_ERROR_NONE)
9008                                         LOGE("failed to release resource, ret(0x%x)\n", ret);
9009                         }
9010                 }
9011
9012                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9013                         if (resource_state == RESOURCE_STATE_PREPARED) {
9014                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9015                                 if (ret != MM_ERROR_NONE)
9016                                         LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9017                         }
9018                 }
9019         } else
9020                 LOGE("failed and don't change asm state to stop");
9021
9022         MMPLAYER_FLEAVE();
9023
9024         return ret;
9025 }
9026
9027 int
9028 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9029 {
9030         mm_player_t* player = (mm_player_t*)hplayer;
9031
9032         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9033
9034         return __gst_set_message_callback(player, callback, user_param);
9035 }
9036
9037 int
9038 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9039 {
9040         mm_player_t *player = (mm_player_t*)hplayer;
9041
9042         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9043
9044         *state = MMPLAYER_CURRENT_STATE(player);
9045
9046         return MM_ERROR_NONE;
9047 }
9048
9049
9050 int
9051 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9052 {
9053         mm_player_t* player = (mm_player_t*) hplayer;
9054         GstElement* vol_element = NULL;
9055         int i = 0;
9056
9057         MMPLAYER_FENTER();
9058
9059         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9060
9061         LOGD("volume [L]=%f:[R]=%f\n",
9062                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9063
9064         /* invalid factor range or not */
9065         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9066                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9067                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
9068                         return MM_ERROR_INVALID_ARGUMENT;
9069                 }
9070         }
9071
9072         /* not support to set other value into each channel */
9073         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9074                 return MM_ERROR_INVALID_ARGUMENT;
9075
9076         /* Save volume to handle. Currently the first array element will be saved. */
9077         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9078
9079         /* check pipeline handle */
9080         if (!player->pipeline || !player->pipeline->audiobin) {
9081                 LOGD("audiobin is not created yet\n");
9082                 LOGD("but, current stored volume will be set when it's created.\n");
9083
9084                 /* NOTE : stored volume will be used in create_audiobin
9085                  * returning MM_ERROR_NONE here makes application to able to
9086                  * set volume at anytime.
9087                  */
9088                 return MM_ERROR_NONE;
9089         }
9090
9091         /* setting volume to volume element */
9092         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9093
9094         if (vol_element) {
9095                 LOGD("volume is set [%f]\n", player->sound.volume);
9096                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9097         }
9098
9099         MMPLAYER_FLEAVE();
9100
9101         return MM_ERROR_NONE;
9102 }
9103
9104
9105 int
9106 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9107 {
9108         mm_player_t* player = (mm_player_t*) hplayer;
9109         int i = 0;
9110
9111         MMPLAYER_FENTER();
9112
9113         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9115
9116         /* returning stored volume */
9117         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9118                 volume->level[i] = player->sound.volume;
9119
9120         MMPLAYER_FLEAVE();
9121
9122         return MM_ERROR_NONE;
9123 }
9124
9125
9126
9127 int
9128 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9129 {
9130         mm_player_t* player = (mm_player_t*) hplayer;
9131         GstElement* vol_element = NULL;
9132
9133         MMPLAYER_FENTER();
9134
9135         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9136
9137         /* mute value shoud 0 or 1 */
9138         if (mute != 0 && mute != 1) {
9139                 LOGE("bad mute value\n");
9140
9141                 /* FIXIT : definitly, we need _BAD_PARAM error code */
9142                 return MM_ERROR_INVALID_ARGUMENT;
9143         }
9144
9145         player->sound.mute = mute;
9146
9147         /* just hold mute value if pipeline is not ready */
9148         if (!player->pipeline || !player->pipeline->audiobin) {
9149                 LOGD("pipeline is not ready. holding mute value\n");
9150                 return MM_ERROR_NONE;
9151         }
9152
9153         vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9154
9155         /* NOTE : volume will only created when the bt is enabled */
9156         if (vol_element) {
9157                 LOGD("mute : %d\n", mute);
9158                 g_object_set(vol_element, "mute", mute, NULL);
9159         } else
9160                 LOGD("volume elemnet is not created. using volume in audiosink\n");
9161
9162         MMPLAYER_FLEAVE();
9163
9164         return MM_ERROR_NONE;
9165 }
9166
9167 int
9168 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9169 {
9170         mm_player_t* player = (mm_player_t*) hplayer;
9171
9172         MMPLAYER_FENTER();
9173
9174         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9175         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9176
9177         /* just hold mute value if pipeline is not ready */
9178         if (!player->pipeline || !player->pipeline->audiobin) {
9179                 LOGD("pipeline is not ready. returning stored value\n");
9180                 *pmute = player->sound.mute;
9181                 return MM_ERROR_NONE;
9182         }
9183
9184         *pmute = player->sound.mute;
9185
9186         MMPLAYER_FLEAVE();
9187
9188         return MM_ERROR_NONE;
9189 }
9190
9191 int
9192 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9193 {
9194         mm_player_t* player = (mm_player_t*) hplayer;
9195
9196         MMPLAYER_FENTER();
9197
9198         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9199
9200         player->video_stream_changed_cb = callback;
9201         player->video_stream_changed_cb_user_param = user_param;
9202         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9203
9204         MMPLAYER_FLEAVE();
9205
9206         return MM_ERROR_NONE;
9207 }
9208
9209 int
9210 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9211 {
9212         mm_player_t* player = (mm_player_t*) hplayer;
9213
9214         MMPLAYER_FENTER();
9215
9216         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9217
9218         player->audio_stream_changed_cb = callback;
9219         player->audio_stream_changed_cb_user_param = user_param;
9220         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9221
9222         MMPLAYER_FLEAVE();
9223
9224         return MM_ERROR_NONE;
9225 }
9226
9227 int
9228 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9229 {
9230         mm_player_t* player = (mm_player_t*) hplayer;
9231
9232         MMPLAYER_FENTER();
9233
9234         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9235
9236         player->audio_stream_render_cb_ex = callback;
9237         player->audio_stream_cb_user_param = user_param;
9238         player->audio_stream_sink_sync = sync;
9239         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);
9240
9241         MMPLAYER_FLEAVE();
9242
9243         return MM_ERROR_NONE;
9244 }
9245
9246 int
9247 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9248 {
9249         mm_player_t* player = (mm_player_t*) hplayer;
9250
9251         MMPLAYER_FENTER();
9252
9253         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9254
9255         if (callback && !player->bufmgr)
9256                 player->bufmgr = tbm_bufmgr_init(-1);
9257
9258         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9259         player->video_stream_cb = callback;
9260         player->video_stream_cb_user_param = user_param;
9261
9262         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9263
9264         MMPLAYER_FLEAVE();
9265
9266         return MM_ERROR_NONE;
9267 }
9268
9269 int
9270 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9271 {
9272         mm_player_t* player = (mm_player_t*) hplayer;
9273
9274         MMPLAYER_FENTER();
9275
9276         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9277
9278         player->audio_stream_cb = callback;
9279         player->audio_stream_cb_user_param = user_param;
9280         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9281
9282         MMPLAYER_FLEAVE();
9283
9284         return MM_ERROR_NONE;
9285 }
9286
9287 // set prepare size
9288 int
9289 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9290 {
9291         mm_player_t* player = (mm_player_t*) hplayer;
9292
9293         MMPLAYER_FENTER();
9294
9295         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9296
9297         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
9298                 return MM_ERROR_PLAYER_INVALID_STATE;
9299
9300         LOGD("pre buffer size : %d sec\n", second);
9301
9302         if (second <= 0) {
9303                 LOGE("bad size value\n");
9304                 return MM_ERROR_INVALID_ARGUMENT;
9305         }
9306
9307         if (player->streamer == NULL) {
9308                 player->streamer = __mm_player_streaming_create();
9309                 __mm_player_streaming_initialize(player->streamer);
9310         }
9311
9312         player->streamer->buffering_req.initial_second = second;
9313
9314         MMPLAYER_FLEAVE();
9315
9316         return MM_ERROR_NONE;
9317 }
9318
9319 // set runtime mode
9320 int
9321 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9322 {
9323         mm_player_t* player = (mm_player_t*) hplayer;
9324
9325         MMPLAYER_FENTER();
9326
9327         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9328
9329         LOGD("mode %d\n", mode);
9330
9331         if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9332                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9333                 return MM_ERROR_INVALID_ARGUMENT;
9334
9335         if (player->streamer == NULL) {
9336                 player->streamer = __mm_player_streaming_create();
9337                 __mm_player_streaming_initialize(player->streamer);
9338         }
9339
9340         player->streamer->buffering_req.mode = mode;
9341
9342         if ((second > 0) &&
9343                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9344                 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9345                 player->streamer->buffering_req.runtime_second = second;
9346
9347         MMPLAYER_FLEAVE();
9348
9349         return MM_ERROR_NONE;
9350 }
9351
9352 int
9353 __mmplayer_start_streaming_ext(mm_player_t *player)
9354 {
9355         gint ret = MM_ERROR_NONE;
9356
9357         MMPLAYER_FENTER();
9358         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9359
9360         if (MMPLAYER_IS_HTTP_PD(player)) {
9361                 if (!player->pd_downloader) {
9362                         ret = __mmplayer_realize_streaming_ext(player);
9363
9364                         if (ret != MM_ERROR_NONE) {
9365                                 LOGE("failed to realize streaming ext\n");
9366                                 return ret;
9367                         }
9368                 }
9369
9370                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9371                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9372                         if (!ret) {
9373                                 LOGE("ERROR while starting PD...\n");
9374                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9375                         }
9376                         ret = MM_ERROR_NONE;
9377                 }
9378         }
9379
9380         MMPLAYER_FLEAVE();
9381         return ret;
9382 }
9383
9384 int
9385 _mmplayer_start(MMHandleType hplayer) // @
9386 {
9387         mm_player_t* player = (mm_player_t*) hplayer;
9388         gint ret = MM_ERROR_NONE;
9389
9390         MMPLAYER_FENTER();
9391
9392         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9393
9394         /* check current state */
9395         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9396
9397         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9398         if (ret != MM_ERROR_NONE) {
9399                 LOGE("failed to acquire sound focus.\n");
9400                 return ret;
9401         }
9402
9403         /* NOTE : we should check and create pipeline again if not created as we destroy
9404          * whole pipeline when stopping in streamming playback
9405          */
9406         if (!player->pipeline) {
9407                 ret = __gst_realize(player);
9408                 if (MM_ERROR_NONE != ret) {
9409                         LOGE("failed to realize before starting. only in streamming\n");
9410                         /* unlock */
9411                         return ret;
9412                 }
9413         }
9414
9415         ret = __mmplayer_start_streaming_ext(player);
9416         if (ret != MM_ERROR_NONE)
9417                 LOGE("failed to start streaming ext \n");
9418
9419         /* start pipeline */
9420         ret = __gst_start(player);
9421         if (ret != MM_ERROR_NONE)
9422                 LOGE("failed to start player.\n");
9423
9424         MMPLAYER_FLEAVE();
9425
9426         return ret;
9427 }
9428
9429 /* NOTE: post "not supported codec message" to application
9430  * when one codec is not found during AUTOPLUGGING in MSL.
9431  * So, it's separated with error of __mmplayer_gst_callback().
9432  * And, if any codec is not found, don't send message here.
9433  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9434  */
9435 int
9436 __mmplayer_handle_missed_plugin(mm_player_t* player)
9437 {
9438         MMMessageParamType msg_param;
9439         memset(&msg_param, 0, sizeof(MMMessageParamType));
9440         gboolean post_msg_direct = FALSE;
9441
9442         MMPLAYER_FENTER();
9443
9444         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9445
9446         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9447                         player->not_supported_codec, player->can_support_codec);
9448
9449         if (player->not_found_demuxer) {
9450                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9451                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9452
9453                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9454                 MMPLAYER_FREEIF(msg_param.data);
9455
9456                 return MM_ERROR_NONE;
9457         }
9458
9459         if (player->not_supported_codec) {
9460                 if (player->can_support_codec) {
9461                         // There is one codec to play
9462                         post_msg_direct = TRUE;
9463                 } else {
9464                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9465                                 post_msg_direct = TRUE;
9466                 }
9467
9468                 if (post_msg_direct) {
9469                         MMMessageParamType msg_param;
9470                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9471
9472                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9473                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9474
9475                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9476                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9477                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9478                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9479
9480                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9481                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9482                         }
9483
9484                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9485
9486                         MMPLAYER_FREEIF(msg_param.data);
9487
9488                         return MM_ERROR_NONE;
9489                 } else {
9490                         // no any supported codec case
9491                         LOGW("not found any codec, posting error code to application.\n");
9492
9493                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9494                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9495                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9496                         } else {
9497                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9498                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9499                         }
9500
9501                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9502
9503                         MMPLAYER_FREEIF(msg_param.data);
9504                 }
9505         }
9506
9507         MMPLAYER_FLEAVE();
9508
9509         return MM_ERROR_NONE;
9510 }
9511
9512 static void __mmplayer_check_pipeline(mm_player_t* player)
9513 {
9514         GstState element_state = GST_STATE_VOID_PENDING;
9515         GstState element_pending_state = GST_STATE_VOID_PENDING;
9516         gint timeout = 0;
9517         int ret = MM_ERROR_NONE;
9518
9519         if (player->gapless.reconfigure) {
9520                 LOGW("pipeline is under construction.\n");
9521
9522                 MMPLAYER_PLAYBACK_LOCK(player);
9523                 MMPLAYER_PLAYBACK_UNLOCK(player);
9524
9525                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9526
9527                 /* wait for state transition */
9528                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9529
9530                 if (ret == GST_STATE_CHANGE_FAILURE)
9531                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9532         }
9533 }
9534
9535 /* NOTE : it should be able to call 'stop' anytime*/
9536 int
9537 _mmplayer_stop(MMHandleType hplayer) // @
9538 {
9539         mm_player_t* player = (mm_player_t*)hplayer;
9540         int ret = MM_ERROR_NONE;
9541
9542         MMPLAYER_FENTER();
9543
9544         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9545
9546         /* check current state */
9547         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9548
9549         /* check pipline building state */
9550         __mmplayer_check_pipeline(player);
9551         __mmplayer_reset_gapless_state(player);
9552
9553         /* NOTE : application should not wait for EOS after calling STOP */
9554         __mmplayer_cancel_eos_timer(player);
9555
9556         __mmplayer_unrealize_streaming_ext(player);
9557
9558         /* reset */
9559         player->doing_seek = FALSE;
9560
9561         /* stop pipeline */
9562         ret = __gst_stop(player);
9563
9564         if (ret != MM_ERROR_NONE)
9565                 LOGE("failed to stop player.\n");
9566
9567         MMPLAYER_FLEAVE();
9568
9569         return ret;
9570 }
9571
9572 int
9573 _mmplayer_pause(MMHandleType hplayer) // @
9574 {
9575         mm_player_t* player = (mm_player_t*)hplayer;
9576         gint64 pos_msec = 0;
9577         gboolean async = FALSE;
9578         gint ret = MM_ERROR_NONE;
9579
9580         MMPLAYER_FENTER();
9581
9582         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9583
9584         /* check current state */
9585         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9586
9587         /* check pipline building state */
9588         __mmplayer_check_pipeline(player);
9589
9590         switch (MMPLAYER_CURRENT_STATE(player)) {
9591         case MM_PLAYER_STATE_READY:
9592                 {
9593                         /* check prepare async or not.
9594                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9595                          */
9596                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9597                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9598                 }
9599                 break;
9600
9601         case MM_PLAYER_STATE_PLAYING:
9602                 {
9603                         /* NOTE : store current point to overcome some bad operation
9604                         *(returning zero when getting current position in paused state) of some
9605                         * elements
9606                         */
9607                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9608                                 LOGW("getting current position failed in paused\n");
9609
9610                         player->last_position = pos_msec;
9611                 }
9612                 break;
9613         }
9614
9615         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9616                 LOGD("doing async pause in case of ms buff src");
9617                 async = TRUE;
9618         }
9619
9620         /* pause pipeline */
9621         ret = __gst_pause(player, async);
9622
9623         if (ret != MM_ERROR_NONE)
9624                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9625
9626         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9627                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9628                         LOGE("failed to update display_rotation");
9629         }
9630
9631         MMPLAYER_FLEAVE();
9632
9633         return ret;
9634 }
9635
9636 int
9637 _mmplayer_resume(MMHandleType hplayer)
9638 {
9639         mm_player_t* player = (mm_player_t*)hplayer;
9640         int ret = MM_ERROR_NONE;
9641         gboolean async = FALSE;
9642
9643         MMPLAYER_FENTER();
9644
9645         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9646
9647         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9648         if (ret != MM_ERROR_NONE) {
9649                 LOGE("failed to acquire sound focus.\n");
9650                 return ret;
9651         }
9652
9653         /* check current state */
9654         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9655
9656         ret = __gst_resume(player, async);
9657
9658         if (ret != MM_ERROR_NONE)
9659                 LOGE("failed to resume player.\n");
9660
9661         MMPLAYER_FLEAVE();
9662
9663         return ret;
9664 }
9665
9666 int
9667 __mmplayer_set_play_count(mm_player_t* player, gint count)
9668 {
9669         MMHandleType attrs = 0;
9670
9671         MMPLAYER_FENTER();
9672
9673         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9674
9675         attrs =  MMPLAYER_GET_ATTRS(player);
9676         if (!attrs) {
9677                 LOGE("fail to get attributes.\n");
9678                 return MM_ERROR_PLAYER_INTERNAL;
9679         }
9680
9681         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9682         if (mmf_attrs_commit(attrs)) /* return -1 if error */
9683                 LOGE("failed to commit\n");
9684
9685         MMPLAYER_FLEAVE();
9686
9687         return  MM_ERROR_NONE;
9688 }
9689
9690 int
9691 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9692 {
9693         mm_player_t* player = (mm_player_t*)hplayer;
9694         gint64 start_pos = 0;
9695         gint64 end_pos = 0;
9696         gint infinity = -1;
9697
9698         MMPLAYER_FENTER();
9699
9700         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9701         MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9702
9703         player->section_repeat = TRUE;
9704         player->section_repeat_start = start;
9705         player->section_repeat_end = end;
9706
9707         start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9708         end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9709
9710         __mmplayer_set_play_count(player, infinity);
9711
9712         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9713                                         player->playback_rate,
9714                                         GST_FORMAT_TIME,
9715                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9716                                         GST_SEEK_TYPE_SET, start_pos,
9717                                         GST_SEEK_TYPE_SET, end_pos))) {
9718                 LOGE("failed to activate section repeat\n");
9719
9720                 return MM_ERROR_PLAYER_SEEK;
9721         }
9722
9723         LOGD("succeeded to set section repeat from %d to %d\n",
9724                 player->section_repeat_start, player->section_repeat_end);
9725
9726         MMPLAYER_FLEAVE();
9727
9728         return  MM_ERROR_NONE;
9729 }
9730
9731 static int
9732 __mmplayer_set_pcm_extraction(mm_player_t* player)
9733 {
9734         gint64 start_nsec = 0;
9735         gint64 end_nsec = 0;
9736         gint64 dur_nsec = 0;
9737         gint64 dur_msec = 0;
9738         int required_start = 0;
9739         int required_end = 0;
9740         int ret = 0;
9741
9742         MMPLAYER_FENTER();
9743
9744         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9745
9746         mm_attrs_multiple_get(player->attrs,
9747                 NULL,
9748                 "pcm_extraction_start_msec", &required_start,
9749                 "pcm_extraction_end_msec", &required_end,
9750                 NULL);
9751
9752         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9753
9754         if (required_start == 0 && required_end == 0) {
9755                 LOGD("extracting entire stream");
9756                 return MM_ERROR_NONE;
9757         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9758                 LOGD("invalid range for pcm extraction");
9759                 return MM_ERROR_INVALID_ARGUMENT;
9760         }
9761
9762         /* get duration */
9763         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9764         if (!ret) {
9765                 LOGE("failed to get duration");
9766                 return MM_ERROR_PLAYER_INTERNAL;
9767         }
9768         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9769
9770         if (dur_msec < required_end) {
9771                 // FIXME
9772                 LOGD("invalid end pos for pcm extraction");
9773                 return MM_ERROR_INVALID_ARGUMENT;
9774         }
9775
9776         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9777         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9778
9779         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9780                                         1.0,
9781                                         GST_FORMAT_TIME,
9782                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9783                                         GST_SEEK_TYPE_SET, start_nsec,
9784                                         GST_SEEK_TYPE_SET, end_nsec))) {
9785                 LOGE("failed to seek for pcm extraction\n");
9786
9787                 return MM_ERROR_PLAYER_SEEK;
9788         }
9789
9790         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9791
9792         MMPLAYER_FLEAVE();
9793
9794         return MM_ERROR_NONE;
9795 }
9796
9797 int
9798 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9799 {
9800         mm_player_t* player = (mm_player_t*)hplayer;
9801         gint64 cur_pos = 0;
9802         gint onetime = 1;
9803
9804         MMPLAYER_FENTER();
9805
9806         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9807
9808         player->section_repeat = FALSE;
9809
9810         __mmplayer_set_play_count(player, onetime);
9811
9812         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9813
9814         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9815                                         1.0,
9816                                         GST_FORMAT_TIME,
9817                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9818                                         GST_SEEK_TYPE_SET, cur_pos,
9819                                         GST_SEEK_TYPE_SET, player->duration))) {
9820                 LOGE("failed to deactivate section repeat\n");
9821
9822                 return MM_ERROR_PLAYER_SEEK;
9823         }
9824
9825         MMPLAYER_FENTER();
9826
9827         return MM_ERROR_NONE;
9828 }
9829
9830 int
9831 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9832 {
9833         mm_player_t* player = (mm_player_t*)hplayer;
9834         gint64 pos_msec = 0;
9835         int ret = MM_ERROR_NONE;
9836         int mute = FALSE;
9837         signed long long start = 0, stop = 0;
9838         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9839         MMPLAYER_FENTER();
9840
9841         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9842         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9843
9844         /* The sound of video is not supported under 0.0 and over 2.0. */
9845         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9846                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9847                         mute = TRUE;
9848         }
9849         _mmplayer_set_mute(hplayer, mute);
9850
9851         if (player->playback_rate == rate)
9852                 return MM_ERROR_NONE;
9853
9854         /* If the position is reached at start potion during fast backward, EOS is posted.
9855          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9856          * */
9857         player->playback_rate = rate;
9858
9859         current_state = MMPLAYER_CURRENT_STATE(player);
9860
9861         if (current_state != MM_PLAYER_STATE_PAUSED)
9862                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9863
9864         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9865
9866         if ((current_state == MM_PLAYER_STATE_PAUSED)
9867                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9868                 LOGW("returning last point : %lld\n", player->last_position);
9869                 pos_msec = player->last_position;
9870         }
9871
9872
9873         if (rate >= 0) {
9874                 start = pos_msec;
9875                 stop = GST_CLOCK_TIME_NONE;
9876         } else {
9877                 start = GST_CLOCK_TIME_NONE;
9878                 stop = pos_msec;
9879         }
9880         if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9881                                 rate,
9882                                 GST_FORMAT_TIME,
9883                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9884                                 GST_SEEK_TYPE_SET, start,
9885                                 GST_SEEK_TYPE_SET, stop))) {
9886                 LOGE("failed to set speed playback\n");
9887                 return MM_ERROR_PLAYER_SEEK;
9888         }
9889
9890         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9891
9892         MMPLAYER_FLEAVE();
9893
9894         return MM_ERROR_NONE;;
9895 }
9896
9897 int
9898 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9899 {
9900         mm_player_t* player = (mm_player_t*)hplayer;
9901         int ret = MM_ERROR_NONE;
9902
9903         MMPLAYER_FENTER();
9904
9905         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9906
9907         /* check pipline building state */
9908         __mmplayer_check_pipeline(player);
9909
9910         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9911
9912         MMPLAYER_FLEAVE();
9913
9914         return ret;
9915 }
9916
9917 int
9918 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
9919 {
9920         mm_player_t* player = (mm_player_t*)hplayer;
9921         int ret = MM_ERROR_NONE;
9922
9923         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9924
9925         ret = __gst_get_position(player, format, position);
9926
9927         return ret;
9928 }
9929
9930 int
9931 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
9932 {
9933         mm_player_t* player = (mm_player_t*)hplayer;
9934         int ret = MM_ERROR_NONE;
9935
9936         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9937
9938         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9939
9940         return ret;
9941 }
9942
9943 int
9944 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
9945 {
9946         mm_player_t* player = (mm_player_t*)hplayer;
9947         int ret = MM_ERROR_NONE;
9948
9949         MMPLAYER_FENTER();
9950
9951         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9952
9953         ret = __gst_adjust_subtitle_position(player, format, position);
9954
9955         MMPLAYER_FLEAVE();
9956
9957         return ret;
9958 }
9959 int
9960 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
9961 {
9962         mm_player_t* player = (mm_player_t*)hplayer;
9963         int ret = MM_ERROR_NONE;
9964
9965         MMPLAYER_FENTER();
9966
9967         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9968
9969         ret = __gst_adjust_video_position(player, offset);
9970
9971         MMPLAYER_FLEAVE();
9972
9973         return ret;
9974 }
9975
9976 static gboolean
9977 __mmplayer_is_midi_type(gchar* str_caps)
9978 {
9979         if ((g_strrstr(str_caps, "audio/midi")) ||
9980                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9981                 (g_strrstr(str_caps, "application/x-smaf")) ||
9982                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9983                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9984                 (g_strrstr(str_caps, "audio/xmf")) ||
9985                 (g_strrstr(str_caps, "audio/mxmf"))) {
9986                 LOGD("midi\n");
9987                 return TRUE;
9988         }
9989
9990         return FALSE;
9991 }
9992
9993 static gboolean
9994 __mmplayer_is_only_mp3_type(gchar *str_caps)
9995 {
9996         if (g_strrstr(str_caps, "application/x-id3") ||
9997                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9998                 return TRUE;
9999         return FALSE;
10000 }
10001
10002 static void
10003 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10004 {
10005         GstStructure* caps_structure = NULL;
10006         gint samplerate = 0;
10007         gint channels = 0;
10008
10009         MMPLAYER_FENTER();
10010         MMPLAYER_RETURN_IF_FAIL(player && caps);
10011
10012         caps_structure = gst_caps_get_structure(caps, 0);
10013
10014         /* set stream information */
10015         gst_structure_get_int(caps_structure, "rate", &samplerate);
10016         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10017
10018         gst_structure_get_int(caps_structure, "channels", &channels);
10019         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10020
10021         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
10022 }
10023
10024 static void
10025 __mmplayer_update_content_type_info(mm_player_t* player)
10026 {
10027         MMPLAYER_FENTER();
10028         MMPLAYER_RETURN_IF_FAIL(player && player->type);
10029
10030         if (__mmplayer_is_midi_type(player->type)) {
10031                 player->bypass_audio_effect = TRUE;
10032         } else if (g_strrstr(player->type, "application/x-hls")) {
10033                 /* If it can't know exact type when it parses uri because of redirection case,
10034                  * it will be fixed by typefinder or when doing autoplugging.
10035                  */
10036                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10037                 if (player->streamer) {
10038                         player->streamer->is_adaptive_streaming = TRUE;
10039                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10040                         player->streamer->buffering_req.runtime_second = 5;
10041                 }
10042         } else if (g_strrstr(player->type, "application/dash+xml")) {
10043                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10044         }
10045
10046         MMPLAYER_FLEAVE();
10047 }
10048
10049 static void
10050 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10051 GstCaps *caps, gpointer data)
10052 {
10053         mm_player_t* player = (mm_player_t*)data;
10054         GstPad* pad = NULL;
10055
10056         MMPLAYER_FENTER();
10057
10058         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10059
10060         /* store type string */
10061         MMPLAYER_FREEIF(player->type);
10062         player->type = gst_caps_to_string(caps);
10063         if (player->type)
10064                 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10065
10066         if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10067                 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10068                 (g_strrstr(player->type, "audio/x-raw-int"))) {
10069                 LOGE("not support media format\n");
10070
10071                 if (player->msg_posted == FALSE) {
10072                         MMMessageParamType msg_param;
10073                         memset(&msg_param, 0, sizeof(MMMessageParamType));
10074
10075                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10076                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10077
10078                         /* don't post more if one was sent already */
10079                         player->msg_posted = TRUE;
10080                 }
10081                 return;
10082         }
10083
10084         __mmplayer_update_content_type_info(player);
10085
10086         pad = gst_element_get_static_pad(tf, "src");
10087         if (!pad) {
10088                 LOGE("fail to get typefind src pad.\n");
10089                 return;
10090         }
10091
10092         if (player->use_decodebin) {
10093                 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10094                         gboolean async = FALSE;
10095                         LOGE("failed to autoplug %s\n", player->type);
10096
10097                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10098
10099                         if (async && player->msg_posted == FALSE)
10100                                 __mmplayer_handle_missed_plugin(player);
10101
10102                         goto DONE;
10103                 }
10104         } else {
10105                 /* try to plug */
10106                 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10107                         gboolean async = FALSE;
10108                         LOGE("failed to autoplug %s\n", player->type);
10109
10110                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10111
10112                         if (async && player->msg_posted == FALSE)
10113                                 __mmplayer_handle_missed_plugin(player);
10114
10115                         goto DONE;
10116                 }
10117
10118                 /* finish autopluging if no dynamic pad waiting */
10119                 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10120                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
10121                                 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10122                 }
10123         }
10124
10125 DONE:
10126         gst_object_unref(GST_OBJECT(pad));
10127
10128         MMPLAYER_FLEAVE();
10129
10130         return;
10131 }
10132
10133 static GstElement *
10134 __mmplayer_create_decodebin(mm_player_t* player)
10135 {
10136         GstElement *decodebin = NULL;
10137
10138         MMPLAYER_FENTER();
10139
10140         /* create decodebin */
10141         decodebin = gst_element_factory_make("decodebin", NULL);
10142
10143         if (!decodebin) {
10144                 LOGE("fail to create decodebin\n");
10145                 goto ERROR;
10146         }
10147
10148         /* raw pad handling signal */
10149         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10150                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10151
10152         /* no-more-pad pad handling signal */
10153         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10154                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10155
10156         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10157                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10158
10159         /* This signal is emitted when a pad for which there is no further possible
10160            decoding is added to the decodebin.*/
10161         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10162                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10163
10164         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10165            before looking for any elements that can handle that stream.*/
10166         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10167                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10168
10169         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10170            before looking for any elements that can handle that stream.*/
10171         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10172                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10173
10174         /* This signal is emitted once decodebin has finished decoding all the data.*/
10175         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10176                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10177
10178         /* This signal is emitted when a element is added to the bin.*/
10179         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10180                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
10181
10182 ERROR:
10183         return decodebin;
10184 }
10185
10186 static gboolean
10187 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10188 {
10189         MMPlayerGstElement* mainbin = NULL;
10190         GstElement* decodebin = NULL;
10191         GstElement* queue2 = NULL;
10192         GstPad* sinkpad = NULL;
10193         GstPad* qsrcpad = NULL;
10194         gchar *caps_str = NULL;
10195         gint64 dur_bytes = 0L;
10196
10197         guint max_buffer_size_bytes = 0;
10198         gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10199
10200         MMPLAYER_FENTER();
10201         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10202
10203         mainbin = player->pipeline->mainbin;
10204
10205         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10206                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10207                 LOGD("creating http streaming buffering queue(queue2)\n");
10208
10209                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10210                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10211                 } else {
10212                         queue2 = gst_element_factory_make("queue2", "queue2");
10213                         if (!queue2) {
10214                                 LOGE("failed to create buffering queue element\n");
10215                                 goto ERROR;
10216                         }
10217
10218                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10219                                 LOGE("failed to add buffering queue\n");
10220                                 goto ERROR;
10221                         }
10222
10223                         sinkpad = gst_element_get_static_pad(queue2, "sink");
10224                         qsrcpad = gst_element_get_static_pad(queue2, "src");
10225
10226                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10227                                 LOGE("failed to link buffering queue\n");
10228                                 goto ERROR;
10229                         }
10230
10231                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10232                                 LOGE("fail to get duration.\n");
10233
10234                         LOGD("dur_bytes = %lld\n", dur_bytes);
10235
10236                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10237
10238                         if (dur_bytes > 0) {
10239                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10240                                         type = MUXED_BUFFER_TYPE_FILE;
10241                                 } else {
10242                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10243                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10244                                 }
10245                         } else {
10246                                 dur_bytes = 0;
10247                         }
10248
10249                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
10250                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10251                         if (!g_strrstr(player->type, "video/mpegts")) {
10252                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10253                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10254
10255                                 __mm_player_streaming_set_queue2(player->streamer,
10256                                                                                                 queue2,
10257                                                                                                 FALSE,
10258                                                                                                 max_buffer_size_bytes,
10259                                                                                                 player->ini.http_buffering_time,
10260                                                                                                 1.0,                                                            // no meaning
10261                                                                                                 player->ini.http_buffering_limit,       // no meaning
10262                                                                                                 type,
10263                                                                                                 player->http_file_buffering_path,
10264                                                                                                 (guint64)dur_bytes);
10265                         }
10266
10267                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10268                                 LOGE("failed to sync queue2 state with parent\n");
10269                                 goto ERROR;
10270                         }
10271
10272                         srcpad = qsrcpad;
10273
10274                         gst_object_unref(GST_OBJECT(sinkpad));
10275
10276                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10277                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10278                 }
10279         }
10280
10281         /* create decodebin */
10282         decodebin = __mmplayer_create_decodebin(player);
10283
10284         if (!decodebin) {
10285                 LOGE("can not create autoplug element\n");
10286                 goto ERROR;
10287         }
10288
10289         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10290                 LOGE("failed to add decodebin\n");
10291                 goto ERROR;
10292         }
10293
10294         /* to force caps on the decodebin element and avoid reparsing stuff by
10295         * typefind. It also avoids a deadlock in the way typefind activates pads in
10296         * the state change */
10297         g_object_set(decodebin, "sink-caps", caps, NULL);
10298
10299         sinkpad = gst_element_get_static_pad(decodebin, "sink");
10300
10301         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10302                 LOGE("failed to link decodebin\n");
10303                 goto ERROR;
10304         }
10305
10306         gst_object_unref(GST_OBJECT(sinkpad));
10307
10308         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10309         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10310
10311         /* set decodebin property about buffer in streaming playback. *
10312          * in case of hls, it does not need to have big buffer        *
10313          * because it is kind of adaptive streaming.                  */
10314         if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10315            (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10316                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10317                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10318                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10319
10320                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10321                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10322                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10323                 }
10324
10325                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10326                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
10327                                                                                         "low-percent", 1,   // 1%
10328                                                                                         "max-size-bytes", max_size_bytes,
10329                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
10330                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
10331         }
10332
10333         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10334                 LOGE("failed to sync decodebin state with parent\n");
10335                 goto ERROR;
10336         }
10337
10338         MMPLAYER_FLEAVE();
10339
10340         return TRUE;
10341
10342 ERROR:
10343
10344         MMPLAYER_FREEIF(caps_str);
10345
10346         if (sinkpad)
10347                 gst_object_unref(GST_OBJECT(sinkpad));
10348
10349         if (queue2) {
10350                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10351                  * You need to explicitly set elements to the NULL state before
10352                  * dropping the final reference, to allow them to clean up.
10353                  */
10354                 gst_element_set_state(queue2, GST_STATE_NULL);
10355
10356                 /* And, it still has a parent "player".
10357                  * You need to let the parent manage the object instead of unreffing the object directly.
10358                  */
10359                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10360                 gst_object_unref(queue2);
10361                 queue2 = NULL;
10362         }
10363
10364         if (decodebin) {
10365                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10366                  * You need to explicitly set elements to the NULL state before
10367                  * dropping the final reference, to allow them to clean up.
10368                  */
10369                 gst_element_set_state(decodebin, GST_STATE_NULL);
10370
10371                 /* And, it still has a parent "player".
10372                  * You need to let the parent manage the object instead of unreffing the object directly.
10373                  */
10374
10375                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10376                 gst_object_unref(decodebin);
10377                 decodebin = NULL;
10378         }
10379
10380         return FALSE;
10381 }
10382
10383 /* it will return first created element */
10384 static gboolean
10385 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10386 {
10387         MMPlayerGstElement* mainbin = NULL;
10388         const char* mime = NULL;
10389         const GList* item = NULL;
10390         const gchar* klass = NULL;
10391         GstCaps* res = NULL;
10392         gboolean skip = FALSE;
10393         GstPad* queue_pad = NULL;
10394         GstElement* queue = NULL;
10395         GstElement *element = NULL;
10396
10397         MMPLAYER_FENTER();
10398
10399         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10400
10401         mainbin = player->pipeline->mainbin;
10402
10403         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10404
10405         /* return if we got raw output */
10406         if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10407                 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10408
10409                 element = (GstElement*)gst_pad_get_parent(pad);
10410 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10411  * No queue will be added. I think it can caused breaking sound when playing raw audio
10412  * frames but there's no different. Decodebin also doesn't add with those wav fils.
10413  * Anyway, currentely raw-queue seems not necessary.
10414  */
10415 #if 1
10416                 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10417                  * has linked. if so, we need to add queue for quality of output. note that
10418                  * decodebin also has same problem.
10419                  */
10420                 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10421
10422                 /* add queue if needed */
10423                 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10424                         || g_strrstr(klass, "Parse")) &&  !g_str_has_prefix(mime, "text")) {
10425                         LOGD("adding raw queue\n");
10426
10427                         queue = gst_element_factory_make("queue", NULL);
10428                         if (!queue) {
10429                                 LOGW("failed to create queue\n");
10430                                 goto ERROR;
10431                         }
10432
10433                         /* warmup */
10434                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10435                                 LOGW("failed to set state READY to queue\n");
10436                                 goto ERROR;
10437                         }
10438
10439                         /* add to pipeline */
10440                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10441                                 LOGW("failed to add queue\n");
10442                                 goto ERROR;
10443                         }
10444
10445                         /* link queue */
10446                         queue_pad = gst_element_get_static_pad(queue, "sink");
10447
10448                         if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10449                                 LOGW("failed to link queue\n");
10450                                 goto ERROR;
10451                         }
10452                         gst_object_unref(GST_OBJECT(queue_pad));
10453                         queue_pad = NULL;
10454
10455                         /* running */
10456                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10457                                 LOGW("failed to set state PAUSED to queue\n");
10458                                 goto ERROR;
10459                         }
10460
10461                         /* replace given pad to queue:src */
10462                         pad = gst_element_get_static_pad(queue, "src");
10463                         if (!pad) {
10464                                 LOGW("failed to get pad from queue\n");
10465                                 goto ERROR;
10466                         }
10467                 }
10468 #endif
10469                 /* check if player can do start continually */
10470                 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10471
10472                 if (__mmplayer_link_sink(player, pad))
10473                         __mmplayer_gst_decode_callback(element, pad, player);
10474
10475                 gst_object_unref(GST_OBJECT(element));
10476                 element = NULL;
10477
10478                 return TRUE;
10479         }
10480
10481         item = player->factories;
10482         for (; item != NULL; item = item->next) {
10483                 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10484                 const GList *pads;
10485                 gint idx = 0;
10486
10487                 skip = FALSE;
10488
10489                 /* filtering exclude keyword */
10490                 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10491                         if (g_strrstr(GST_OBJECT_NAME(factory),
10492                                         player->ini.exclude_element_keyword[idx])) {
10493                                 LOGW("skipping [%s] by exculde keyword [%s]\n",
10494                                         GST_OBJECT_NAME(factory),
10495                                         player->ini.exclude_element_keyword[idx]);
10496
10497                                 skip = TRUE;
10498                                 break;
10499                         }
10500                 }
10501
10502                 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10503                         // omx decoder can not support mpeg4video data partitioned
10504                         // rtsp streaming didn't know mpeg4video data partitioned format
10505                         // so, if rtsp playback, player will skip omx_mpeg4dec.
10506                         LOGW("skipping [%s] when rtsp streaming \n",
10507                                         GST_OBJECT_NAME(factory));
10508
10509                         skip = TRUE;
10510                 }
10511
10512                 if (skip) continue;
10513
10514                 /* check factory class for filtering */
10515                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10516
10517                 /*parsers are not required in case of external feeder*/
10518                 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10519                         continue;
10520
10521                 /* NOTE : msl don't need to use image plugins.
10522                  * So, those plugins should be skipped for error handling.
10523                  */
10524                 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10525                         LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10526                         continue;
10527                 }
10528
10529                 /* check pad compatability */
10530                 for (pads = gst_element_factory_get_static_pad_templates(factory);
10531                                         pads != NULL; pads = pads->next) {
10532                         GstStaticPadTemplate *temp1 = pads->data;
10533                         GstCaps* static_caps = NULL;
10534
10535                         if (temp1->direction != GST_PAD_SINK
10536                                 || temp1->presence != GST_PAD_ALWAYS)
10537                                 continue;
10538
10539                         /* using existing caps */
10540                         if (GST_IS_CAPS(&temp1->static_caps.caps))
10541                                 static_caps = gst_caps_ref(temp1->static_caps.caps);
10542                         /* create one */
10543                         else
10544                                 static_caps = gst_caps_from_string(temp1->static_caps.string);
10545
10546                         res = gst_caps_intersect((GstCaps*)caps, static_caps);
10547                         gst_caps_unref(static_caps);
10548                         static_caps = NULL;
10549
10550                         if (res && !gst_caps_is_empty(res)) {
10551                                 GstElement *new_element;
10552                                 GList *elements = player->parsers;
10553                                 char *name_template = g_strdup(temp1->name_template);
10554                                 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10555                                 gst_caps_unref(res);
10556
10557                                 /* check ALP Codec can be used or not */
10558                                 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10559                                         /* consider mp3 audio only */
10560                                         if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10561                                                 /* try to use ALP decoder first instead of selected decoder */
10562                                                 GstElement *element = NULL;
10563                                                 GstElementFactory * element_facory;
10564                                                 gchar *path = NULL;
10565                                                 guint64 data_size = 0;
10566                                                 #define MIN_THRESHOLD_SIZE  320 * 1024 // 320K
10567                                                 struct stat sb;
10568
10569                                                 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10570
10571                                                 if (stat(path, &sb) == 0)
10572                                                         data_size = (guint64)sb.st_size;
10573                                                 LOGD("file size : %u", data_size);
10574
10575                                                 if (data_size > MIN_THRESHOLD_SIZE) {
10576                                                         LOGD("checking if ALP can be used or not");
10577                                                         element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10578                                                         if (element) {
10579                                                                 /* check availability because multi-instance is not supported */
10580                                                                 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10581
10582                                                                 if (ret != GST_STATE_CHANGE_SUCCESS) {
10583                                                                         // use just selected decoder
10584                                                                         gst_object_unref(element);
10585                                                                 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10586                                                                         // replace facotry to use omx
10587                                                                         /* clean  */
10588                                                                         gst_element_set_state(element, GST_STATE_NULL);
10589                                                                         gst_object_unref(element);
10590
10591                                                                         element_facory = gst_element_factory_find("omx_mp3dec");
10592                                                                         /* replace, otherwise use selected thing instead */
10593                                                                         if (element_facory) {
10594                                                                                 factory = element_facory;
10595                                                                                 name_to_plug = GST_OBJECT_NAME(factory);
10596                                                                         }
10597                                                                 }
10598                                                         }
10599                                                 }
10600                                         }
10601                                 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10602                                         if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10603                                                 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10604                                                 if (env != NULL) {
10605                                                         if (strncasecmp(env, "yes", 3) == 0) {
10606                                                                 LOGD("skipping [%s] by disabled\n", name_to_plug);
10607                                                                 MMPLAYER_FREEIF(name_template);
10608                                                                 continue;
10609                                                         }
10610                                                 }
10611                                         }
10612                                 }
10613
10614                                 LOGD("found %s to plug\n", name_to_plug);
10615
10616                                 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10617                                 if (!new_element) {
10618                                         LOGE("failed to create element [%s]. continue with next.\n",
10619                                                 GST_OBJECT_NAME(factory));
10620
10621                                         MMPLAYER_FREEIF(name_template);
10622
10623                                         continue;
10624                                 }
10625
10626                                 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10627                                  * because parser can accept its own output as input.
10628                                  */
10629                                 if (g_strrstr(klass, "Parser")) {
10630                                         gchar *selected = NULL;
10631
10632                                         for (; elements; elements = g_list_next(elements)) {
10633                                                 gchar *element_name = elements->data;
10634
10635                                                 if (g_strrstr(element_name, name_to_plug)) {
10636                                                         LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10637                                                         skip = TRUE;
10638                                                 }
10639                                         }
10640
10641                                         if (skip) {
10642                                                 MMPLAYER_FREEIF(name_template);
10643                                                 continue;
10644                                         }
10645
10646                                         selected = g_strdup(name_to_plug);
10647                                         player->parsers = g_list_append(player->parsers, selected);
10648                                 }
10649
10650                                 /* store specific handles for futher control */
10651                                 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10652                                         /* FIXIT : first value will be overwritten if there's more
10653                                          * than 1 demuxer/parser
10654                                          */
10655                                         LOGD("plugged element is demuxer. take it\n");
10656                                         mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10657                                         mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10658
10659                                         /*Added for multi audio support */
10660                                         if (g_strrstr(klass, "Demux")) {
10661                                                 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10662                                                 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10663
10664                                                 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10665                                                 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10666                                                 this code should be removed after mpegtsdemux is fixed */
10667                                                 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10668                                                         LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10669                                                         player->no_more_pad = TRUE;
10670                                                 }
10671                                         }
10672                                         if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10673                                                 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10674                                 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10675                                         if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10676                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10677                                                 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10678                                                 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10679                                         } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10680                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10681                                                 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10682                                                 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10683                                         }
10684                                         /* NOTE : IF one codec is found, add it to supported_codec and remove from
10685                                          * missing plugin. Both of them are used to check what's supported codec
10686                                          * before returning result of play start. And, missing plugin should be
10687                                          * updated here for multi track files.
10688                                          */
10689                                         if (g_str_has_prefix(mime, "video")) {
10690                                                 GstPad *src_pad = NULL;
10691                                                 GstPadTemplate *pad_templ = NULL;
10692                                                 GstCaps *caps = NULL;
10693                                                 gchar *caps_str = NULL;
10694
10695                                                 LOGD("found VIDEO decoder\n");
10696                                                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10697                                                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10698
10699                                                 src_pad = gst_element_get_static_pad(new_element, "src");
10700                                                 pad_templ = gst_pad_get_pad_template(src_pad);
10701                                                 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10702
10703                                                 caps_str = gst_caps_to_string(caps);
10704
10705                                                 /* clean */
10706                                                 MMPLAYER_FREEIF(caps_str);
10707                                                 gst_object_unref(src_pad);
10708                                         } else if (g_str_has_prefix(mime, "audio")) {
10709                                                 LOGD("found AUDIO decoder\n");
10710                                                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10711                                                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10712                                         }
10713                                 }
10714
10715                                 if (!__mmplayer_close_link(player, pad, new_element,
10716                                                         name_template, gst_element_factory_get_static_pad_templates(factory))) {
10717                                         MMPLAYER_FREEIF(name_template);
10718                                         if (player->keep_detecting_vcodec)
10719                                                 continue;
10720
10721                                         /* Link is failed even though a supportable codec is found. */
10722                                         __mmplayer_check_not_supported_codec(player, klass, mime);
10723
10724                                         LOGE("failed to call _close_link\n");
10725                                         return FALSE;
10726                                 }
10727
10728                                 MMPLAYER_FREEIF(name_template);
10729                                 return TRUE;
10730                         }
10731
10732                         gst_caps_unref(res);
10733                         break;
10734                 }
10735         }
10736
10737         /* There is no available codec. */
10738         __mmplayer_check_not_supported_codec(player, klass, mime);
10739
10740         MMPLAYER_FLEAVE();
10741         return FALSE;
10742
10743 ERROR:
10744         /* release */
10745         if (queue)
10746                 gst_object_unref(queue);
10747
10748         if (queue_pad)
10749                 gst_object_unref(queue_pad);
10750
10751         if (element)
10752                 gst_object_unref(element);
10753
10754         return FALSE;
10755 }
10756
10757
10758 static int
10759 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10760 {
10761         MMPLAYER_FENTER();
10762
10763         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10764         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10765
10766         LOGD("class : %s, mime : %s \n", factory_class, mime);
10767
10768         /* add missing plugin */
10769         /* NOTE : msl should check missing plugin for image mime type.
10770          * Some motion jpeg clips can have playable audio track.
10771          * So, msl have to play audio after displaying popup written video format not supported.
10772          */
10773         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10774                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10775                         LOGD("not found demuxer\n");
10776                         player->not_found_demuxer = TRUE;
10777                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10778
10779                         goto DONE;
10780                 }
10781         }
10782
10783         if (!g_strrstr(factory_class, "Demuxer")) {
10784                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10785                         LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10786                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10787
10788                         /* check that clip have multi tracks or not */
10789                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10790                                 LOGD("video plugin is already linked\n");
10791                         } else {
10792                                 LOGW("add VIDEO to missing plugin\n");
10793                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10794                         }
10795                 } else if (g_str_has_prefix(mime, "audio")) {
10796                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10797                                 LOGD("audio plugin is already linked\n");
10798                         } else {
10799                                 LOGW("add AUDIO to missing plugin\n");
10800                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10801                         }
10802                 }
10803         }
10804
10805 DONE:
10806         MMPLAYER_FLEAVE();
10807
10808         return MM_ERROR_NONE;
10809 }
10810
10811
10812 static void
10813 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10814 {
10815         mm_player_t* player = (mm_player_t*)data;
10816
10817         MMPLAYER_FENTER();
10818
10819         MMPLAYER_RETURN_IF_FAIL(player);
10820
10821         /* remove fakesink. */
10822         if (!__mmplayer_gst_remove_fakesink(player,
10823                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10824                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10825                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10826                  * source element are not same. To overcome this situation, this function will called
10827                  * several places and several times. Therefore, this is not an error case.
10828                  */
10829                 return;
10830         }
10831
10832         LOGD("pipeline has completely constructed\n");
10833
10834         if ((player->ini.async_start) &&
10835                 (player->msg_posted == FALSE) &&
10836                 (player->cmd >= MMPLAYER_COMMAND_START))
10837                 __mmplayer_handle_missed_plugin(player);
10838
10839         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10840 }
10841
10842 static gboolean
10843 __mmplayer_verify_next_play_path(mm_player_t *player)
10844 {
10845         MMHandleType attrs = 0;
10846         MMPlayerParseProfile profile;
10847         gint uri_idx = 0, check_cnt = 0;
10848         char *uri = NULL;
10849         gint mode = MM_PLAYER_PD_MODE_NONE;
10850         gint video = 0;
10851         gint count = 0;
10852         gint gapless = 0;
10853         guint num_of_list = 0;
10854
10855         MMPLAYER_FENTER();
10856
10857         LOGD("checking for gapless play");
10858
10859         if (player->pipeline->textbin) {
10860                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10861                 goto ERROR;
10862         }
10863
10864         attrs = MMPLAYER_GET_ATTRS(player);
10865         if (!attrs) {
10866                 LOGE("fail to get attributes.\n");
10867                 goto ERROR;
10868         }
10869
10870         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10871
10872 #ifdef TIZEN_TV
10873         /* gapless playback is not supported in case of video at TV profile. */
10874         if (video) {
10875                 LOGW("not support video gapless playback");
10876                 goto ERROR;
10877         }
10878 #endif
10879
10880         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10881                 if (mode == TRUE) {
10882                         LOGW("pd mode\n");
10883                         goto ERROR;
10884                 }
10885         }
10886
10887         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10888                 LOGE("can not get play count\n");
10889
10890         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10891                 LOGE("can not get gapless mode\n");
10892
10893         if (video && !gapless) {
10894                 LOGW("not enabled video gapless playback");
10895                 goto ERROR;
10896         }
10897
10898         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10899                 gapless = 1;
10900
10901         if (!gapless) {
10902                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10903                 goto ERROR;
10904         }
10905
10906         num_of_list = g_list_length(player->uri_info.uri_list);
10907
10908         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10909
10910         if (num_of_list == 0) {
10911                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10912                         LOGE("can not get profile_uri\n");
10913                         goto ERROR;
10914                 }
10915
10916                 if (!uri) {
10917                         LOGE("uri list is empty.\n");
10918                         goto ERROR;
10919                 }
10920
10921                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10922                 LOGD("add original path : %s ", uri);
10923
10924                 num_of_list = 1;
10925                 uri = NULL;
10926         }
10927
10928         uri_idx = player->uri_info.uri_idx;
10929
10930         while (TRUE) {
10931                 check_cnt++;
10932
10933                 if (check_cnt > num_of_list) {
10934                         LOGE("there is no valid uri.");
10935                         goto ERROR;
10936                 }
10937
10938                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10939
10940                 if (uri_idx < num_of_list-1) {
10941                         uri_idx++;
10942                 } else {
10943                         if ((count <= 1) && (count != -1)) {
10944                                 LOGD("no repeat.");
10945                                 goto ERROR;
10946                         } else if (count > 1) {
10947                                 /* decrease play count */
10948                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10949                                 count--;
10950
10951                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10952
10953                                 /* commit attribute */
10954                                 if (mmf_attrs_commit(attrs))
10955                                         LOGE("failed to commit attribute\n");
10956                         }
10957
10958                         /* count < 0 : repeat continually */
10959                         uri_idx = 0;
10960                 }
10961
10962                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10963                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10964
10965                 if (uri == NULL) {
10966                         LOGW("next uri does not exist\n");
10967                         continue;
10968                 }
10969
10970                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10971                         LOGE("failed to parse profile\n");
10972                         continue;
10973                 }
10974
10975                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10976                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10977                         LOGW("uri type is not supported(%d).", profile.uri_type);
10978                         continue;
10979                 }
10980
10981                 break;
10982         }
10983
10984         player->uri_info.uri_idx = uri_idx;
10985         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10986
10987         if (mmf_attrs_commit(player->attrs)) {
10988                 LOGE("failed to commit.\n");
10989                 goto ERROR;
10990         }
10991
10992         LOGD("next uri %s(%d)\n", uri, uri_idx);
10993
10994         return TRUE;
10995
10996 ERROR:
10997
10998         LOGE("unable to play next path. EOS will be posted soon.\n");
10999         return FALSE;
11000 }
11001
11002 static void
11003 __mmplayer_initialize_next_play(mm_player_t *player)
11004 {
11005         int i;
11006
11007         MMPLAYER_FENTER();
11008
11009         player->smooth_streaming = FALSE;
11010         player->videodec_linked = 0;
11011         player->audiodec_linked = 0;
11012         player->videosink_linked = 0;
11013         player->audiosink_linked = 0;
11014         player->textsink_linked = 0;
11015         player->is_external_subtitle_present = FALSE;
11016         player->not_supported_codec = MISSING_PLUGIN_NONE;
11017         player->can_support_codec = FOUND_PLUGIN_NONE;
11018         player->pending_seek.is_pending = FALSE;
11019         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11020         player->pending_seek.pos = 0;
11021         player->msg_posted = FALSE;
11022         player->has_many_types = FALSE;
11023         player->no_more_pad = FALSE;
11024         player->not_found_demuxer = 0;
11025         player->doing_seek = FALSE;
11026         player->max_audio_channels = 0;
11027         player->is_subtitle_force_drop = FALSE;
11028         player->play_subtitle = FALSE;
11029         player->use_textoverlay = FALSE;
11030         player->adjust_subtitle_pos = 0;
11031
11032         player->updated_bitrate_count = 0;
11033         player->total_bitrate = 0;
11034         player->updated_maximum_bitrate_count = 0;
11035         player->total_maximum_bitrate = 0;
11036
11037         _mmplayer_track_initialize(player);
11038
11039         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11040                 player->bitrate[i] = 0;
11041                 player->maximum_bitrate[i] = 0;
11042         }
11043
11044         if (player->v_stream_caps) {
11045                 gst_caps_unref(player->v_stream_caps);
11046                 player->v_stream_caps = NULL;
11047         }
11048
11049         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11050         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11051
11052         /* clean found parsers */
11053         if (player->parsers) {
11054                 GList *parsers = player->parsers;
11055                 for (; parsers; parsers = g_list_next(parsers)) {
11056                         gchar *name = parsers->data;
11057                         MMPLAYER_FREEIF(name);
11058                 }
11059                 g_list_free(player->parsers);
11060                 player->parsers = NULL;
11061         }
11062
11063         /* clean found audio decoders */
11064         if (player->audio_decoders) {
11065                 GList *a_dec = player->audio_decoders;
11066                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11067                         gchar *name = a_dec->data;
11068                         MMPLAYER_FREEIF(name);
11069                 }
11070                 g_list_free(player->audio_decoders);
11071                 player->audio_decoders = NULL;
11072         }
11073
11074         MMPLAYER_FLEAVE();
11075 }
11076
11077 static void
11078 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11079 {
11080         MMPlayerGstElement *mainbin = NULL;
11081         MMMessageParamType msg_param = {0,};
11082         GstElement *element = NULL;
11083         MMHandleType attrs = 0;
11084         char *uri = NULL;
11085         enum MainElementID elemId = MMPLAYER_M_NUM;
11086
11087         MMPLAYER_FENTER();
11088
11089         if ((player == NULL) ||
11090                 (player->pipeline == NULL) ||
11091                 (player->pipeline->mainbin == NULL)) {
11092                 LOGE("player is null.\n");
11093                 goto ERROR;
11094         }
11095
11096         mainbin = player->pipeline->mainbin;
11097         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11098
11099         attrs = MMPLAYER_GET_ATTRS(player);
11100         if (!attrs) {
11101                 LOGE("fail to get attributes.\n");
11102                 goto ERROR;
11103         }
11104
11105         /* Initialize Player values */
11106         __mmplayer_initialize_next_play(player);
11107
11108         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11109
11110         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11111                 LOGE("failed to parse profile\n");
11112                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11113                 goto ERROR;
11114         }
11115
11116         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11117                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11118                 LOGE("it's dash or hls. not support.");
11119                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11120                 goto ERROR;
11121         }
11122
11123         /* setup source */
11124         switch (player->profile.uri_type) {
11125         /* file source */
11126         case MM_PLAYER_URI_TYPE_FILE:
11127         {
11128                 LOGD("using filesrc for 'file://' handler.\n");
11129
11130                 element = gst_element_factory_make("filesrc", "source");
11131
11132                 if (!element) {
11133                         LOGE("failed to create filesrc\n");
11134                         break;
11135                 }
11136
11137                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
11138                 break;
11139         }
11140         case MM_PLAYER_URI_TYPE_URL_HTTP:
11141         {
11142                 gchar *user_agent, *proxy, *cookies, **cookie_list;
11143                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11144                 user_agent = proxy = cookies = NULL;
11145                 cookie_list = NULL;
11146
11147                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11148                 if (!element) {
11149                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11150                         break;
11151                 }
11152                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11153
11154                 /* get attribute */
11155                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11156                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11157                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11158                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11159
11160                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11161                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11162                         LOGD("get timeout from ini\n");
11163                         http_timeout = player->ini.http_timeout;
11164                 }
11165
11166                 /* get attribute */
11167                 SECURE_LOGD("location : %s\n", player->profile.uri);
11168                 SECURE_LOGD("cookies : %s\n", cookies);
11169                 SECURE_LOGD("proxy : %s\n", proxy);
11170                 SECURE_LOGD("user_agent :  %s\n", user_agent);
11171                 LOGD("timeout : %d\n", http_timeout);
11172
11173                 /* setting property to streaming source */
11174                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11175                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11176                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11177
11178                 /* check if prosy is vailid or not */
11179                 if (util_check_valid_url(proxy))
11180                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11181                 /* parsing cookies */
11182                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11183                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11184                 if (user_agent)
11185                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11186                 break;
11187         }
11188         default:
11189                 LOGE("not support uri type %d\n", player->profile.uri_type);
11190                 break;
11191         }
11192
11193         if (!element) {
11194                 LOGE("no source element was created.\n");
11195                 goto ERROR;
11196         }
11197
11198         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11199                 LOGE("failed to add source element to pipeline\n");
11200                 gst_object_unref(GST_OBJECT(element));
11201                 element = NULL;
11202                 goto ERROR;
11203         }
11204
11205         /* take source element */
11206         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11207         mainbin[MMPLAYER_M_SRC].gst = element;
11208
11209         element = NULL;
11210
11211         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11212                 if (player->streamer == NULL) {
11213                         player->streamer = __mm_player_streaming_create();
11214                         __mm_player_streaming_initialize(player->streamer);
11215                 }
11216
11217                 elemId = MMPLAYER_M_TYPEFIND;
11218                 element = gst_element_factory_make("typefind", "typefinder");
11219                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11220                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11221         } else {
11222                 elemId = MMPLAYER_M_AUTOPLUG;
11223                 element = __mmplayer_create_decodebin(player);
11224         }
11225
11226         /* check autoplug element is OK */
11227         if (!element) {
11228                 LOGE("can not create element(%d)\n", elemId);
11229                 goto ERROR;
11230         }
11231
11232         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11233                 LOGE("failed to add sinkbin to pipeline\n");
11234                 gst_object_unref(GST_OBJECT(element));
11235                 element = NULL;
11236                 goto ERROR;
11237         }
11238
11239         mainbin[elemId].id = elemId;
11240         mainbin[elemId].gst = element;
11241
11242         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11243                 LOGE("Failed to link src - autoplug(or typefind)\n");
11244                 goto ERROR;
11245         }
11246
11247         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11248                 LOGE("Failed to change state of src element\n");
11249                 goto ERROR;
11250         }
11251
11252         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11253                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11254                         LOGE("Failed to change state of decodebin\n");
11255                         goto ERROR;
11256                 }
11257         } else {
11258                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11259                         LOGE("Failed to change state of src element\n");
11260                         goto ERROR;
11261                 }
11262         }
11263
11264         player->gapless.stream_changed = TRUE;
11265         player->gapless.running = TRUE;
11266         MMPLAYER_FLEAVE();
11267         return;
11268
11269 ERROR:
11270         if (player) {
11271                 MMPLAYER_PLAYBACK_UNLOCK(player);
11272
11273                 if (!player->msg_posted) {
11274                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11275                         player->msg_posted = TRUE;
11276                 }
11277         }
11278         return;
11279 }
11280
11281 static gboolean
11282 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11283 {
11284         mm_player_selector_t *selector = &player->selector[type];
11285         MMPlayerGstElement *sinkbin = NULL;
11286         enum MainElementID selectorId = MMPLAYER_M_NUM;
11287         enum MainElementID sinkId = MMPLAYER_M_NUM;
11288         GstPad *srcpad = NULL;
11289         GstPad *sinkpad = NULL;
11290         gboolean send_notice = FALSE;
11291
11292         MMPLAYER_FENTER();
11293         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11294
11295         LOGD("type %d", type);
11296
11297         switch (type) {
11298         case MM_PLAYER_TRACK_TYPE_AUDIO:
11299                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11300                 sinkId = MMPLAYER_A_BIN;
11301                 sinkbin = player->pipeline->audiobin;
11302                 break;
11303         case MM_PLAYER_TRACK_TYPE_VIDEO:
11304                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11305                 sinkId = MMPLAYER_V_BIN;
11306                 sinkbin = player->pipeline->videobin;
11307                 send_notice = TRUE;
11308                 break;
11309         case MM_PLAYER_TRACK_TYPE_TEXT:
11310                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11311                 sinkId = MMPLAYER_T_BIN;
11312                 sinkbin = player->pipeline->textbin;
11313                 break;
11314         default:
11315                 LOGE("requested type is not supportable");
11316                 return FALSE;
11317                 break;
11318         }
11319
11320         if (player->pipeline->mainbin[selectorId].gst) {
11321                 gint n;
11322
11323                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11324
11325                 if (selector->event_probe_id != 0)
11326                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
11327                 selector->event_probe_id = 0;
11328
11329                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11330                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11331
11332                         if (srcpad && sinkpad) {
11333                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
11334                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11335                                 gst_pad_unlink(srcpad, sinkpad);
11336
11337                                 /* send custom event to sink pad to handle it at video sink */
11338                                 if (send_notice) {
11339                                         LOGD("send custom event to sinkpad");
11340                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11341                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11342                                         gst_pad_send_event(sinkpad, event);
11343                                 }
11344                         }
11345
11346                         gst_object_unref(sinkpad);
11347                         sinkpad = NULL;
11348                 }
11349                 gst_object_unref(srcpad);
11350                 srcpad = NULL;
11351
11352                 LOGD("selector release");
11353
11354                 /* release and unref requests pad from the selector */
11355                 for (n = 0; n < selector->channels->len; n++) {
11356                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11357                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11358                 }
11359                 g_ptr_array_set_size(selector->channels, 0);
11360
11361                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11362                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11363
11364                 player->pipeline->mainbin[selectorId].gst = NULL;
11365                 selector = NULL;
11366         }
11367
11368         return TRUE;
11369 }
11370
11371 static void
11372 __mmplayer_deactivate_old_path(mm_player_t *player)
11373 {
11374         MMPLAYER_FENTER();
11375         MMPLAYER_RETURN_IF_FAIL(player);
11376
11377         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11378                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11379                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11380                 LOGE("deactivate selector error");
11381                 goto ERROR;
11382         }
11383
11384         _mmplayer_track_destroy(player);
11385         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11386
11387         if (player->streamer) {
11388                 __mm_player_streaming_deinitialize(player->streamer);
11389                 __mm_player_streaming_destroy(player->streamer);
11390                 player->streamer = NULL;
11391         }
11392
11393         MMPLAYER_PLAYBACK_LOCK(player);
11394         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11395
11396         MMPLAYER_FLEAVE();
11397         return;
11398
11399 ERROR:
11400
11401         if (!player->msg_posted) {
11402                 MMMessageParamType msg = {0,};
11403
11404                 /*post error*/
11405                 msg.code = MM_ERROR_PLAYER_INTERNAL;
11406                 LOGE("next_uri_play> deactivate error");
11407
11408                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11409                 player->msg_posted = TRUE;
11410         }
11411         return;
11412 }
11413
11414 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11415 {
11416         int result = MM_ERROR_NONE;
11417         mm_player_t* player = (mm_player_t*) hplayer;
11418         MMPLAYER_FENTER();
11419
11420         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11421
11422         if (file_path) {
11423                 player->http_file_buffering_path = (gchar*)file_path;
11424                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11425         }
11426         MMPLAYER_FLEAVE();
11427         return result;
11428 }
11429
11430 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11431 {
11432         int result = MM_ERROR_NONE;
11433         mm_player_t* player = (mm_player_t*) hplayer;
11434         MMPLAYER_FENTER();
11435
11436         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11437
11438         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11439         if (mmf_attrs_commit(player->attrs)) {
11440                 LOGE("failed to commit the original uri.\n");
11441                 result = MM_ERROR_PLAYER_INTERNAL;
11442         } else {
11443                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11444                         LOGE("failed to add the original uri in the uri list.\n");
11445         }
11446
11447         MMPLAYER_FLEAVE();
11448         return result;
11449 }
11450
11451 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11452 {
11453         mm_player_t* player = (mm_player_t*) hplayer;
11454         guint num_of_list = 0;
11455
11456         MMPLAYER_FENTER();
11457
11458         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11459         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11460
11461         if (player->pipeline && player->pipeline->textbin) {
11462                 LOGE("subtitle path is enabled.\n");
11463                 return MM_ERROR_PLAYER_INVALID_STATE;
11464         }
11465
11466         num_of_list = g_list_length(player->uri_info.uri_list);
11467
11468         if (is_first_path == TRUE) {
11469                 if (num_of_list == 0) {
11470                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11471                         LOGD("add original path : %s", uri);
11472                 } else {
11473                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11474                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11475
11476                         LOGD("change original path : %s", uri);
11477                 }
11478         } else {
11479                 MMHandleType attrs = 0;
11480                 attrs = MMPLAYER_GET_ATTRS(player);
11481
11482                 if (num_of_list == 0) {
11483                         char *original_uri = NULL;
11484
11485                         if (attrs) {
11486                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11487
11488                                 if (!original_uri) {
11489                                         LOGE("there is no original uri.");
11490                                         return MM_ERROR_PLAYER_INVALID_STATE;
11491                                 }
11492
11493                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11494                                 player->uri_info.uri_idx = 0;
11495
11496                                 LOGD("add original path at first : %s(%d)", original_uri);
11497                         }
11498                 }
11499
11500                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11501                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11502         }
11503
11504         MMPLAYER_FLEAVE();
11505         return MM_ERROR_NONE;
11506 }
11507
11508 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11509 {
11510         mm_player_t* player = (mm_player_t*) hplayer;
11511         char *next_uri = NULL;
11512         guint num_of_list = 0;
11513
11514         MMPLAYER_FENTER();
11515         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11516
11517         num_of_list = g_list_length(player->uri_info.uri_list);
11518
11519         if (num_of_list > 0) {
11520                 gint uri_idx = player->uri_info.uri_idx;
11521
11522                 if (uri_idx < num_of_list-1)
11523                         uri_idx++;
11524                 else
11525                         uri_idx = 0;
11526
11527                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11528                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11529
11530                 *uri = g_strdup(next_uri);
11531         }
11532
11533         MMPLAYER_FLEAVE();
11534         return MM_ERROR_NONE;
11535 }
11536
11537 static void
11538 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
11539 GstCaps *caps, gpointer data)
11540 {
11541         mm_player_t* player = (mm_player_t*)data;
11542         const gchar* klass = NULL;
11543         const gchar* mime = NULL;
11544         gchar* caps_str = NULL;
11545
11546         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11547         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11548         caps_str = gst_caps_to_string(caps);
11549
11550         LOGW("unknown type of caps : %s from %s",
11551                                         caps_str, GST_ELEMENT_NAME(elem));
11552
11553         MMPLAYER_FREEIF(caps_str);
11554
11555         /* There is no available codec. */
11556         __mmplayer_check_not_supported_codec(player, klass, mime);
11557 }
11558
11559 static gboolean
11560 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
11561 GstCaps * caps,  gpointer data)
11562 {
11563         mm_player_t* player = (mm_player_t*)data;
11564         const char* mime = NULL;
11565         gboolean ret = TRUE;
11566
11567         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11568         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11569
11570         if (g_str_has_prefix(mime, "audio")) {
11571                 GstStructure* caps_structure = NULL;
11572                 gint samplerate = 0;
11573                 gint channels = 0;
11574                 gchar *caps_str = NULL;
11575
11576                 caps_structure = gst_caps_get_structure(caps, 0);
11577                 gst_structure_get_int(caps_structure, "rate", &samplerate);
11578                 gst_structure_get_int(caps_structure, "channels", &channels);
11579
11580                 if ((channels > 0 && samplerate == 0)) {
11581                         LOGD("exclude audio...");
11582                         ret = FALSE;
11583                 }
11584
11585                 caps_str = gst_caps_to_string(caps);
11586                 /* set it directly because not sent by TAG */
11587                 if (g_strrstr(caps_str, "mobile-xmf"))
11588                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11589                 MMPLAYER_FREEIF(caps_str);
11590         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11591                 MMMessageParamType msg_param;
11592                 memset(&msg_param, 0, sizeof(MMMessageParamType));
11593                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11594                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11595                 LOGD("video file is not supported on this device");
11596                 ret = FALSE;
11597         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11598                 LOGD("already video linked");
11599                 ret = FALSE;
11600         } else {
11601                 LOGD("found new stream");
11602         }
11603
11604         return ret;
11605 }
11606
11607 static gint
11608 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
11609 GstCaps* caps, GstElementFactory* factory, gpointer data)
11610 {
11611         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11612          We are defining our own and will be removed when it actually exposed */
11613         typedef enum {
11614                 GST_AUTOPLUG_SELECT_TRY,
11615                 GST_AUTOPLUG_SELECT_EXPOSE,
11616                 GST_AUTOPLUG_SELECT_SKIP
11617         } GstAutoplugSelectResult;
11618
11619         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11620         mm_player_t* player = (mm_player_t*)data;
11621
11622         gchar* factory_name = NULL;
11623         gchar* caps_str = NULL;
11624         const gchar* klass = NULL;
11625         gint idx = 0;
11626         int surface_type = 0;
11627
11628         factory_name = GST_OBJECT_NAME(factory);
11629         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11630         caps_str = gst_caps_to_string(caps);
11631
11632         LOGD("found new element [%s] to link", factory_name);
11633
11634         /* store type string */
11635         if (player->type == NULL) {
11636                 player->type = gst_caps_to_string(caps);
11637                 __mmplayer_update_content_type_info(player);
11638         }
11639
11640         /* To support evasimagesink, omx is excluded temporarily*/
11641         mm_attrs_get_int_by_name(player->attrs,
11642                                 "display_surface_type", &surface_type);
11643         LOGD("check display surface type attribute: %d", surface_type);
11644         if (surface_type == MM_DISPLAY_SURFACE_EVAS && strstr(factory_name, "omx")) {
11645                 LOGW("skipping [%s] for supporting evasimagesink temporarily.\n", factory_name);
11646                 result = GST_AUTOPLUG_SELECT_SKIP;
11647                 goto DONE;
11648         }
11649
11650         /* filtering exclude keyword */
11651         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11652                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11653                         LOGW("skipping [%s] by exculde keyword [%s]\n",
11654                         factory_name, player->ini.exclude_element_keyword[idx]);
11655
11656                         // NOTE : does we need to check n_value against the number of item selected?
11657                         result = GST_AUTOPLUG_SELECT_SKIP;
11658                         goto DONE;
11659                 }
11660         }
11661
11662         /* check factory class for filtering */
11663         /* NOTE : msl don't need to use image plugins.
11664          * So, those plugins should be skipped for error handling.
11665          */
11666         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11667                 LOGD("skipping [%s] by not required\n", factory_name);
11668                 result = GST_AUTOPLUG_SELECT_SKIP;
11669                 goto DONE;
11670         }
11671
11672         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11673                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11674                 // TO CHECK : subtitle if needed, add subparse exception.
11675                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11676                 result = GST_AUTOPLUG_SELECT_SKIP;
11677                 goto DONE;
11678         }
11679
11680         if (g_strrstr(factory_name, "mpegpsdemux")) {
11681                 LOGD("skipping PS container - not support\n");
11682                 result = GST_AUTOPLUG_SELECT_SKIP;
11683                 goto DONE;
11684         }
11685
11686         if (g_strrstr(factory_name, "mssdemux"))
11687                 player->smooth_streaming = TRUE;
11688
11689         /* check ALP Codec can be used or not */
11690         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11691                 GstStructure* str = NULL;
11692                 gint channels = 0;
11693
11694                 str = gst_caps_get_structure(caps, 0);
11695                 if (str) {
11696                         gst_structure_get_int(str, "channels", &channels);
11697
11698                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11699                         if (player->max_audio_channels < channels)
11700                                 player->max_audio_channels = channels;
11701                 }
11702                 /* set stream information */
11703                 if (!player->audiodec_linked)
11704                         __mmplayer_set_audio_attrs(player, caps);
11705         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11706                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11707                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11708                         /* prepare resource manager for video decoder */
11709                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11710
11711                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11712                                 /* prepare resource manager for video decoder */
11713                                 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11714                                         if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11715                                                 != MM_ERROR_NONE) {
11716                                                 LOGW("could not prepare for video_decoder resource, skip it.");
11717                                                 result = GST_AUTOPLUG_SELECT_SKIP;
11718                                                 goto DONE;
11719                                         }
11720                                 }
11721                         }
11722                 }
11723         }
11724
11725         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11726                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11727                 gint stype = 0;
11728                 gint width = 0;
11729                 GstStructure *str = NULL;
11730                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11731
11732                 /* don't make video because of not required */
11733                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11734                         (player->set_mode.media_packet_video_stream == FALSE)) {
11735                         LOGD("no video because it's not required. -> return expose");
11736                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11737                         goto DONE;
11738                 }
11739
11740                 /* get w/h for omx state-tune */
11741                 str = gst_caps_get_structure(caps, 0);
11742                 gst_structure_get_int(str, "width", &width);
11743
11744                 if (width != 0) {
11745                         if (player->v_stream_caps) {
11746                                 gst_caps_unref(player->v_stream_caps);
11747                                 player->v_stream_caps = NULL;
11748                         }
11749
11750                         player->v_stream_caps = gst_caps_copy(caps);
11751                         LOGD("take caps for video state tune");
11752                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11753                 }
11754         }
11755
11756         if (g_strrstr(klass, "Decoder")) {
11757                 const char* mime = NULL;
11758                 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11759
11760                 if (g_str_has_prefix(mime, "video")) {
11761                         // __mmplayer_check_video_zero_cpoy(player, factory);
11762
11763                         player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11764                         player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11765
11766                         player->videodec_linked = 1;
11767                 } else if (g_str_has_prefix(mime, "audio")) {
11768                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11769                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11770
11771                         player->audiodec_linked = 1;
11772                 }
11773         }
11774
11775 DONE:
11776         MMPLAYER_FREEIF(caps_str);
11777
11778         return result;
11779 }
11780
11781
11782 #if 0
11783 static GValueArray*
11784 __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad,
11785 GstCaps * caps,  gpointer data)
11786 {
11787         //mm_player_t* player = (mm_player_t*)data;
11788
11789         LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11790         gst_caps_to_string(caps),
11791         GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11792
11793         return NULL;
11794 }
11795 #endif
11796
11797 static void
11798 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11799 gpointer data) // @
11800 {
11801         //mm_player_t* player = (mm_player_t*)data;
11802         GstCaps* caps = NULL;
11803
11804         LOGD("[Decodebin2] pad-removed signal\n");
11805
11806         caps = gst_pad_query_caps(new_pad, NULL);
11807         if (caps) {
11808                 gchar* caps_str = NULL;
11809                 caps_str = gst_caps_to_string(caps);
11810
11811                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11812
11813                 MMPLAYER_FREEIF(caps_str);
11814         }
11815 }
11816
11817 static void
11818 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11819 {
11820         mm_player_t* player = (mm_player_t*)data;
11821
11822         MMPLAYER_FENTER();
11823         MMPLAYER_RETURN_IF_FAIL(player);
11824
11825         LOGD("__mmplayer_gst_decode_drained");
11826
11827         if (player->use_deinterleave == TRUE) {
11828                 LOGD("group playing mode.");
11829                 return;
11830         }
11831
11832         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11833                 LOGW("Fail to get cmd lock");
11834                 return;
11835         }
11836
11837         if (!__mmplayer_verify_next_play_path(player)) {
11838                 LOGD("decoding is finished.");
11839                 __mmplayer_reset_gapless_state(player);
11840                 MMPLAYER_CMD_UNLOCK(player);
11841                 return;
11842         }
11843
11844         player->gapless.reconfigure = TRUE;
11845         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11846         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11847
11848         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11849         __mmplayer_deactivate_old_path(player);
11850         MMPLAYER_CMD_UNLOCK(player);
11851
11852         MMPLAYER_FLEAVE();
11853 }
11854
11855 static void
11856 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11857 {
11858         mm_player_t* player = (mm_player_t*)data;
11859         const gchar* klass = NULL;
11860         gchar* factory_name = NULL;
11861
11862         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11863         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11864
11865         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11866
11867         if (__mmplayer_add_dump_buffer_probe(player, element))
11868                 LOGD("add buffer probe");
11869
11870         //<-
11871         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11872                 gchar* selected = NULL;
11873                 selected = g_strdup(GST_ELEMENT_NAME(element));
11874                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11875         }
11876         //-> temp code
11877
11878         if (g_strrstr(klass, "Parser")) {
11879                 gchar* selected = NULL;
11880
11881                 selected = g_strdup(factory_name);
11882                 player->parsers = g_list_append(player->parsers, selected);
11883         }
11884
11885         if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
11886                 /* FIXIT : first value will be overwritten if there's more
11887                  * than 1 demuxer/parser
11888                  */
11889
11890                 //LOGD("plugged element is demuxer. take it\n");
11891                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11892                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11893
11894                 /*Added for multi audio support */ // Q. del?
11895                 if (g_strrstr(klass, "Demux")) {
11896                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11897                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11898                 }
11899         }
11900
11901         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11902                 int surface_type = 0;
11903
11904                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11905         }
11906
11907         // to support trust-zone only
11908         if (g_strrstr(factory_name, "asfdemux")) {
11909                 LOGD("set file-location %s\n", player->profile.uri);
11910                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11911
11912                 if (player->video_hub_download_mode == TRUE)
11913                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11914         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11915                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11916                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11917         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11918                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11919                         (__mmplayer_is_only_mp3_type(player->type))) {
11920                         LOGD("[mpegaudioparse] set streaming pull mode.");
11921                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11922                 }
11923         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
11924                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11925
11926
11927         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11928                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11929                 LOGD("plugged element is multiqueue. take it\n");
11930
11931                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11932                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11933
11934                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11935                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
11936                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11937                         __mm_player_streaming_set_multiqueue(player->streamer,
11938                                 element,
11939                                 TRUE,
11940                                 player->ini.http_buffering_time,
11941                                 1.0,
11942                                 player->ini.http_buffering_limit);
11943
11944                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11945                 }
11946         }
11947
11948         return;
11949 }
11950
11951 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11952 {
11953         MMPLAYER_FENTER();
11954         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11955
11956         if (MMPLAYER_IS_STREAMING(player))
11957                 return FALSE;
11958
11959         /* This callback can be set to music player only. */
11960         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11961                 LOGW("audio callback is not supported for video");
11962                 return FALSE;
11963         }
11964
11965         if (player->audio_stream_cb) {
11966                 GstPad *pad = NULL;
11967
11968                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11969
11970                 if (!pad) {
11971                         LOGE("failed to get sink pad from audiosink to probe data\n");
11972                         return FALSE;
11973                 }
11974                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11975                         __mmplayer_audio_stream_probe, player, NULL);
11976
11977                 gst_object_unref(pad);
11978
11979                 pad = NULL;
11980         } else {
11981                 LOGE("There is no audio callback to configure.\n");
11982                 return FALSE;
11983         }
11984
11985         MMPLAYER_FLEAVE();
11986
11987         return TRUE;
11988 }
11989
11990 static void
11991 __mmplayer_init_factories(mm_player_t* player) // @
11992 {
11993         MMPLAYER_RETURN_IF_FAIL(player);
11994
11995         player->factories = gst_registry_feature_filter(gst_registry_get(),
11996                 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
11997         player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
11998 }
11999
12000 static void
12001 __mmplayer_release_factories(mm_player_t* player) // @
12002 {
12003         MMPLAYER_FENTER();
12004         MMPLAYER_RETURN_IF_FAIL(player);
12005
12006         if (player->factories) {
12007                 gst_plugin_feature_list_free(player->factories);
12008                 player->factories = NULL;
12009         }
12010
12011         MMPLAYER_FLEAVE();
12012 }
12013
12014 static void
12015 __mmplayer_release_misc(mm_player_t* player)
12016 {
12017         int i;
12018         gboolean cur_mode = player->set_mode.rich_audio;
12019         MMPLAYER_FENTER();
12020
12021         MMPLAYER_RETURN_IF_FAIL(player);
12022
12023         player->video_stream_cb = NULL;
12024         player->video_stream_cb_user_param = NULL;
12025         player->video_stream_prerolled = FALSE;
12026
12027         player->audio_stream_cb = NULL;
12028         player->audio_stream_render_cb_ex = NULL;
12029         player->audio_stream_cb_user_param = NULL;
12030         player->audio_stream_sink_sync = false;
12031
12032         player->video_stream_changed_cb = NULL;
12033         player->video_stream_changed_cb_user_param = NULL;
12034
12035         player->audio_stream_changed_cb = NULL;
12036         player->audio_stream_changed_cb_user_param = NULL;
12037
12038         player->sent_bos = FALSE;
12039         player->playback_rate = DEFAULT_PLAYBACK_RATE;
12040
12041         player->doing_seek = FALSE;
12042
12043         player->updated_bitrate_count = 0;
12044         player->total_bitrate = 0;
12045         player->updated_maximum_bitrate_count = 0;
12046         player->total_maximum_bitrate = 0;
12047
12048         player->not_found_demuxer = 0;
12049
12050         player->last_position = 0;
12051         player->duration = 0;
12052         player->http_content_size = 0;
12053         player->not_supported_codec = MISSING_PLUGIN_NONE;
12054         player->can_support_codec = FOUND_PLUGIN_NONE;
12055         player->pending_seek.is_pending = FALSE;
12056         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12057         player->pending_seek.pos = 0;
12058         player->msg_posted = FALSE;
12059         player->has_many_types = FALSE;
12060         player->max_audio_channels = 0;
12061         player->video_share_api_delta = 0;
12062         player->video_share_clock_delta = 0;
12063         player->sound_focus.keep_last_pos = FALSE;
12064         player->sound_focus.acquired = FALSE;
12065         player->is_subtitle_force_drop = FALSE;
12066         player->play_subtitle = FALSE;
12067         player->use_textoverlay = FALSE;
12068         player->adjust_subtitle_pos = 0;
12069         player->last_multiwin_status = FALSE;
12070         player->has_closed_caption = FALSE;
12071         player->set_mode.media_packet_video_stream = FALSE;
12072         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12073         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12074         /* recover mode */
12075         player->set_mode.rich_audio = cur_mode;
12076
12077         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12078                 player->bitrate[i] = 0;
12079                 player->maximum_bitrate[i] = 0;
12080         }
12081
12082         /* remove media stream cb(appsrc cb) */
12083         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12084                 player->media_stream_buffer_status_cb[i] = NULL;
12085                 player->media_stream_seek_data_cb[i] = NULL;
12086         }
12087
12088         /* free memory related to audio effect */
12089         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12090
12091         if (player->state_tune_caps) {
12092                 gst_caps_unref(player->state_tune_caps);
12093                 player->state_tune_caps = NULL;
12094         }
12095
12096         MMPLAYER_FLEAVE();
12097 }
12098
12099 static void
12100 __mmplayer_release_misc_post(mm_player_t* player)
12101 {
12102         char *original_uri = NULL;
12103         MMPLAYER_FENTER();
12104
12105         /* player->pipeline is already released before. */
12106
12107         MMPLAYER_RETURN_IF_FAIL(player);
12108
12109         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12110         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12111
12112         /* clean found parsers */
12113         if (player->parsers) {
12114                 GList *parsers = player->parsers;
12115                 for (; parsers; parsers = g_list_next(parsers)) {
12116                         gchar *name = parsers->data;
12117                         MMPLAYER_FREEIF(name);
12118                 }
12119                 g_list_free(player->parsers);
12120                 player->parsers = NULL;
12121         }
12122
12123         /* clean found audio decoders */
12124         if (player->audio_decoders) {
12125                 GList *a_dec = player->audio_decoders;
12126                 for (; a_dec; a_dec = g_list_next(a_dec)) {
12127                         gchar *name = a_dec->data;
12128                         MMPLAYER_FREEIF(name);
12129                 }
12130                 g_list_free(player->audio_decoders);
12131                 player->audio_decoders = NULL;
12132         }
12133
12134         /* clean the uri list except original uri */
12135         if (player->uri_info.uri_list) {
12136                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12137
12138                 if (player->attrs) {
12139                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12140                         LOGD("restore original uri = %s\n", original_uri);
12141
12142                         if (mmf_attrs_commit(player->attrs))
12143                                 LOGE("failed to commit the original uri.\n");
12144                 }
12145
12146                 GList *uri_list = player->uri_info.uri_list;
12147                 for (; uri_list; uri_list = g_list_next(uri_list)) {
12148                         gchar *uri = uri_list->data;
12149                         MMPLAYER_FREEIF(uri);
12150                 }
12151                 g_list_free(player->uri_info.uri_list);
12152                 player->uri_info.uri_list = NULL;
12153         }
12154
12155         /* clear the audio stream buffer list */
12156         __mmplayer_audio_stream_clear_buffer(player, FALSE);
12157
12158         /* clear the video stream bo list */
12159         __mmplayer_video_stream_destroy_bo_list(player);
12160
12161         player->uri_info.uri_idx = 0;
12162         MMPLAYER_FLEAVE();
12163 }
12164
12165 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12166 {
12167         GstElement *element = NULL;
12168         GstPad *sinkpad;
12169
12170         LOGD("creating %s to plug\n", name);
12171
12172         element = gst_element_factory_make(name, NULL);
12173         if (!element) {
12174                 LOGE("failed to create queue\n");
12175                 return NULL;
12176         }
12177
12178         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12179                 LOGE("failed to set state READY to %s\n", name);
12180                 gst_object_unref(element);
12181                 return NULL;
12182         }
12183
12184         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12185                 LOGE("failed to add %s\n", name);
12186                 gst_object_unref(element);
12187                 return NULL;
12188         }
12189
12190         sinkpad = gst_element_get_static_pad(element, "sink");
12191
12192         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12193                 LOGE("failed to link %s\n", name);
12194                 gst_object_unref(sinkpad);
12195                 gst_object_unref(element);
12196                 return NULL;
12197         }
12198
12199         LOGD("linked %s to pipeline successfully\n", name);
12200
12201         gst_object_unref(sinkpad);
12202
12203         return element;
12204 }
12205
12206 static gboolean
12207 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12208 const char *padname, const GList *templlist)
12209 {
12210         GstPad *pad = NULL;
12211         gboolean has_dynamic_pads = FALSE;
12212         gboolean has_many_types = FALSE;
12213         const char *klass = NULL;
12214         GstStaticPadTemplate *padtemplate = NULL;
12215         GstElementFactory *factory = NULL;
12216         GstElement* queue = NULL;
12217         GstElement* parser = NULL;
12218         GstPad *pssrcpad = NULL;
12219         GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12220         MMPlayerGstElement *mainbin = NULL;
12221         GstStructure* str = NULL;
12222         GstCaps* srccaps = NULL;
12223         GstState target_state = GST_STATE_READY;
12224         gboolean isvideo_decoder = FALSE;
12225         guint q_max_size_time = 0;
12226
12227         MMPLAYER_FENTER();
12228
12229         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12230                 player->pipeline &&
12231                 player->pipeline->mainbin,
12232                 FALSE);
12233
12234         mainbin = player->pipeline->mainbin;
12235
12236         LOGD("plugging pad %s:%s to newly create %s:%s\n",
12237                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12238                         GST_PAD_NAME(srcpad),
12239                         GST_ELEMENT_NAME(sinkelement),
12240                         padname);
12241
12242         factory = gst_element_get_factory(sinkelement);
12243         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12244
12245         /* check if player can do start continually */
12246         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12247
12248         /* need it to warm up omx before linking to pipeline */
12249         if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12250                 LOGD("get demux caps.\n");
12251                 if (player->state_tune_caps) {
12252                         gst_caps_unref(player->state_tune_caps);
12253                         player->state_tune_caps = NULL;
12254                 }
12255                 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12256         }
12257
12258         /* NOTE : OMX Codec can check if resource is available or not at this state. */
12259         if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12260                 if (player->state_tune_caps != NULL) {
12261                         LOGD("set demux's caps to omx codec if resource is available");
12262                         if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12263                                 target_state = GST_STATE_PAUSED;
12264                                 isvideo_decoder = TRUE;
12265                                 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12266                         } else
12267                                 LOGW("failed to set caps for state tuning");
12268                 }
12269                 gst_caps_unref(player->state_tune_caps);
12270                 player->state_tune_caps = NULL;
12271         }
12272
12273         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12274                 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12275                 if (isvideo_decoder) {
12276                         gst_element_set_state(sinkelement, GST_STATE_NULL);
12277                         gst_object_unref(G_OBJECT(sinkelement));
12278                         player->keep_detecting_vcodec = TRUE;
12279                 }
12280                 goto ERROR;
12281         }
12282
12283         /* add to pipeline */
12284         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12285                 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12286                 goto ERROR;
12287         }
12288
12289         LOGD("element klass : %s\n", klass);
12290
12291         /* added to support multi track files */
12292         /* only decoder case and any of the video/audio still need to link*/
12293         if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12294                 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12295
12296                 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12297                         gchar *src_demux_caps_str = NULL;
12298                         gchar *needed_parser = NULL;
12299                         GstCaps *src_demux_caps = NULL;
12300                         gboolean smooth_streaming = FALSE;
12301
12302                         src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12303                         src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12304
12305                         gst_caps_unref(src_demux_caps);
12306
12307                         if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12308                                 if (g_strrstr(name, "mssdemux")) {
12309                                         needed_parser = g_strdup("legacyh264parse");
12310                                         smooth_streaming = TRUE;
12311                                 } else
12312                                         needed_parser = g_strdup("h264parse");
12313                         } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12314                                 needed_parser = g_strdup("mpeg4videoparse");
12315
12316                         MMPLAYER_FREEIF(src_demux_caps_str);
12317
12318                         if (needed_parser) {
12319                                 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12320                                 MMPLAYER_FREEIF(needed_parser);
12321
12322                                 if (!parser) {
12323                                         LOGE("failed to create parser\n");
12324                                 } else {
12325                                         if (smooth_streaming)
12326                                                 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12327
12328                                         /* update srcpad if parser is created */
12329                                         pssrcpad = gst_element_get_static_pad(parser, "src");
12330                                         srcpad = pssrcpad;
12331                                 }
12332                         }
12333                 }
12334                 MMPLAYER_FREEIF(name);
12335
12336                 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12337                 if (!queue) {
12338                         LOGE("failed to create queue\n");
12339                         goto ERROR;
12340                 }
12341
12342                 /* update srcpad to link with decoder */
12343                 qsrcpad = gst_element_get_static_pad(queue, "src");
12344                 srcpad = qsrcpad;
12345
12346                 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12347
12348                 /* assigning queue handle for futher manipulation purpose */
12349                 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12350                 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12351                         mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12352                         mainbin[MMPLAYER_M_Q1].gst = queue;
12353
12354                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12355                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12356                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12357                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12358                         } else {
12359                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12360                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12361                         }
12362                 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12363                         mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12364                         mainbin[MMPLAYER_M_Q2].gst = queue;
12365
12366                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12367                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12368                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12369                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12370                         } else {
12371                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12372                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12373                         }
12374                 } else {
12375                         LOGE("Not supporting more then two elementary stream\n");
12376                         g_assert(1);
12377                 }
12378
12379                 pad = gst_element_get_static_pad(sinkelement, padname);
12380
12381                 if (!pad) {
12382                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12383                                 padname, GST_ELEMENT_NAME(sinkelement));
12384
12385                         pad = gst_element_get_static_pad(sinkelement, "sink");
12386                         if (!pad) {
12387                                 LOGE("failed to get pad(sink) from %s. \n",
12388                                 GST_ELEMENT_NAME(sinkelement));
12389                                 goto ERROR;
12390                         }
12391                 }
12392
12393                 /* to check the video/audio type set the proper flag*/
12394                 const gchar *mime_type = NULL;
12395                 srccaps = gst_pad_query_caps(srcpad, NULL);
12396                 if (!srccaps)
12397                         goto ERROR;
12398                 str = gst_caps_get_structure(srccaps, 0);
12399                 if (!str)
12400                         goto ERROR;
12401                 mime_type = gst_structure_get_name(str);
12402                 if (!mime_type)
12403                         goto ERROR;
12404
12405                 /* link queue and decoder. so, it will be queue - decoder. */
12406                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12407                         gst_object_unref(GST_OBJECT(pad));
12408                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12409
12410                         /* reconstitute supportable codec */
12411                         if (strstr(mime_type, "video"))
12412                                 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12413                         else if (strstr(mime_type, "audio"))
12414                                 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12415                         goto ERROR;
12416                 }
12417
12418                 if (strstr(mime_type, "video")) {
12419                         player->videodec_linked = 1;
12420                         LOGI("player->videodec_linked set to 1\n");
12421
12422                 } else if (strstr(mime_type, "audio")) {
12423                         player->audiodec_linked = 1;
12424                         LOGI("player->auddiodec_linked set to 1\n");
12425                 }
12426
12427                 gst_object_unref(GST_OBJECT(pad));
12428                 gst_caps_unref(GST_CAPS(srccaps));
12429                 srccaps = NULL;
12430         }
12431
12432         if (!MMPLAYER_IS_HTTP_PD(player)) {
12433                 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12434                         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12435                                 gint64 dur_bytes = 0L;
12436                                 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12437
12438                                 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12439                                         LOGD("creating http streaming buffering queue\n");
12440
12441                                         queue = gst_element_factory_make("queue2", "queue2");
12442                                         if (!queue) {
12443                                                 LOGE("failed to create buffering queue element\n");
12444                                                 goto ERROR;
12445                                         }
12446
12447                                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12448                                                 LOGE("failed to set state READY to buffering queue\n");
12449                                                 goto ERROR;
12450                                         }
12451
12452                                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12453                                                 LOGE("failed to add buffering queue\n");
12454                                                 goto ERROR;
12455                                         }
12456
12457                                         qsinkpad = gst_element_get_static_pad(queue, "sink");
12458                                         qsrcpad = gst_element_get_static_pad(queue, "src");
12459
12460                                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12461                                                 LOGE("failed to link buffering queue\n");
12462                                                 goto ERROR;
12463                                         }
12464                                         srcpad = qsrcpad;
12465
12466
12467                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12468                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12469
12470                                         if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12471                                                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12472                                                         LOGE("fail to get duration.\n");
12473
12474                                                 if (dur_bytes > 0) {
12475                                                         if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12476                                                                 type = MUXED_BUFFER_TYPE_FILE;
12477                                                         } else {
12478                                                                 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12479                                                                 if (player->streamer)
12480                                                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12481                                                         }
12482                                                 } else {
12483                                                         dur_bytes = 0;
12484                                                 }
12485                                         }
12486
12487                                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
12488                                         if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12489                                                 __mm_player_streaming_set_queue2(player->streamer,
12490                                                         queue,
12491                                                         TRUE,
12492                                                         player->ini.http_max_size_bytes,
12493                                                         player->ini.http_buffering_time,
12494                                                         1.0,
12495                                                         player->ini.http_buffering_limit,
12496                                                         type,
12497                                                         player->http_file_buffering_path,
12498                                                         (guint64)dur_bytes);
12499                                         }
12500                                 }
12501                         }
12502                 }
12503         }
12504         /* if it is not decoder or */
12505         /* in decoder case any of the video/audio still need to link*/
12506         if (!g_strrstr(klass, "Decoder")) {
12507                 pad = gst_element_get_static_pad(sinkelement, padname);
12508                 if (!pad) {
12509                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12510                                         padname, GST_ELEMENT_NAME(sinkelement));
12511
12512                         pad = gst_element_get_static_pad(sinkelement, "sink");
12513
12514                         if (!pad) {
12515                                 LOGE("failed to get pad(sink) from %s. \n",
12516                                         GST_ELEMENT_NAME(sinkelement));
12517                                 goto ERROR;
12518                         }
12519                 }
12520
12521                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12522                         gst_object_unref(GST_OBJECT(pad));
12523                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12524                         goto ERROR;
12525                 }
12526
12527                 gst_object_unref(GST_OBJECT(pad));
12528         }
12529
12530         for (; templlist != NULL; templlist = templlist->next) {
12531                 padtemplate = templlist->data;
12532
12533                 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12534
12535                 if (padtemplate->direction != GST_PAD_SRC ||
12536                         padtemplate->presence == GST_PAD_REQUEST)
12537                         continue;
12538
12539                 switch (padtemplate->presence) {
12540                 case GST_PAD_ALWAYS:
12541                         {
12542                                 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12543                                 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12544
12545                                 /* Check whether caps has many types */
12546                                 if (!gst_caps_is_fixed(caps)) {
12547                                         LOGD("always pad but, caps has many types");
12548                                         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12549                                         has_many_types = TRUE;
12550                                         break;
12551                                 }
12552
12553                                 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12554                                         gst_object_unref(GST_OBJECT(srcpad));
12555                                         gst_caps_unref(GST_CAPS(caps));
12556
12557                                         LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12558                                         goto ERROR;
12559                                 }
12560
12561                                 gst_caps_unref(GST_CAPS(caps));
12562                                 gst_object_unref(GST_OBJECT(srcpad));
12563
12564                         }
12565                         break;
12566
12567
12568                 case GST_PAD_SOMETIMES:
12569                         has_dynamic_pads = TRUE;
12570                         break;
12571
12572                 default:
12573                         break;
12574                 }
12575         }
12576
12577         /* check if player can do start continually */
12578         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12579
12580         if (has_dynamic_pads) {
12581                 player->have_dynamic_pad = TRUE;
12582                 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12583                         G_CALLBACK(__mmplayer_add_new_pad), player);
12584
12585                 /* for streaming, more then one typefind will used for each elementary stream
12586                  * so this doesn't mean the whole pipeline completion
12587                  */
12588                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12589                         MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12590                                 G_CALLBACK(__mmplayer_pipeline_complete), player);
12591                 }
12592         }
12593
12594         if (has_many_types) {
12595                 GstPad *pad = NULL;
12596
12597                 player->has_many_types = has_many_types;
12598
12599                 pad = gst_element_get_static_pad(sinkelement, "src");
12600                 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12601                 gst_object_unref(GST_OBJECT(pad));
12602         }
12603
12604
12605         /* check if player can do start continually */
12606         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12607
12608         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12609                 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12610                 goto ERROR;
12611         }
12612
12613         if (queue) {
12614                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12615                         LOGE("failed to set state PAUSED to queue\n");
12616                         goto ERROR;
12617                 }
12618
12619                 queue = NULL;
12620
12621                 gst_object_unref(GST_OBJECT(qsrcpad));
12622                 qsrcpad = NULL;
12623         }
12624
12625         if (parser) {
12626                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12627                         LOGE("failed to set state PAUSED to queue\n");
12628                         goto ERROR;
12629                 }
12630
12631                 parser = NULL;
12632
12633                 gst_object_unref(GST_OBJECT(pssrcpad));
12634                 pssrcpad = NULL;
12635         }
12636
12637         MMPLAYER_FLEAVE();
12638
12639         return TRUE;
12640
12641 ERROR:
12642
12643         if (queue) {
12644                 gst_object_unref(GST_OBJECT(qsrcpad));
12645
12646                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12647                  * You need to explicitly set elements to the NULL state before
12648                  * dropping the final reference, to allow them to clean up.
12649                  */
12650                 gst_element_set_state(queue, GST_STATE_NULL);
12651                 /* And, it still has a parent "player".
12652                  * You need to let the parent manage the object instead of unreffing the object directly.
12653                  */
12654
12655                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12656                 //gst_object_unref(queue);
12657         }
12658
12659         if (srccaps)
12660                 gst_caps_unref(GST_CAPS(srccaps));
12661
12662         return FALSE;
12663 }
12664
12665 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12666 {
12667         const gchar *klass;
12668
12669         /* we only care about element factories */
12670         if (!GST_IS_ELEMENT_FACTORY(feature))
12671                 return FALSE;
12672
12673         /* only parsers, demuxers and decoders */
12674                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12675
12676         if (g_strrstr(klass, "Demux") == NULL &&
12677                         g_strrstr(klass, "Codec/Decoder") == NULL &&
12678                         g_strrstr(klass, "Depayloader") == NULL &&
12679                         g_strrstr(klass, "Parse") == NULL)
12680                 return FALSE;
12681         return TRUE;
12682 }
12683
12684
12685 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12686 {
12687         mm_player_t* player = (mm_player_t*) data;
12688         GstCaps *caps = NULL;
12689         GstStructure *str = NULL;
12690         const char *name;
12691
12692         MMPLAYER_FENTER();
12693
12694         MMPLAYER_RETURN_IF_FAIL(pad)
12695         MMPLAYER_RETURN_IF_FAIL(unused)
12696         MMPLAYER_RETURN_IF_FAIL(data)
12697
12698         caps = gst_pad_query_caps(pad, NULL);
12699         if (!caps)
12700                 return;
12701
12702         str = gst_caps_get_structure(caps, 0);
12703         if (!str)
12704                 return;
12705
12706         name = gst_structure_get_name(str);
12707         if (!name)
12708                 return;
12709         LOGD("name=%s\n", name);
12710
12711         if (!__mmplayer_try_to_plug(player, pad, caps)) {
12712                 LOGE("failed to autoplug for type(%s)\n", name);
12713                 gst_caps_unref(caps);
12714                 return;
12715         }
12716
12717         gst_caps_unref(caps);
12718
12719         __mmplayer_pipeline_complete(NULL, (gpointer)player);
12720
12721         MMPLAYER_FLEAVE();
12722
12723         return;
12724 }
12725
12726 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12727 {
12728         GstStructure *str;
12729         gint version = 0;
12730         const char *stream_type;
12731         gchar *version_field = NULL;
12732
12733         MMPLAYER_FENTER();
12734
12735         MMPLAYER_RETURN_IF_FAIL(player);
12736         MMPLAYER_RETURN_IF_FAIL(caps);
12737
12738         str = gst_caps_get_structure(caps, 0);
12739         if (!str)
12740                 return;
12741
12742         stream_type = gst_structure_get_name(str);
12743         if (!stream_type)
12744                 return;
12745
12746
12747         /* set unlinked mime type for downloadable codec */
12748         if (g_str_has_prefix(stream_type, "video/")) {
12749                 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12750                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12751                         version_field = MM_PLAYER_MPEG_VNAME;
12752                 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12753                         gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12754                         version_field = MM_PLAYER_WMV_VNAME;
12755
12756                 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12757                         gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12758                         version_field = MM_PLAYER_DIVX_VNAME;
12759                 }
12760
12761                 if (version)
12762                         player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12763                 else
12764                         player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12765         } else if (g_str_has_prefix(stream_type, "audio/")) {
12766                 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12767                         // mp3 or aac
12768                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12769                         version_field = MM_PLAYER_MPEG_VNAME;
12770                 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12771                         gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12772                         version_field = MM_PLAYER_WMA_VNAME;
12773                 }
12774
12775                 if (version)
12776                         player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12777                 else
12778                         player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12779         }
12780
12781         MMPLAYER_FLEAVE();
12782 }
12783
12784 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12785 {
12786         mm_player_t* player = (mm_player_t*) data;
12787         GstCaps *caps = NULL;
12788         GstStructure *str = NULL;
12789         const char *name;
12790
12791         MMPLAYER_FENTER();
12792         MMPLAYER_RETURN_IF_FAIL(player);
12793         MMPLAYER_RETURN_IF_FAIL(pad);
12794
12795         GST_OBJECT_LOCK(pad);
12796         if ((caps = gst_pad_get_current_caps(pad)))
12797                 gst_caps_ref(caps);
12798         GST_OBJECT_UNLOCK(pad);
12799
12800         if (NULL == caps) {
12801                 caps = gst_pad_query_caps(pad, NULL);
12802                 if (!caps) return;
12803         }
12804
12805         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12806
12807         str = gst_caps_get_structure(caps, 0);
12808         if (!str)
12809                 return;
12810
12811         name = gst_structure_get_name(str);
12812         if (!name)
12813                 return;
12814
12815         player->num_dynamic_pad++;
12816         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12817
12818         /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12819           *     If want to play it, remove this code.
12820           */
12821         if (g_strrstr(name, "application")) {
12822                 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12823                         /* If id3/ape tag comes, keep going */
12824                         LOGD("application mime exception : id3/ape tag");
12825                 } else {
12826                         /* Otherwise, we assume that this stream is subtile. */
12827                         LOGD(" application mime type pad is closed.");
12828                         return;
12829                 }
12830         } else if (g_strrstr(name, "audio")) {
12831                 gint samplerate = 0, channels = 0;
12832
12833                 if (player->audiodec_linked) {
12834                         gst_caps_unref(caps);
12835                         LOGD("multi tracks. skip to plug");
12836                         return;
12837                 }
12838
12839                 /* set stream information */
12840                 /* if possible, set it here because the caps is not distrubed by resampler. */
12841                 gst_structure_get_int(str, "rate", &samplerate);
12842                 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12843
12844                 gst_structure_get_int(str, "channels", &channels);
12845                 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12846
12847                 LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
12848         } else if (g_strrstr(name, "video")) {
12849                 gint stype;
12850                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12851
12852                 /* don't make video because of not required */
12853                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
12854                         LOGD("no video because it's not required");
12855                         return;
12856                 }
12857
12858                 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
12859         }
12860
12861         if (!__mmplayer_try_to_plug(player, pad, caps)) {
12862                 LOGE("failed to autoplug for type(%s)", name);
12863
12864                 __mmplayer_set_unlinked_mime_type(player, caps);
12865         }
12866
12867         gst_caps_unref(caps);
12868
12869         MMPLAYER_FLEAVE();
12870         return;
12871 }
12872
12873 gboolean
12874 __mmplayer_check_subtitle(mm_player_t* player)
12875 {
12876         MMHandleType attrs = 0;
12877         char *subtitle_uri = NULL;
12878
12879         MMPLAYER_FENTER();
12880
12881         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12882
12883         /* get subtitle attribute */
12884         attrs = MMPLAYER_GET_ATTRS(player);
12885         if (!attrs)
12886                 return FALSE;
12887
12888         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12889         if (!subtitle_uri || !strlen(subtitle_uri))
12890                 return FALSE;
12891
12892         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
12893         player->is_external_subtitle_present = TRUE;
12894
12895         MMPLAYER_FLEAVE();
12896
12897         return TRUE;
12898 }
12899
12900 static gboolean
12901 __mmplayer_can_extract_pcm(mm_player_t* player)
12902 {
12903         MMHandleType attrs = 0;
12904         gboolean sound_extraction = FALSE;
12905
12906         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12907
12908         attrs = MMPLAYER_GET_ATTRS(player);
12909         if (!attrs) {
12910                 LOGE("fail to get attributes.");
12911                 return FALSE;
12912         }
12913
12914         /* get sound_extraction property */
12915         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
12916
12917         if (!sound_extraction) {
12918                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
12919                 return FALSE;
12920         }
12921
12922         return TRUE;
12923 }
12924
12925 static gboolean
12926 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
12927 {
12928         LOGD("\n");
12929         MMMessageParamType msg_param;
12930         gchar *msg_src_element = NULL;
12931         GstStructure *s = NULL;
12932         guint error_id = 0;
12933         gchar *error_string = NULL;
12934
12935         MMPLAYER_FENTER();
12936
12937         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12938         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
12939
12940         s = malloc(sizeof(GstStructure));
12941         memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
12942
12943         if (!gst_structure_get_uint(s, "error_id", &error_id))
12944                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
12945
12946         switch (error_id) {
12947         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
12948                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
12949                 break;
12950         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
12951                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
12952                 break;
12953         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
12954                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
12955                 break;
12956         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
12957                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
12958                 break;
12959         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
12960                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
12961                 break;
12962         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
12963                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
12964                 break;
12965         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
12966                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
12967                 break;
12968         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
12969                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
12970                 break;
12971         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
12972                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
12973                 break;
12974         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
12975                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
12976                 break;
12977         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
12978                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
12979                 break;
12980         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
12981                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
12982                 break;
12983         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
12984                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
12985                 break;
12986         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
12987                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
12988                 break;
12989         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
12990                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
12991                 break;
12992         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
12993                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
12994                 break;
12995         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
12996                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
12997                 break;
12998         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
12999                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13000                 break;
13001         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13002                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13003                 break;
13004         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13005                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13006                 break;
13007         case MMPLAYER_STREAMING_ERROR_GONE:
13008                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13009                 break;
13010         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13011                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13012                 break;
13013         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13014                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13015                 break;
13016         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13017                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13018                 break;
13019         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13020                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13021                 break;
13022         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13023                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13024                 break;
13025         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13026                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13027                 break;
13028         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13029                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13030                 break;
13031         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13032                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13033                 break;
13034         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13035                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13036                 break;
13037         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13038                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13039                 break;
13040         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13041                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13042                 break;
13043         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13044                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13045                 break;
13046         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13047                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13048                 break;
13049         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13050                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13051                 break;
13052         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13053                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13054                 break;
13055         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13056                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13057                 break;
13058         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13059                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13060                 break;
13061         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13062                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13063                 break;
13064         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13065                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13066                 break;
13067         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13068                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13069                 break;
13070         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13071                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13072                 break;
13073         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13074                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13075                 break;
13076         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13077                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13078                 break;
13079         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13080                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13081                 break;
13082         default:
13083                 {
13084                         MMPLAYER_FREEIF(s);
13085                         return MM_ERROR_PLAYER_STREAMING_FAIL;
13086                 }
13087         }
13088
13089         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13090         if (error_string)
13091                 msg_param.data = (void *) error_string;
13092
13093         if (message->src) {
13094                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13095
13096                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
13097                         msg_src_element, msg_param.code, (char*)msg_param.data);
13098         }
13099
13100         /* post error to application */
13101         if (!player->msg_posted) {
13102                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13103
13104                 /* don't post more if one was sent already */
13105                 player->msg_posted = TRUE;
13106         } else
13107                 LOGD("skip error post because it's sent already.\n");
13108
13109         MMPLAYER_FREEIF(s);
13110         MMPLAYER_FLEAVE();
13111         g_free(error_string);
13112
13113         return TRUE;
13114
13115 }
13116
13117 static void
13118 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13119 {
13120         MMPLAYER_RETURN_IF_FAIL(player);
13121
13122
13123         /* post now if delay is zero */
13124         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13125                 LOGD("eos delay is zero. posting EOS now\n");
13126                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13127
13128                 if (player->set_mode.pcm_extraction)
13129                         __mmplayer_cancel_eos_timer(player);
13130
13131                 return;
13132         }
13133
13134         /* cancel if existing */
13135         __mmplayer_cancel_eos_timer(player);
13136
13137         /* init new timeout */
13138         /* NOTE : consider give high priority to this timer */
13139         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13140
13141         player->eos_timer = g_timeout_add(delay_in_ms,
13142                 __mmplayer_eos_timer_cb, player);
13143
13144         player->context.global_default = g_main_context_default();
13145         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13146
13147         /* check timer is valid. if not, send EOS now */
13148         if (player->eos_timer == 0) {
13149                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13150                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13151         }
13152 }
13153
13154 static void
13155 __mmplayer_cancel_eos_timer(mm_player_t* player)
13156 {
13157         MMPLAYER_RETURN_IF_FAIL(player);
13158
13159         if (player->eos_timer) {
13160                 LOGD("cancel eos timer");
13161                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13162                 player->eos_timer = 0;
13163         }
13164
13165         return;
13166 }
13167
13168 static gboolean
13169 __mmplayer_eos_timer_cb(gpointer u_data)
13170 {
13171         mm_player_t* player = NULL;
13172         player = (mm_player_t*) u_data;
13173
13174         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13175
13176         if (player->play_count > 1) {
13177                 gint ret_value = 0;
13178                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13179                 if (ret_value == MM_ERROR_NONE) {
13180                         MMHandleType attrs = 0;
13181                         attrs = MMPLAYER_GET_ATTRS(player);
13182
13183                         /* we successeded to rewind. update play count and then wait for next EOS */
13184                         player->play_count--;
13185
13186                         mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13187                         mmf_attrs_commit(attrs);
13188                 } else
13189                         LOGE("seeking to 0 failed in repeat play");
13190         } else
13191                 /* posting eos */
13192                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13193
13194         /* we are returning FALSE as we need only one posting */
13195         return FALSE;
13196 }
13197
13198 static gboolean
13199 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13200 {
13201         const gchar* name = NULL;
13202         GstStructure* str = NULL;
13203         GstCaps* srccaps = NULL;
13204
13205         MMPLAYER_FENTER();
13206
13207         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13208         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13209
13210         /* to check any of the decoder(video/audio) need to be linked  to parser*/
13211         srccaps = gst_pad_query_caps(srcpad, NULL);
13212         if (!srccaps)
13213                 goto ERROR;
13214
13215         str = gst_caps_get_structure(srccaps, 0);
13216         if (!str)
13217                 goto ERROR;
13218
13219         name = gst_structure_get_name(str);
13220         if (!name)
13221                 goto ERROR;
13222
13223         if (strstr(name, "video")) {
13224                 if (player->videodec_linked) {
13225                     LOGI("Video decoder already linked\n");
13226                         return FALSE;
13227                 }
13228         }
13229         if (strstr(name, "audio")) {
13230                 if (player->audiodec_linked) {
13231                     LOGI("Audio decoder already linked\n");
13232                         return FALSE;
13233                 }
13234         }
13235
13236         gst_caps_unref(srccaps);
13237
13238         MMPLAYER_FLEAVE();
13239
13240         return TRUE;
13241
13242 ERROR:
13243         if (srccaps)
13244                 gst_caps_unref(srccaps);
13245
13246         return FALSE;
13247 }
13248
13249 static gboolean
13250 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13251 {
13252         const gchar* name = NULL;
13253         GstStructure* str = NULL;
13254         GstCaps* srccaps = NULL;
13255
13256         MMPLAYER_FENTER();
13257
13258         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13259         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13260
13261         /* to check any of the decoder(video/audio) need to be linked   to parser*/
13262         srccaps = gst_pad_query_caps(srcpad, NULL);
13263         if (!srccaps)
13264                 goto ERROR;
13265
13266         str = gst_caps_get_structure(srccaps, 0);
13267         if (!str)
13268                 goto ERROR;
13269
13270         name = gst_structure_get_name(str);
13271         if (!name)
13272                 goto ERROR;
13273
13274         if (strstr(name, "video")) {
13275                 if (player->videosink_linked) {
13276                         LOGI("Video Sink already linked\n");
13277                         return FALSE;
13278                 }
13279         }
13280         if (strstr(name, "audio")) {
13281                 if (player->audiosink_linked) {
13282                         LOGI("Audio Sink already linked\n");
13283                         return FALSE;
13284                 }
13285         }
13286         if (strstr(name, "text")) {
13287                 if (player->textsink_linked) {
13288                         LOGI("Text Sink already linked\n");
13289                         return FALSE;
13290                 }
13291         }
13292
13293         gst_caps_unref(srccaps);
13294
13295         MMPLAYER_FLEAVE();
13296
13297         //return (!player->videosink_linked || !player->audiosink_linked);
13298         return TRUE;
13299
13300 ERROR:
13301         if (srccaps)
13302                 gst_caps_unref(srccaps);
13303
13304         return FALSE;
13305 }
13306
13307
13308 /* sending event to one of sinkelements */
13309 static gboolean
13310 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13311 {
13312         GstEvent * event2 = NULL;
13313         GList *sinks = NULL;
13314         gboolean res = FALSE;
13315         MMPLAYER_FENTER();
13316
13317         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13318         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13319
13320         if (player->play_subtitle && !player->use_textoverlay)
13321                 event2 = gst_event_copy((const GstEvent *)event);
13322
13323         sinks = player->sink_elements;
13324         while (sinks) {
13325                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13326
13327                 if (GST_IS_ELEMENT(sink)) {
13328                         /* keep ref to the event */
13329                         gst_event_ref(event);
13330
13331                         if ((res = gst_element_send_event(sink, event))) {
13332                                 LOGD("sending event[%s] to sink element [%s] success!\n",
13333                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13334
13335                                 /* rtsp case, asyn_done is not called after seek during pause state */
13336                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13337                                         if (strstr(GST_EVENT_TYPE_NAME(event), "seek")) {
13338                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13339                                                         LOGD("RTSP seek completed, after pause state..\n");
13340                                                         player->doing_seek = FALSE;
13341                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13342                                                 }
13343
13344                                         }
13345                                 }
13346
13347                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13348                                         sinks = g_list_next(sinks);
13349                                         continue;
13350                                 } else
13351                                         break;
13352                         }
13353
13354                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13355                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13356                 }
13357
13358                 sinks = g_list_next(sinks);
13359         }
13360
13361 #if 0
13362         if (internal_sub)
13363           request pad name = sink0;
13364         else
13365           request pad name = sink1; // external
13366 #endif
13367
13368         /* Note : Textbin is not linked to the video or audio bin.
13369          * It needs to send the event to the text sink seperatelly.
13370          */
13371          if (player->play_subtitle && !player->use_textoverlay) {
13372                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13373
13374                 if (GST_IS_ELEMENT(text_sink)) {
13375                         /* keep ref to the event */
13376                         gst_event_ref(event2);
13377
13378                         if ((res = gst_element_send_event(text_sink, event2)))
13379                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13380                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13381                         else
13382                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13383                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13384
13385                         gst_event_unref(event2);
13386                 }
13387          }
13388
13389         gst_event_unref(event);
13390
13391         MMPLAYER_FLEAVE();
13392
13393         return res;
13394 }
13395
13396 static void
13397 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13398 {
13399         MMPLAYER_FENTER();
13400
13401         MMPLAYER_RETURN_IF_FAIL(player);
13402         MMPLAYER_RETURN_IF_FAIL(sink);
13403
13404         player->sink_elements =
13405                 g_list_append(player->sink_elements, sink);
13406
13407         MMPLAYER_FLEAVE();
13408 }
13409
13410 static void
13411 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13412 {
13413         MMPLAYER_FENTER();
13414
13415         MMPLAYER_RETURN_IF_FAIL(player);
13416         MMPLAYER_RETURN_IF_FAIL(sink);
13417
13418         player->sink_elements =
13419                         g_list_remove(player->sink_elements, sink);
13420
13421         MMPLAYER_FLEAVE();
13422 }
13423
13424 static gboolean
13425 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13426                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13427                         gint64 cur, GstSeekType stop_type, gint64 stop)
13428 {
13429         GstEvent* event = NULL;
13430         gboolean result = FALSE;
13431
13432         MMPLAYER_FENTER();
13433
13434         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13435
13436         if (player->pipeline && player->pipeline->textbin)
13437                 __mmplayer_drop_subtitle(player, FALSE);
13438
13439         event = gst_event_new_seek(rate, format, flags, cur_type,
13440                 cur, stop_type, stop);
13441
13442         result = __gst_send_event_to_sink(player, event);
13443
13444         MMPLAYER_FLEAVE();
13445
13446         return result;
13447 }
13448
13449 /* NOTE : be careful with calling this api. please refer to below glib comment
13450  * glib comment : Note that there is a bug in GObject that makes this function much
13451  * less useful than it might seem otherwise. Once gobject is disposed, the callback
13452  * will no longer be called, but, the signal handler is not currently disconnected.
13453  * If the instance is itself being freed at the same time than this doesn't matter,
13454  * since the signal will automatically be removed, but if instance persists,
13455  * then the signal handler will leak. You should not remove the signal yourself
13456  * because in a future versions of GObject, the handler will automatically be
13457  * disconnected.
13458  *
13459  * It's possible to work around this problem in a way that will continue to work
13460  * with future versions of GObject by checking that the signal handler is still
13461  * connected before disconnected it:
13462  *
13463  *  if (g_signal_handler_is_connected(instance, id))
13464  *    g_signal_handler_disconnect(instance, id);
13465  */
13466 static void
13467 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13468 {
13469         GList* sig_list = NULL;
13470         MMPlayerSignalItem* item = NULL;
13471
13472         MMPLAYER_FENTER();
13473
13474         MMPLAYER_RETURN_IF_FAIL(player);
13475
13476         LOGD("release signals type : %d", type);
13477
13478         if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13479                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13480                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13481                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13482                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13483                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13484                 return;
13485         }
13486
13487         sig_list = player->signals[type];
13488
13489         for (; sig_list; sig_list = sig_list->next) {
13490                 item = sig_list->data;
13491
13492                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13493                         if (g_signal_handler_is_connected(item->obj, item->sig))
13494                                 g_signal_handler_disconnect(item->obj, item->sig);
13495                 }
13496
13497                 MMPLAYER_FREEIF(item);
13498         }
13499
13500         g_list_free(player->signals[type]);
13501         player->signals[type] = NULL;
13502
13503         MMPLAYER_FLEAVE();
13504
13505         return;
13506 }
13507
13508 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13509 {
13510         mm_player_t* player = 0;
13511         int prev_display_surface_type = 0;
13512         void *prev_display_overlay = NULL;
13513         const gchar *klass = NULL;
13514         gchar *cur_videosink_name = NULL;
13515         int ret = 0;
13516         int i = 0;
13517         int num_of_dec = 2; /* DEC1, DEC2 */
13518
13519         MMPLAYER_FENTER();
13520
13521         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13522         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13523
13524         player = MM_PLAYER_CAST(handle);
13525
13526         if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13527                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13528                 MMPLAYER_FLEAVE();
13529                 return MM_ERROR_INVALID_ARGUMENT;
13530         }
13531
13532         /* load previous attributes */
13533         if (player->attrs) {
13534                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13535                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13536                 LOGD("[0: Video surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13537                 if (prev_display_surface_type == surface_type) {
13538                         LOGD("incoming display surface type is same as previous one, do nothing..");
13539                         MMPLAYER_FLEAVE();
13540                         return MM_ERROR_NONE;
13541                 }
13542         } else {
13543                 LOGE("failed to load attributes");
13544                 MMPLAYER_FLEAVE();
13545                 return MM_ERROR_PLAYER_INTERNAL;
13546         }
13547
13548         /* check videosink element is created */
13549         if (!player->pipeline || !player->pipeline->videobin ||
13550                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13551                 LOGD("videosink element is not yet ready");
13552
13553                 /* videobin is not created yet, so we just set attributes related to display surface */
13554                 LOGD("store display attribute for given surface type(%d)", surface_type);
13555                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13556                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13557                 if (mmf_attrs_commit(player->attrs)) {
13558                         LOGE("failed to commit attribute");
13559                         MMPLAYER_FLEAVE();
13560                         return MM_ERROR_PLAYER_INTERNAL;
13561                 }
13562                 MMPLAYER_FLEAVE();
13563                 return MM_ERROR_NONE;
13564         } else {
13565                 /* get player command status */
13566                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13567                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13568                         MMPLAYER_FLEAVE();
13569                         return MM_ERROR_PLAYER_INVALID_STATE;
13570                 }
13571
13572                 /* get a current videosink name */
13573                 cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13574
13575                 /* surface change */
13576                 for (i = 0 ; i < num_of_dec ; i++) {
13577                         if (player->pipeline->mainbin &&
13578                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13579                                 GstElementFactory *decfactory;
13580                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13581
13582                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13583                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13584                                         if (!strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS)) {
13585                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay);
13586                                                 if (ret) {
13587                                                         goto ERROR_CASE;
13588                                                 } else {
13589                                                         LOGW("success to changing display surface(%d)", surface_type);
13590                                                         MMPLAYER_FLEAVE();
13591                                                         return MM_ERROR_NONE;
13592                                                 }
13593                                         } else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13594                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13595                                                 if (ret) {
13596                                                         goto ERROR_CASE;
13597                                                 } else {
13598                                                         LOGW("success to changing display surface(%d)", surface_type);
13599                                                         MMPLAYER_FLEAVE();
13600                                                         return MM_ERROR_NONE;
13601                                                 }
13602                                         } else {
13603                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13604                                                 ret = MM_ERROR_PLAYER_INTERNAL;
13605                                                 goto ERROR_CASE;
13606                                         }
13607                                 }
13608                         }
13609                 }
13610         }
13611
13612 ERROR_CASE:
13613         /* rollback to previous attributes */
13614         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13615         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13616         if (mmf_attrs_commit(player->attrs)) {
13617                 LOGE("failed to commit attributes to rollback");
13618                 MMPLAYER_FLEAVE();
13619                 return MM_ERROR_PLAYER_INTERNAL;
13620         }
13621         MMPLAYER_FLEAVE();
13622         return ret;
13623 }
13624
13625 /* NOTE : It does not support some use cases, eg using colorspace converter */
13626 int
13627 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13628 {
13629         GstPad *src_pad_dec = NULL;
13630         GstPad *sink_pad_videosink = NULL;
13631         GstPad *sink_pad_videobin = NULL;
13632         GstClock *clock = NULL;
13633         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13634         int ret = MM_ERROR_NONE;
13635         gboolean is_audiobin_created = TRUE;
13636
13637         MMPLAYER_FENTER();
13638
13639         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13640         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13641         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13642
13643         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13644         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13645
13646         /* get information whether if audiobin is created */
13647         if (!player->pipeline->audiobin ||
13648                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13649                 LOGW("audiobin is null, this video content may not have audio data");
13650                 is_audiobin_created = FALSE;
13651         }
13652
13653         /* get current state of player */
13654         previous_state = MMPLAYER_CURRENT_STATE(player);
13655         LOGD("previous state(%d)", previous_state);
13656
13657
13658         /* get src pad of decoder and block it */
13659         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13660         if (!src_pad_dec) {
13661                 LOGE("failed to get src pad from decode in mainbin");
13662                 return MM_ERROR_PLAYER_INTERNAL;
13663         }
13664
13665         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13666                 LOGW("trying to block pad(video)");
13667 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13668                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13669                         NULL, NULL, NULL);
13670                 {
13671                         LOGE("failed to set block pad(video)");
13672                         return MM_ERROR_PLAYER_INTERNAL;
13673                 }
13674                 LOGW("pad is blocked(video)");
13675         } else {
13676                 /* no data flows, so no need to do pad_block */
13677                 if (player->doing_seek)
13678                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
13679
13680                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13681         }
13682
13683         /* remove pad */
13684         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13685                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13686                 LOGE("failed to remove previous ghost_pad for videobin");
13687                 return MM_ERROR_PLAYER_INTERNAL;
13688         }
13689
13690         /* change state of videobin to NULL */
13691         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13692         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13693         if (ret != GST_STATE_CHANGE_SUCCESS) {
13694                 LOGE("failed to change state of videobin to NULL");
13695                 return MM_ERROR_PLAYER_INTERNAL;
13696         }
13697
13698         /* unlink between decoder and videobin and remove previous videosink from videobin */
13699         GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13700         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13701                 LOGE("failed to remove former videosink from videobin");
13702                 return MM_ERROR_PLAYER_INTERNAL;
13703         }
13704
13705         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13706
13707         /* create a new videosink and add it to videobin */
13708         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13709         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13710                 LOGE("failed to create videosink element\n");
13711                 MMPLAYER_FLEAVE();
13712                 return MM_ERROR_PLAYER_INTERNAL;
13713         }
13714         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13715         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13716         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13717
13718         /* save attributes */
13719         if (player->attrs) {
13720                 /* set a new display surface type */
13721                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13722                 /* set a new diplay overlay */
13723                 switch (surface_type) {
13724                 case MM_DISPLAY_SURFACE_OVERLAY:
13725                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13726                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13727                         break;
13728                 case MM_DISPLAY_SURFACE_EVAS:
13729                         LOGD("save attributes related to display surface to EVAS : evas image object = %x", display_overlay);
13730                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(void*));
13731                         break;
13732                 default:
13733                         LOGE("invalid type(%d) for changing display surface", surface_type);
13734                         MMPLAYER_FLEAVE();
13735                         return MM_ERROR_INVALID_ARGUMENT;
13736                 }
13737                 if (mmf_attrs_commit(player->attrs)) {
13738                         LOGE("failed to commit");
13739                         MMPLAYER_FLEAVE();
13740                         return MM_ERROR_PLAYER_INTERNAL;
13741                 }
13742         } else {
13743                 LOGE("player->attrs is null, failed to save attributes");
13744                 MMPLAYER_FLEAVE();
13745                 return MM_ERROR_PLAYER_INTERNAL;
13746         }
13747
13748         /* update video param */
13749         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13750                 LOGE("failed to update video param");
13751                 return MM_ERROR_PLAYER_INTERNAL;
13752         }
13753
13754         /* change state of videobin to READY */
13755         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13756         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13757         if (ret != GST_STATE_CHANGE_SUCCESS) {
13758                 LOGE("failed to change state of videobin to READY");
13759                 return MM_ERROR_PLAYER_INTERNAL;
13760         }
13761
13762         /* change ghostpad */
13763         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13764         if (!sink_pad_videosink) {
13765                 LOGE("failed to get sink pad from videosink element");
13766                 return MM_ERROR_PLAYER_INTERNAL;
13767         }
13768         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13769         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13770                 LOGE("failed to set active to ghost_pad");
13771                 return MM_ERROR_PLAYER_INTERNAL;
13772         }
13773         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13774                 LOGE("failed to change ghostpad for videobin");
13775                 return MM_ERROR_PLAYER_INTERNAL;
13776         }
13777         gst_object_unref(sink_pad_videosink);
13778
13779         /* link decoder with videobin */
13780         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13781         if (!sink_pad_videobin) {
13782                 LOGE("failed to get sink pad from videobin");
13783                 return MM_ERROR_PLAYER_INTERNAL;
13784         }
13785         if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13786                 LOGE("failed to link");
13787                 return MM_ERROR_PLAYER_INTERNAL;
13788         }
13789         gst_object_unref(sink_pad_videobin);
13790
13791         /* clock setting for a new videosink plugin */
13792         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13793                         so we set it from audiosink plugin or pipeline(system clock) */
13794         if (!is_audiobin_created) {
13795                 LOGW("audiobin is not created, get clock from pipeline..");
13796                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13797         } else {
13798                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13799         }
13800         if (clock) {
13801                 GstClockTime now;
13802                 GstClockTime base_time;
13803                 LOGD("set the clock to videosink");
13804                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13805                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13806                 if (clock) {
13807                         LOGD("got clock of videosink");
13808                         now = gst_clock_get_time(clock);
13809                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13810                         LOGD("at time %" GST_TIME_FORMAT ", base %"
13811                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13812                 } else {
13813                         LOGE("failed to get clock of videosink after setting clock");
13814                         return MM_ERROR_PLAYER_INTERNAL;
13815                 }
13816         } else
13817                 LOGW("failed to get clock, maybe it is the time before first playing");
13818
13819         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13820                 /* change state of videobin to PAUSED */
13821                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13822                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13823                 if (ret != GST_STATE_CHANGE_FAILURE) {
13824                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13825                 } else {
13826                         LOGE("failed to change state of videobin to PLAYING");
13827                         return MM_ERROR_PLAYER_INTERNAL;
13828                 }
13829
13830                 /* release blocked and unref src pad of video decoder */
13831                 #if 0
13832                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13833                         LOGE("failed to set pad blocked FALSE(video)");
13834                         return MM_ERROR_PLAYER_INTERNAL;
13835                 }
13836                 #endif
13837                 LOGW("pad is unblocked(video)");
13838         } else {
13839                 if (player->doing_seek)
13840                         LOGW("not completed seek(%d)", player->doing_seek);
13841                 /* change state of videobin to PAUSED */
13842                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13843                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13844                 if (ret != GST_STATE_CHANGE_FAILURE) {
13845                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13846                 } else {
13847                         LOGE("failed to change state of videobin to PLAYING");
13848                         return MM_ERROR_PLAYER_INTERNAL;
13849                 }
13850
13851                 /* already skipped pad block */
13852                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
13853         }
13854
13855         /* do get/set position for new videosink plugin */
13856         {
13857                 unsigned long position = 0;
13858                 gint64 pos_msec = 0;
13859
13860                 LOGD("do get/set position for new videosink plugin");
13861                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
13862                         LOGE("failed to get position");
13863                         return MM_ERROR_PLAYER_INTERNAL;
13864                 }
13865 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
13866                 /* accurate seek */
13867                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
13868                         LOGE("failed to set position");
13869                         return MM_ERROR_PLAYER_INTERNAL;
13870                 }
13871 #else
13872                 /* key unit seek */
13873                 pos_msec = position * G_GINT64_CONSTANT(1000000);
13874                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
13875                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
13876                                                         GST_SEEK_TYPE_SET, pos_msec,
13877                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
13878                 if (!ret) {
13879                         LOGE("failed to set position");
13880                         return MM_ERROR_PLAYER_INTERNAL;
13881                 }
13882 #endif
13883         }
13884
13885         if (src_pad_dec)
13886                 gst_object_unref(src_pad_dec);
13887         LOGD("success to change sink");
13888
13889         MMPLAYER_FLEAVE();
13890
13891         return MM_ERROR_NONE;
13892 }
13893
13894
13895 /* Note : if silent is true, then subtitle would not be displayed. :*/
13896 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
13897 {
13898         mm_player_t* player = (mm_player_t*) hplayer;
13899
13900         MMPLAYER_FENTER();
13901
13902         /* check player handle */
13903         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13904
13905         player->set_mode.subtitle_off = silent;
13906
13907         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
13908
13909         MMPLAYER_FLEAVE();
13910
13911         return MM_ERROR_NONE;
13912 }
13913
13914 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
13915 {
13916         int result = MM_ERROR_NONE;
13917         GstPad *peer = NULL, *pad = NULL;
13918         GstElement *Element = NULL;
13919         MMPlayerGstElement* mainbin = NULL;
13920         mainbin = player->pipeline->mainbin;
13921
13922         #if 0
13923         if (!gst_pad_set_blocked(inpad, TRUE)) {
13924                 result = MM_ERROR_PLAYER_INTERNAL;
13925                 goto EXIT;
13926         }
13927         #endif
13928         gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13929                         NULL, NULL, NULL);
13930
13931         /*Getting pad connected to demuxer audio pad */
13932         peer = gst_pad_get_peer(inpad);
13933         /* Disconnecting Demuxer and its peer plugin [audio] */
13934         if (peer) {
13935                 if (!gst_pad_unlink(inpad, peer)) {
13936                         result = MM_ERROR_PLAYER_INTERNAL;
13937                         goto EXIT;
13938                 }
13939         } else {
13940                 result = MM_ERROR_PLAYER_INTERNAL;
13941                 goto EXIT;
13942         }
13943         /*Removing elements between Demuxer and audiobin*/
13944         while (peer != NULL) {
13945                 gchar *Element_name = NULL;
13946                 gchar *factory_name = NULL;
13947                 GList *elements = NULL;
13948                 GstElementFactory *factory = NULL;
13949                 /*Getting peer element*/
13950                 Element = gst_pad_get_parent_element(peer);
13951                 if (Element == NULL) {
13952                         gst_object_unref(peer);
13953                         result = MM_ERROR_PLAYER_INTERNAL;
13954                         break;
13955                 }
13956
13957                 Element_name = gst_element_get_name(Element);
13958                 factory = gst_element_get_factory(Element);
13959                 /*checking the element is audio bin*/
13960                 if (!strcmp(Element_name, "audiobin")) {
13961                         gst_object_unref(peer);
13962                         result = MM_ERROR_NONE;
13963                         g_free(Element_name);
13964                         break;
13965                 }
13966                 factory_name = GST_OBJECT_NAME(factory);
13967                 pad = gst_element_get_static_pad(Element, "src");
13968                 if (pad == NULL) {
13969                         result = MM_ERROR_PLAYER_INTERNAL;
13970                         g_free(Element_name);
13971                         break;
13972                 }
13973                 gst_object_unref(peer);
13974                 peer = gst_pad_get_peer(pad);
13975                 if (peer) {
13976                         if (!gst_pad_unlink(pad, peer)) {
13977                                 gst_object_unref(peer);
13978                                 gst_object_unref(pad);
13979                                 result = MM_ERROR_PLAYER_INTERNAL;
13980                                 g_free(Element_name);
13981                                 break;
13982                         }
13983                 }
13984                 elements = player->parsers;
13985                 /* Removing the element form the list*/
13986                 for (; elements; elements = g_list_next(elements)) {
13987                         Element_name = elements->data;
13988                         if (g_strrstr(Element_name, factory_name))
13989                                 player->parsers = g_list_remove(player->parsers, elements->data);
13990                 }
13991                 gst_element_set_state(Element, GST_STATE_NULL);
13992                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
13993                 gst_object_unref(pad);
13994                 if (Element == mainbin[MMPLAYER_M_Q1].gst)
13995                         mainbin[MMPLAYER_M_Q1].gst = NULL;
13996                 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
13997                         mainbin[MMPLAYER_M_Q2].gst = NULL;
13998                 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
13999                         mainbin[MMPLAYER_M_DEC1].gst = NULL;
14000                 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14001                         mainbin[MMPLAYER_M_DEC2].gst = NULL;
14002
14003                 gst_object_unref(Element);
14004         }
14005 EXIT:
14006         return result;
14007 }
14008
14009 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14010 {
14011         MMPlayerGstElement* mainbin = NULL;
14012         MMPlayerGstElement* textbin = NULL;
14013         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14014         GstState current_state = GST_STATE_VOID_PENDING;
14015         GstState element_state = GST_STATE_VOID_PENDING;
14016         GstState element_pending_state = GST_STATE_VOID_PENDING;
14017         gint64 time = 0;
14018         GstEvent *event = NULL;
14019         int result = MM_ERROR_NONE;
14020
14021         GstClock *curr_clock = NULL;
14022         GstClockTime base_time, start_time, curr_time;
14023
14024
14025         MMPLAYER_FENTER();
14026
14027         /* check player handle */
14028         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14029
14030         if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14031                 LOGE("Pipeline is not in proper state\n");
14032                 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14033                 goto EXIT;
14034         }
14035
14036         mainbin = player->pipeline->mainbin;
14037         textbin = player->pipeline->textbin;
14038
14039         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14040
14041         // sync clock with current pipeline
14042         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14043         curr_time = gst_clock_get_time(curr_clock);
14044
14045         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14046         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14047
14048         LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14049                 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14050
14051         if (current_state > GST_STATE_READY) {
14052                 // sync state with current pipeline
14053                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14054                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14055                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14056
14057                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14058                 if (GST_STATE_CHANGE_FAILURE == ret)
14059                         LOGE("fail to state change.\n");
14060         }
14061
14062         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14063         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14064
14065         if (curr_clock) {
14066                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14067                 gst_object_unref(curr_clock);
14068         }
14069
14070         // seek to current position
14071         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14072                 result = MM_ERROR_PLAYER_INVALID_STATE;
14073                 LOGE("gst_element_query_position failed, invalid state\n");
14074                 goto EXIT;
14075         }
14076
14077         LOGD("seek time = %lld\n", time);
14078         event = gst_event_new_seek(1.0, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
14079         if (event) {
14080                 __gst_send_event_to_sink(player, event);
14081         } else {
14082                 result = MM_ERROR_PLAYER_INTERNAL;
14083                 LOGE("gst_event_new_seek failed\n");
14084                 goto EXIT;
14085         }
14086
14087         // sync state with current pipeline
14088         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14089         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14090         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14091
14092 EXIT:
14093         return result;
14094 }
14095
14096 static int
14097 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14098 {
14099         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14100         GstState current_state = GST_STATE_VOID_PENDING;
14101
14102         MMHandleType attrs = 0;
14103         MMPlayerGstElement* mainbin = NULL;
14104         MMPlayerGstElement* textbin = NULL;
14105
14106         gchar* subtitle_uri = NULL;
14107         int result = MM_ERROR_NONE;
14108         const gchar *charset = NULL;
14109
14110         MMPLAYER_FENTER();
14111
14112         /* check player handle */
14113         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14114         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14115
14116         if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14117                 result = MM_ERROR_PLAYER_INVALID_STATE;
14118                 LOGE("Pipeline is not in proper state\n");
14119                 goto EXIT;
14120         }
14121
14122         mainbin = player->pipeline->mainbin;
14123         textbin = player->pipeline->textbin;
14124
14125         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14126         if (current_state < GST_STATE_READY) {
14127                 result = MM_ERROR_PLAYER_INVALID_STATE;
14128                 LOGE("Pipeline is not in proper state\n");
14129                 goto EXIT;
14130         }
14131
14132         attrs = MMPLAYER_GET_ATTRS(player);
14133         if (!attrs) {
14134                 LOGE("cannot get content attribute\n");
14135                 result = MM_ERROR_PLAYER_INTERNAL;
14136                 goto EXIT;
14137         }
14138
14139         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14140         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14141                 LOGE("subtitle uri is not proper filepath\n");
14142                 result = MM_ERROR_PLAYER_INVALID_URI;
14143                 goto EXIT;
14144         }
14145
14146         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14147         LOGD("new subtitle file path is [%s]\n", filepath);
14148
14149         if (!strcmp(filepath, subtitle_uri)) {
14150                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14151                 goto EXIT;
14152         } else {
14153                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14154                 if (mmf_attrs_commit(player->attrs)) {
14155                         LOGE("failed to commit.\n");
14156                         goto EXIT;
14157                 }
14158         }
14159
14160         //gst_pad_set_blocked_async(src-srcpad, TRUE)
14161
14162         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14163         if (ret != GST_STATE_CHANGE_SUCCESS) {
14164                 LOGE("failed to change state of textbin to READY");
14165                 result = MM_ERROR_PLAYER_INTERNAL;
14166                 goto EXIT;
14167         }
14168
14169         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14170         if (ret != GST_STATE_CHANGE_SUCCESS) {
14171                 LOGE("failed to change state of subparse to READY");
14172                 result = MM_ERROR_PLAYER_INTERNAL;
14173                 goto EXIT;
14174         }
14175
14176         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14177         if (ret != GST_STATE_CHANGE_SUCCESS) {
14178                 LOGE("failed to change state of filesrc to READY");
14179                 result = MM_ERROR_PLAYER_INTERNAL;
14180                 goto EXIT;
14181         }
14182
14183         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14184
14185         charset = util_get_charset(filepath);
14186         if (charset) {
14187                 LOGD("detected charset is %s\n", charset);
14188                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14189         }
14190
14191         result = _mmplayer_sync_subtitle_pipeline(player);
14192
14193 EXIT:
14194         MMPLAYER_FLEAVE();
14195         return result;
14196 }
14197
14198 /* API to switch between external subtitles */
14199 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14200 {
14201         int result = MM_ERROR_NONE;
14202         mm_player_t* player = (mm_player_t*)hplayer;
14203
14204         MMPLAYER_FENTER();
14205
14206         /* check player handle */
14207         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14208
14209         if (!player->pipeline) {
14210                 // IDLE state
14211                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14212                 if (mmf_attrs_commit(player->attrs)) {
14213                         LOGE("failed to commit.\n");
14214                         result = MM_ERROR_PLAYER_INTERNAL;
14215                 }
14216         } else {
14217                 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14218                 if (filepath == NULL)
14219                         return MM_ERROR_COMMON_INVALID_ARGUMENT;
14220
14221                 if (!__mmplayer_check_subtitle(player)) {
14222                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14223                         if (mmf_attrs_commit(player->attrs)) {
14224                                 LOGE("failed to commit.\n");
14225                                 result = MM_ERROR_PLAYER_INTERNAL;
14226                         }
14227
14228                         if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14229                                 LOGE("fail to create subtitle src\n");
14230
14231                         result = _mmplayer_sync_subtitle_pipeline(player);
14232                 } else
14233                         result = __mmplayer_change_external_subtitle_language(player, filepath);
14234         }
14235
14236         MMPLAYER_FLEAVE();
14237         return result;
14238 }
14239
14240 static int
14241 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14242 {
14243         int result = MM_ERROR_NONE;
14244         gchar* change_pad_name = NULL;
14245         GstPad* sinkpad = NULL;
14246         MMPlayerGstElement* mainbin = NULL;
14247         enum MainElementID elemId = MMPLAYER_M_NUM;
14248         GstCaps* caps = NULL;
14249         gint total_track_num = 0;
14250
14251         MMPLAYER_FENTER();
14252
14253         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14254                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
14255
14256         LOGD("Change Track(%d) to %d\n", type, index);
14257
14258         mainbin = player->pipeline->mainbin;
14259
14260         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14261                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14262         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14263                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14264         } else {
14265                 /* Changing Video Track is not supported. */
14266                 LOGE("Track Type Error\n");
14267                 goto EXIT;
14268         }
14269
14270         if (mainbin[elemId].gst == NULL) {
14271                 result = MM_ERROR_PLAYER_NO_OP;
14272                 LOGD("Req track doesn't exist\n");
14273                 goto EXIT;
14274         }
14275
14276         total_track_num = player->selector[type].total_track_num;
14277         if (total_track_num <= 0) {
14278                 result = MM_ERROR_PLAYER_NO_OP;
14279                 LOGD("Language list is not available \n");
14280                 goto EXIT;
14281         }
14282
14283         if ((index < 0) || (index >= total_track_num)) {
14284                 result = MM_ERROR_INVALID_ARGUMENT;
14285                 LOGD("Not a proper index : %d \n", index);
14286                 goto EXIT;
14287         }
14288
14289         /*To get the new pad from the selector*/
14290         change_pad_name = g_strdup_printf("sink_%u", index);
14291         if (change_pad_name == NULL) {
14292                 result = MM_ERROR_PLAYER_INTERNAL;
14293                 LOGD("Pad does not exists\n");
14294                 goto EXIT;
14295         }
14296
14297         LOGD("new active pad name: %s\n", change_pad_name);
14298
14299         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14300         if (sinkpad == NULL) {
14301                 LOGD("sinkpad is NULL");
14302                 result = MM_ERROR_PLAYER_INTERNAL;
14303                 goto EXIT;
14304         }
14305
14306         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14307         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14308
14309         caps = gst_pad_get_current_caps(sinkpad);
14310         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14311
14312         if (sinkpad)
14313                 gst_object_unref(sinkpad);
14314
14315         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14316                 __mmplayer_set_audio_attrs(player, caps);
14317
14318 EXIT:
14319
14320         MMPLAYER_FREEIF(change_pad_name);
14321         return result;
14322 }
14323
14324 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14325 {
14326         int result = MM_ERROR_NONE;
14327         mm_player_t* player = NULL;
14328         MMPlayerGstElement* mainbin = NULL;
14329
14330         gint current_active_index = 0;
14331
14332         GstState current_state = GST_STATE_VOID_PENDING;
14333         GstEvent* event = NULL;
14334         gint64 time = 0;
14335
14336         MMPLAYER_FENTER();
14337
14338         player = (mm_player_t*)hplayer;
14339         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14340
14341         if (!player->pipeline) {
14342                 LOGE("Track %d pre setting -> %d\n", type, index);
14343
14344                 player->selector[type].active_pad_index = index;
14345                 goto EXIT;
14346         }
14347
14348         mainbin = player->pipeline->mainbin;
14349
14350         current_active_index = player->selector[type].active_pad_index;
14351
14352         /*If index is same as running index no need to change the pad*/
14353         if (current_active_index == index)
14354                 goto EXIT;
14355
14356         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14357                 result = MM_ERROR_PLAYER_INVALID_STATE;
14358                 goto EXIT;
14359         }
14360
14361         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14362         if (current_state < GST_STATE_PAUSED) {
14363                 result = MM_ERROR_PLAYER_INVALID_STATE;
14364                 LOGW("Pipeline not in porper state\n");
14365                 goto EXIT;
14366         }
14367
14368         result = __mmplayer_change_selector_pad(player, type, index);
14369         if (result != MM_ERROR_NONE) {
14370                 LOGE("change selector pad error\n");
14371                 goto EXIT;
14372         }
14373
14374         player->selector[type].active_pad_index = index;
14375
14376         if (current_state == GST_STATE_PLAYING) {
14377                 event = gst_event_new_seek(1.0, 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);
14378                 if (event) {
14379                         __gst_send_event_to_sink(player, event);
14380                 } else {
14381                         result = MM_ERROR_PLAYER_INTERNAL;
14382                         goto EXIT;
14383                 }
14384         }
14385
14386 EXIT:
14387         return result;
14388 }
14389
14390 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14391 {
14392         mm_player_t* player = (mm_player_t*) hplayer;
14393
14394         MMPLAYER_FENTER();
14395
14396         /* check player handle */
14397         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14398
14399         *silent = player->set_mode.subtitle_off;
14400
14401         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14402
14403         MMPLAYER_FLEAVE();
14404
14405         return MM_ERROR_NONE;
14406 }
14407
14408 gboolean
14409 __is_ms_buff_src(mm_player_t* player)
14410 {
14411         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14412
14413         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14414 }
14415
14416 gboolean
14417 __has_suffix(mm_player_t* player, const gchar* suffix)
14418 {
14419         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14420         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14421
14422         gboolean ret = FALSE;
14423         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14424         gchar* t_suffix = g_ascii_strdown(suffix, -1);
14425
14426         if (g_str_has_suffix(player->profile.uri, suffix))
14427                 ret = TRUE;
14428
14429         MMPLAYER_FREEIF(t_url);
14430         MMPLAYER_FREEIF(t_suffix);
14431
14432         return ret;
14433 }
14434
14435 int
14436 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14437 {
14438         mm_player_t* player = (mm_player_t*) hplayer;
14439
14440         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14441
14442         MMPLAYER_VIDEO_SINK_CHECK(player);
14443
14444         LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14445
14446         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14447
14448         return MM_ERROR_NONE;
14449 }
14450 int
14451 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14452 {
14453
14454         mm_player_t* player = (mm_player_t*) hplayer;
14455         float _level = 0.0;
14456         int _x = 0;
14457         int _y = 0;
14458
14459         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14460
14461         MMPLAYER_VIDEO_SINK_CHECK(player);
14462
14463         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14464
14465         LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14466
14467         *level = _level;
14468         *x = _x;
14469         *y = _y;
14470
14471         return MM_ERROR_NONE;
14472 }
14473
14474 int
14475 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14476 {
14477         mm_player_t* player = (mm_player_t*) hplayer;
14478
14479         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14480
14481         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14482                 MMPLAYER_PRINT_STATE(player);
14483                 LOGE("wrong-state : can't set the download mode to parse");
14484                 return MM_ERROR_PLAYER_INVALID_STATE;
14485         }
14486
14487         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14488         player->video_hub_download_mode = mode;
14489
14490         return MM_ERROR_NONE;
14491 }
14492
14493 int
14494 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14495 {
14496         mm_player_t* player = (mm_player_t*) hplayer;
14497
14498         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14499
14500         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14501         player->sync_handler = enable;
14502
14503         return MM_ERROR_NONE;
14504 }
14505
14506 int
14507 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14508                                         long long clock,
14509                                         long long clock_delta,
14510                                         long long video_time,
14511                                         long long media_clock,
14512                                         long long audio_time)
14513 {
14514         mm_player_t* player = (mm_player_t*) hplayer;
14515         MMPlayerGstElement* mainbin = NULL;
14516         GstClockTime start_time_audio = 0, start_time_video = 0;
14517         GstClockTimeDiff base_time = 0, new_base_time = 0;
14518         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14519         gint64 api_delta = 0;
14520         gint64 position = 0, position_delta = 0;
14521         gint64 adj_base_time = 0;
14522         GstClock *curr_clock = NULL;
14523         GstClockTime curr_time = 0;
14524         gboolean query_ret = TRUE;
14525         int result = MM_ERROR_NONE;
14526
14527         MMPLAYER_FENTER();
14528
14529         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14530         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14531         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14532
14533         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14534
14535         if ((video_time < 0) || (player->doing_seek)) {
14536                 LOGD("skip setting master clock.  %lld", video_time);
14537                 goto EXIT;
14538         }
14539
14540         mainbin = player->pipeline->mainbin;
14541
14542         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14543         curr_time = gst_clock_get_time(curr_clock);
14544
14545         current_state = MMPLAYER_CURRENT_STATE(player);
14546
14547         if (current_state == MM_PLAYER_STATE_PLAYING)
14548                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14549
14550         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14551                 (!query_ret)) {
14552                 position = player->last_position;
14553                 LOGD("query fail. %lld", position);
14554         }
14555
14556         clock *= GST_USECOND;
14557         clock_delta *= GST_USECOND;
14558
14559         api_delta = clock - curr_time;
14560         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14561                 player->video_share_api_delta = api_delta;
14562         else
14563                 clock_delta += (api_delta - player->video_share_api_delta);
14564
14565         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14566                 player->video_share_clock_delta = (gint64)clock_delta;
14567
14568                 position_delta = (position/GST_USECOND) - video_time;
14569                 position_delta *= GST_USECOND;
14570
14571                 adj_base_time = position_delta;
14572                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14573
14574         } else {
14575                 gint64 new_play_time = 0;
14576                 gint64 network_delay = 0;
14577
14578                 video_time *= GST_USECOND;
14579
14580                 network_delay = clock_delta - player->video_share_clock_delta;
14581                 new_play_time = video_time + network_delay;
14582
14583                 adj_base_time = position - new_play_time;
14584
14585                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14586                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14587         }
14588
14589         /* Adjust Current Stream Time with base_time of sink
14590          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14591          * 2. Set new base time
14592          *    if adj_base_time is positive value, the stream time will be decreased.
14593          * 3. If seek event is occurred, the start time will be reset. */
14594         if ((player->pipeline->audiobin) &&
14595                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14596                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14597
14598                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14599                         LOGD("audio sink : gst_element_set_start_time -> NONE");
14600                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14601                 }
14602
14603                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14604         }
14605
14606         if ((player->pipeline->videobin) &&
14607                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14608                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14609
14610                 if (start_time_video != GST_CLOCK_TIME_NONE) {
14611                         LOGD("video sink : gst_element_set_start_time -> NONE");
14612                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14613                 }
14614
14615                 // if videobin exist, get base_time from videobin.
14616                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14617         }
14618
14619         new_base_time = base_time + adj_base_time;
14620
14621         if ((player->pipeline->audiobin) &&
14622                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14623                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14624
14625         if ((player->pipeline->videobin) &&
14626                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14627                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14628
14629 EXIT:
14630         MMPLAYER_FLEAVE();
14631
14632         return result;
14633 }
14634
14635 int
14636 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14637                                         long long *video_time,
14638                                         long long *media_clock,
14639                                         long long *audio_time)
14640 {
14641         mm_player_t* player = (mm_player_t*) hplayer;
14642         MMPlayerGstElement* mainbin = NULL;
14643         GstClock *curr_clock = NULL;
14644         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14645         gint64 position = 0;
14646         gboolean query_ret = TRUE;
14647
14648         MMPLAYER_FENTER();
14649
14650         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14651         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14652         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14653
14654         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14655         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14656         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14657
14658         mainbin = player->pipeline->mainbin;
14659
14660         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14661
14662         current_state = MMPLAYER_CURRENT_STATE(player);
14663
14664         if (current_state != MM_PLAYER_STATE_PAUSED)
14665                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14666
14667         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14668                 (!query_ret))
14669                 position = player->last_position;
14670
14671         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14672
14673         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14674
14675         if (curr_clock)
14676                 gst_object_unref(curr_clock);
14677
14678         MMPLAYER_FLEAVE();
14679
14680         return MM_ERROR_NONE;
14681 }
14682
14683 int
14684 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14685 {
14686         mm_player_t* player = (mm_player_t*) hplayer;
14687         int org_angle = 0;
14688
14689         MMPLAYER_FENTER();
14690
14691         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14692         MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14693
14694         if (player->v_stream_caps) {
14695                 GstStructure *str = NULL;
14696
14697                 str = gst_caps_get_structure(player->v_stream_caps, 0);
14698                 if (!gst_structure_get_int(str, "orientation", &org_angle))
14699                         LOGD("missing 'orientation' field in video caps");
14700         }
14701
14702         LOGD("orientation: %d", org_angle);
14703         *angle = org_angle;
14704
14705         MMPLAYER_FLEAVE();
14706         return MM_ERROR_NONE;
14707 }
14708
14709 static gboolean
14710 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14711 {
14712         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14713         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14714
14715         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14716         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14717
14718         int idx = 0;
14719
14720         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14721                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14722                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14723                         mm_player_dump_t *dump_s;
14724                         dump_s = g_malloc(sizeof(mm_player_dump_t));
14725
14726                         if (dump_s == NULL) {
14727                                 LOGE("malloc fail");
14728                                 return FALSE;
14729                         }
14730
14731                         dump_s->dump_element_file = NULL;
14732                         dump_s->dump_pad = NULL;
14733                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14734
14735                         if (dump_s->dump_pad) {
14736                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14737                                 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]);
14738                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14739                                 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);
14740                                 /* add list for removed buffer probe and close FILE */
14741                                 player->dump_list = g_list_append(player->dump_list, dump_s);
14742                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
14743                                 return TRUE;
14744                         } else {
14745                                 g_free(dump_s);
14746                                 dump_s = NULL;
14747                                 LOGE("failed to get %s sink pad added", factory_name);
14748                         }
14749
14750
14751                 }
14752         }
14753         return FALSE;
14754 }
14755
14756 static GstPadProbeReturn
14757 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
14758 {
14759         FILE *dump_data = (FILE *) u_data;
14760 //      int written = 0;
14761         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14762         GstMapInfo probe_info = GST_MAP_INFO_INIT;
14763
14764         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14765
14766         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14767
14768 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14769
14770         fwrite(probe_info.data, 1, probe_info.size , dump_data);
14771
14772         return GST_PAD_PROBE_OK;
14773 }
14774
14775 static void
14776 __mmplayer_release_dump_list(GList *dump_list)
14777 {
14778         if (dump_list) {
14779                 GList *d_list = dump_list;
14780                 for (; d_list; d_list = g_list_next(d_list)) {
14781                         mm_player_dump_t *dump_s = d_list->data;
14782                         if (dump_s->dump_pad) {
14783                                 if (dump_s->probe_handle_id)
14784                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14785                         }
14786                         if (dump_s->dump_element_file) {
14787                                 fclose(dump_s->dump_element_file);
14788                                 dump_s->dump_element_file = NULL;
14789                         }
14790                         MMPLAYER_FREEIF(dump_s);
14791                 }
14792                 g_list_free(dump_list);
14793                 dump_list = NULL;
14794         }
14795 }
14796
14797 int
14798 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14799 {
14800         mm_player_t* player = (mm_player_t*) hplayer;
14801
14802         MMPLAYER_FENTER();
14803
14804         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14805         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14806
14807         *exist = player->has_closed_caption;
14808
14809         MMPLAYER_FLEAVE();
14810
14811         return MM_ERROR_NONE;
14812 }
14813
14814 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14815 {
14816         void * ret = NULL
14817         MMPLAYER_FENTER();
14818         /* increase ref count of gst buffer */
14819         if (buffer)
14820                 ret = gst_buffer_ref((GstBuffer *)buffer);
14821
14822         MMPLAYER_FLEAVE();
14823         return ret;
14824 }
14825
14826 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14827 {
14828         MMPLAYER_FENTER();
14829         if (buffer) {
14830                 gst_buffer_unref((GstBuffer *)buffer);
14831                 buffer = NULL;
14832         }
14833         MMPLAYER_FLEAVE();
14834 }
14835
14836 void
14837 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14838 {
14839         mm_player_t *player  = (mm_player_t*)user_data;
14840         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14841         guint64 current_level_bytes = 0;
14842
14843         MMPLAYER_RETURN_IF_FAIL(player);
14844
14845         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14846
14847         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14848
14849         if (player->media_stream_buffer_status_cb[type])
14850                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14851 }
14852
14853 void
14854 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
14855 {
14856         mm_player_t *player  = (mm_player_t*)user_data;
14857         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14858         guint64 current_level_bytes = 0;
14859
14860         MMPLAYER_RETURN_IF_FAIL(player);
14861
14862         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14863
14864         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
14865
14866         if (player->media_stream_buffer_status_cb[type])
14867                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14868 }
14869
14870 void
14871 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
14872 {
14873         mm_player_t *player  = (mm_player_t*)user_data;
14874         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14875         guint64 current_level_bytes = 0;
14876
14877         MMPLAYER_RETURN_IF_FAIL(player);
14878
14879         LOGI("app-src: feed subtitle\n");
14880
14881         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14882
14883         if (player->media_stream_buffer_status_cb[type])
14884                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14885 }
14886
14887 void
14888 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
14889 {
14890         mm_player_t *player  = (mm_player_t*)user_data;
14891         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14892         guint64 current_level_bytes = 0;
14893
14894         MMPLAYER_RETURN_IF_FAIL(player);
14895
14896         LOGI("app-src: audio buffer is full.\n");
14897
14898         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14899
14900         if (player->media_stream_buffer_status_cb[type])
14901                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
14902 }
14903
14904 void
14905 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
14906 {
14907         mm_player_t *player  = (mm_player_t*)user_data;
14908         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14909         guint64 current_level_bytes = 0;
14910
14911         MMPLAYER_RETURN_IF_FAIL(player);
14912
14913         LOGI("app-src: video buffer is full.\n");
14914
14915         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14916
14917         if (player->media_stream_buffer_status_cb[type])
14918                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
14919 }
14920
14921 gboolean
14922 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
14923 {
14924         mm_player_t *player  = (mm_player_t*)user_data;
14925         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14926
14927         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14928
14929         LOGD("app-src: seek audio data %llu\n", position);
14930
14931         if (player->media_stream_seek_data_cb[type])
14932                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14933
14934         return TRUE;
14935 }
14936
14937 gboolean
14938 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
14939 {
14940         mm_player_t *player  = (mm_player_t*)user_data;
14941         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14942
14943         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14944
14945         LOGD("app-src: seek video data %llu\n", position);
14946
14947         if (player->media_stream_seek_data_cb[type])
14948                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14949
14950         return TRUE;
14951 }
14952
14953 gboolean
14954 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
14955 {
14956         mm_player_t *player  = (mm_player_t*)user_data;
14957         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14958
14959         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14960
14961         LOGD("app-src: seek subtitle data\n");
14962
14963         if (player->media_stream_seek_data_cb[type])
14964                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14965
14966         return TRUE;
14967 }
14968
14969 int
14970 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
14971 {
14972         mm_player_t* player = (mm_player_t*) hplayer;
14973
14974         MMPLAYER_FENTER();
14975
14976         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14977
14978         player->pcm_samplerate = samplerate;
14979         player->pcm_channel = channel;
14980
14981         MMPLAYER_FLEAVE();
14982         return MM_ERROR_NONE;
14983 }
14984
14985 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
14986 {
14987         mm_player_t* player = (mm_player_t*) hplayer;
14988
14989         MMPLAYER_FENTER();
14990
14991         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14992         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
14993
14994         if (MMPLAYER_IS_STREAMING(player))
14995                 *timeout = player->ini.live_state_change_timeout;
14996         else
14997                 *timeout = player->ini.localplayback_state_change_timeout;
14998
14999         LOGD("timeout = %d\n", *timeout);
15000
15001         MMPLAYER_FLEAVE();
15002         return MM_ERROR_NONE;
15003 }
15004
15005 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15006 {
15007         mm_player_t* player = (mm_player_t*) hplayer;
15008
15009         MMPLAYER_FENTER();
15010
15011         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15012         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15013
15014         *num = player->video_num_buffers;
15015         *extra_num = player->video_extra_num_buffers;
15016
15017         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15018
15019         MMPLAYER_FLEAVE();
15020         return MM_ERROR_NONE;
15021 }
15022