[0.6.125] improve the complexity issue of gst_callback
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
52
53 #include <system_info.h>
54 #include <sound_manager.h>
55
56 /*===========================================================================================
57 |                                                                                                                                                                                       |
58 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
59 |                                                                                                                                                                                       |
60 ========================================================================================== */
61
62 /*---------------------------------------------------------------------------
63 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
64 ---------------------------------------------------------------------------*/
65
66 /*---------------------------------------------------------------------------
67 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
68 ---------------------------------------------------------------------------*/
69
70 /*---------------------------------------------------------------------------
71 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
72 ---------------------------------------------------------------------------*/
73
74 /*---------------------------------------------------------------------------
75 |    LOCAL #defines:                                                                                                            |
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
79
80 #define MM_VOLUME_FACTOR_DEFAULT                1.0
81 #define MM_VOLUME_FACTOR_MIN                    0
82 #define MM_VOLUME_FACTOR_MAX                    1.0
83
84 /* Don't need to sleep for sound fadeout
85  * fadeout related fucntion will be deleted(Deprecated)
86  */
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
88
89 #define DEFAULT_PLAYBACK_RATE                   1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
91
92 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94         (player->ini.http_use_file_buffer) && \
95         (player->http_file_buffering_path) && \
96         (strlen(player->http_file_buffering_path) > 0))
97
98 #define PLAYER_DISPLAY_MODE_DST_ROI             5
99
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
101
102 /* For PD mode */
103 #define PLAYER_PD_EXT_MAX_SIZE_BYTE             1024 * 1024 * 3
104
105 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
106 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
107 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
108 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
109
110 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
111 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
112
113 /*---------------------------------------------------------------------------
114 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
115 ---------------------------------------------------------------------------*/
116
117 /*---------------------------------------------------------------------------
118 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
119 ---------------------------------------------------------------------------*/
120
121 /*---------------------------------------------------------------------------
122 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
123 ---------------------------------------------------------------------------*/
124
125 /*---------------------------------------------------------------------------
126 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
129
130 /*---------------------------------------------------------------------------
131 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
132 ---------------------------------------------------------------------------*/
133 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
135 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
138 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
140
141 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
142 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
143 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
144 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
145 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
146 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
147 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
151 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
152 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
153 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
154 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
155 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
156 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
157 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
158
159 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
160 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
166 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
169 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
171
172 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
173 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
174 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
175 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
176 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
177 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
178 static gpointer __mmplayer_next_play_thread(gpointer data);
179 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
180 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
181 static void __mmplayer_release_dump_list(GList *dump_list);
182 static int              __gst_realize(mm_player_t* player);
183 static int              __gst_unrealize(mm_player_t* player);
184 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
185 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
186 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
187
188 /* util */
189 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
190 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
191 static int __mmplayer_start_streaming_ext(mm_player_t *player);
192 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
193 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
194 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
195 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
196 static void __mmplayer_check_pipeline(mm_player_t* player);
197 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
198 static void __mmplayer_deactivate_old_path(mm_player_t *player);
199 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
200 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
201 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
202 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
203 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
204 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
205 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
206 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
207 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
208 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
209 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
210 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
211 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
212 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
213 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
214
215 /*===========================================================================================
216 |                                                                                                                                                                                       |
217 |  FUNCTION DEFINITIONS                                                                                                                                         |
218 |                                                                                                                                                                                       |
219 ========================================================================================== */
220
221 #if 0 //debug
222 static void
223 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
224 {
225         gint i, count;
226
227         count = gst_tag_list_get_tag_size(list, tag);
228
229         LOGD("count = %d", count);
230
231         for (i = 0; i < count; i++) {
232                 gchar *str;
233
234                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
235                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
236                                 g_assert_not_reached();
237                 } else
238                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
239
240                 if (i == 0)
241                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
242                 else
243                         g_print("                 : %s\n", str);
244
245                 g_free(str);
246         }
247 }
248 #endif
249
250 /* This function should be called after the pipeline goes PAUSED or higher
251 state. */
252 gboolean
253 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
254 {
255         static gboolean has_duration = FALSE;
256         static gboolean has_video_attrs = FALSE;
257         static gboolean has_audio_attrs = FALSE;
258         static gboolean has_bitrate = FALSE;
259         gboolean missing_only = FALSE;
260         gboolean all = FALSE;
261         gint64 dur_nsec = 0;
262         GstStructure* p = NULL;
263         MMHandleType attrs = 0;
264         gchar *path = NULL;
265         struct stat sb;
266
267         MMPLAYER_FENTER();
268
269         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
270
271         /* check player state here */
272         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
273                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
274                 /* give warning now only */
275                 LOGW("be careful. content attributes may not available in this state ");
276         }
277
278         /* get content attribute first */
279         attrs = MMPLAYER_GET_ATTRS(player);
280         if (!attrs) {
281                 LOGE("cannot get content attribute");
282                 return FALSE;
283         }
284
285         /* get update flag */
286
287         if (flag & ATTR_MISSING_ONLY) {
288                 missing_only = TRUE;
289                 LOGD("updating missed attr only");
290         }
291
292         if (flag & ATTR_ALL) {
293                 all = TRUE;
294                 has_duration = FALSE;
295                 has_video_attrs = FALSE;
296                 has_audio_attrs = FALSE;
297                 has_bitrate = FALSE;
298
299                 LOGD("updating all attrs");
300         }
301
302         if (missing_only && all) {
303                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
304                 missing_only = FALSE;
305         }
306
307         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
308                 LOGD("try to update duration");
309                 has_duration = FALSE;
310
311                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
312                         player->duration = dur_nsec;
313                         LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
314                         has_duration = TRUE;
315                 }
316
317                 if (player->duration < 0) {
318                         LOGW("duration is Non-Initialized !!!");
319                         player->duration = 0;
320                 }
321
322                 /* update streaming service type */
323                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
324
325                 /* check duration is OK */
326                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
327                         /* FIXIT : find another way to get duration here. */
328                         LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
329                 }
330         }
331
332         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
333                 /* update audio params
334                 NOTE : We need original audio params and it can be only obtained from src pad of audio
335                 decoder. Below code only valid when we are not using 'resampler' just before
336                 'audioconverter'. */
337
338                 LOGD("try to update audio attrs");
339                 has_audio_attrs = FALSE;
340
341                 if (player->pipeline->audiobin &&
342                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
343                         GstCaps *caps_a = NULL;
344                         GstPad* pad = NULL;
345                         gint samplerate = 0, channels = 0;
346
347                         pad = gst_element_get_static_pad(
348                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
349
350                         if (pad) {
351                                 caps_a = gst_pad_get_current_caps(pad);
352
353                                 if (caps_a) {
354                                         p = gst_caps_get_structure(caps_a, 0);
355
356                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
357
358                                         gst_structure_get_int(p, "rate", &samplerate);
359                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
360
361                                         gst_structure_get_int(p, "channels", &channels);
362                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
363
364                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
365
366                                         gst_caps_unref(caps_a);
367                                         caps_a = NULL;
368
369                                         has_audio_attrs = TRUE;
370                                 } else
371                                         LOGW("not ready to get audio caps");
372
373                                 gst_object_unref(pad);
374                         } else
375                                 LOGW("failed to get pad from audiosink");
376                 }
377         }
378
379         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
380                 LOGD("try to update video attrs");
381                 has_video_attrs = FALSE;
382
383                 if (player->pipeline->videobin &&
384                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
385                         GstCaps *caps_v = NULL;
386                         GstPad* pad = NULL;
387                         gint tmpNu, tmpDe;
388                         gint width, height;
389
390                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
391                         if (pad) {
392                                 caps_v = gst_pad_get_current_caps(pad);
393
394                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
395                                 if (!caps_v && player->v_stream_caps) {
396                                         caps_v = player->v_stream_caps;
397                                         gst_caps_ref(caps_v);
398                                 }
399
400                                 if (caps_v) {
401                                         p = gst_caps_get_structure(caps_v, 0);
402                                         gst_structure_get_int(p, "width", &width);
403                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
404
405                                         gst_structure_get_int(p, "height", &height);
406                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
407
408                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
409
410                                         SECURE_LOGD("width : %d     height : %d", width, height);
411
412                                         gst_caps_unref(caps_v);
413                                         caps_v = NULL;
414
415                                         if (tmpDe > 0) {
416                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
417                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
418                                         }
419
420                                         has_video_attrs = TRUE;
421                                 } else
422                                         LOGD("no negitiated caps from videosink");
423                                 gst_object_unref(pad);
424                                 pad = NULL;
425                         } else {
426                                 LOGD("no videosink sink pad");
427                         }
428                 }
429         }
430
431
432         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
433                 has_bitrate = FALSE;
434
435                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
436                 if (player->duration) {
437                         guint64 data_size = 0;
438
439                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
440                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
441
442                                 if (stat(path, &sb) == 0)
443                                         data_size = (guint64)sb.st_size;
444                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
445                                 data_size = player->http_content_size;
446                         }
447                         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
448
449                         if (data_size) {
450                                 guint64 bitrate = 0;
451                                 guint64 msec_dur = 0;
452
453                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
454                                 if (msec_dur > 0) {
455                                         bitrate = data_size * 8 * 1000 / msec_dur;
456                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
457                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
458
459                                         has_bitrate = TRUE;
460                                 } else {
461                                         LOGD("player duration is less than 0");
462                                 }
463                         }
464
465                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
466                                 if (player->total_bitrate) {
467                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
468                                         has_bitrate = TRUE;
469                                 }
470                         }
471                 }
472         }
473
474         /* validate all */
475         if (mmf_attrs_commit(attrs)) {
476                 LOGE("failed to update attributes\n");
477                 return FALSE;
478         }
479
480         MMPLAYER_FLEAVE();
481
482         return TRUE;
483 }
484
485 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
486 {
487         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
488
489         MMPLAYER_FENTER();
490
491         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
492                         player->pipeline &&
493                         player->pipeline->mainbin &&
494                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
495                         STREAMING_SERVICE_NONE);
496
497         /* streaming service type if streaming */
498         if (!MMPLAYER_IS_STREAMING(player))
499                 return STREAMING_SERVICE_NONE;
500
501         if (MMPLAYER_IS_HTTP_STREAMING(player))
502                 streaming_type = (player->duration == 0) ?
503                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
504
505         switch (streaming_type) {
506         case STREAMING_SERVICE_LIVE:
507                 LOGD("it's live streaming");
508                 break;
509         case STREAMING_SERVICE_VOD:
510                 LOGD("it's vod streaming");
511                 break;
512         default:
513                 LOGE("should not get here");
514                 break;
515         }
516
517         MMPLAYER_FLEAVE();
518
519         return streaming_type;
520 }
521
522
523 /* this function sets the player state and also report
524  * it to applicaton by calling callback function
525  */
526 void
527 __mmplayer_set_state(mm_player_t* player, int state)
528 {
529         MMMessageParamType msg = {0, };
530         gboolean post_bos = FALSE;
531
532         MMPLAYER_RETURN_IF_FAIL(player);
533
534         if (MMPLAYER_CURRENT_STATE(player) == state) {
535                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
536                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
537                 return;
538         }
539
540         /* update player states */
541         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
542         MMPLAYER_CURRENT_STATE(player) = state;
543
544         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
545                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
546
547         /* print state */
548         MMPLAYER_PRINT_STATE(player);
549
550         switch (MMPLAYER_CURRENT_STATE(player)) {
551         case MM_PLAYER_STATE_NULL:
552         case MM_PLAYER_STATE_READY:
553                 break;
554
555         case MM_PLAYER_STATE_PAUSED:
556                 {
557                         if (!player->sent_bos) {
558                                 /* rtsp case, get content attrs by GstMessage */
559                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
560                                         /* it's first time to update all content attrs. */
561                                         __mmplayer_update_content_attrs(player, ATTR_ALL);
562                                 }
563                         }
564
565                         /* add audio callback probe if condition is satisfied */
566                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
567                                 __mmplayer_configure_audio_callback(player);
568
569                         /* FIXIT : handle return value */
570                 }
571                 break;
572
573         case MM_PLAYER_STATE_PLAYING:
574                 {
575                         /* try to get content metadata */
576                         if (!player->sent_bos) {
577                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
578                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
579                                  * legacy mmfw-player api */
580                                 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
581                         }
582
583                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
584                                 if (!player->sent_bos)
585                                         __mmplayer_handle_missed_plugin(player);
586                         }
587
588                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
589                                 /* initialize because auto resume is done well. */
590                                 player->resumed_by_rewind = FALSE;
591                                 player->playback_rate = 1.0;
592                         }
593
594                         if (!player->sent_bos) {
595                                 /* check audio codec field is set or not
596                                  * we can get it from typefinder or codec's caps.
597                                  */
598                                 gchar *audio_codec = NULL;
599                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
600
601                                 /* The codec format can't be sent for audio only case like amr, mid etc.
602                                  * Because, parser don't make related TAG.
603                                  * So, if it's not set yet, fill it with found data.
604                                  */
605                                 if (!audio_codec) {
606                                         if (g_strrstr(player->type, "audio/midi"))
607                                                 audio_codec = g_strdup("MIDI");
608                                         else if (g_strrstr(player->type, "audio/x-amr"))
609                                                 audio_codec = g_strdup("AMR");
610                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
611                                                 audio_codec = g_strdup("AAC");
612                                         else
613                                                 audio_codec = g_strdup("unknown");
614                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
615
616                                         MMPLAYER_FREEIF(audio_codec);
617                                         if (mmf_attrs_commit(player->attrs))
618                                                 LOGE("failed to update attributes\n");
619
620                                         LOGD("set audio codec type with caps\n");
621                                 }
622
623                                 post_bos = TRUE;
624                         }
625                 }
626                 break;
627
628         case MM_PLAYER_STATE_NONE:
629         default:
630                 LOGW("invalid target state, there is nothing to do.\n");
631                 break;
632         }
633
634
635         /* post message to application */
636         if (MMPLAYER_TARGET_STATE(player) == state) {
637                 /* fill the message with state of player */
638                 msg.union_type = MM_MSG_UNION_STATE;
639                 msg.state.previous = MMPLAYER_PREV_STATE(player);
640                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
641
642                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
643
644                 /* state changed by resource callback */
645                 if (player->interrupted_by_resource) {
646                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
647                 } else { /* state changed by usecase */
648                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
649                 }
650         } else {
651                 LOGD("intermediate state, do nothing.\n");
652                 MMPLAYER_PRINT_STATE(player);
653                 return;
654         }
655
656         if (post_bos) {
657                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
658                 player->sent_bos = TRUE;
659         }
660
661         return;
662 }
663
664 int
665 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
666 {
667         MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
668         MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
669
670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
671
672         //LOGD("incomming command : %d \n", command);
673
674         current_state = MMPLAYER_CURRENT_STATE(player);
675         pending_state = MMPLAYER_PENDING_STATE(player);
676
677         MMPLAYER_PRINT_STATE(player);
678
679         switch (command) {
680         case MMPLAYER_COMMAND_CREATE:
681         {
682                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
683
684                 if (current_state == MM_PLAYER_STATE_NULL ||
685                         current_state == MM_PLAYER_STATE_READY ||
686                         current_state == MM_PLAYER_STATE_PAUSED ||
687                         current_state == MM_PLAYER_STATE_PLAYING)
688                         goto NO_OP;
689         }
690         break;
691
692         case MMPLAYER_COMMAND_DESTROY:
693         {
694                 /* destroy can called anytime */
695
696                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
697         }
698         break;
699
700         case MMPLAYER_COMMAND_REALIZE:
701         {
702                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
703
704                 if (pending_state != MM_PLAYER_STATE_NONE) {
705                         goto INVALID_STATE;
706                 } else {
707                         /* need ready state to realize */
708                         if (current_state == MM_PLAYER_STATE_READY)
709                                 goto NO_OP;
710
711                         if (current_state != MM_PLAYER_STATE_NULL)
712                                 goto INVALID_STATE;
713                 }
714         }
715         break;
716
717         case MMPLAYER_COMMAND_UNREALIZE:
718         {
719                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
720
721                 if (current_state == MM_PLAYER_STATE_NULL)
722                         goto NO_OP;
723         }
724         break;
725
726         case MMPLAYER_COMMAND_START:
727         {
728                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
729
730                 if (pending_state == MM_PLAYER_STATE_NONE) {
731                         if (current_state == MM_PLAYER_STATE_PLAYING)
732                                 goto NO_OP;
733                         else if (current_state  != MM_PLAYER_STATE_READY &&
734                                 current_state != MM_PLAYER_STATE_PAUSED)
735                                 goto INVALID_STATE;
736                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
737                         goto ALREADY_GOING;
738                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
739                         LOGD("player is going to paused state, just change the pending state as playing");
740                 } else
741                         goto INVALID_STATE;
742         }
743         break;
744
745         case MMPLAYER_COMMAND_STOP:
746         {
747                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
748
749                 if (current_state == MM_PLAYER_STATE_READY)
750                         goto NO_OP;
751
752                 /* need playing/paused state to stop */
753                 if (current_state != MM_PLAYER_STATE_PLAYING &&
754                          current_state != MM_PLAYER_STATE_PAUSED)
755                         goto INVALID_STATE;
756         }
757         break;
758
759         case MMPLAYER_COMMAND_PAUSE:
760         {
761                 if (MMPLAYER_IS_LIVE_STREAMING(player))
762                         goto NO_OP;
763
764                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
765                         goto NOT_COMPLETED_SEEK;
766
767                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
768
769                 if (pending_state == MM_PLAYER_STATE_NONE) {
770                         if (current_state == MM_PLAYER_STATE_PAUSED)
771                                 goto NO_OP;
772                         else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
773                                 goto INVALID_STATE;
774                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
775                         goto ALREADY_GOING;
776                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
777                         if (current_state == MM_PLAYER_STATE_PAUSED)
778                                 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
779                         else
780                                 goto INVALID_STATE;
781                 }
782         }
783         break;
784
785         case MMPLAYER_COMMAND_RESUME:
786         {
787                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
788                         goto NOT_COMPLETED_SEEK;
789
790                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
791
792                 if (pending_state == MM_PLAYER_STATE_NONE) {
793                         if (current_state == MM_PLAYER_STATE_PLAYING)
794                                 goto NO_OP;
795                         else if (current_state != MM_PLAYER_STATE_PAUSED)
796                                 goto INVALID_STATE;
797                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
798                         goto ALREADY_GOING;
799                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
800                         LOGD("player is going to paused state, just change the pending state as playing");
801                 } else
802                         goto INVALID_STATE;
803         }
804                 break;
805
806         default:
807                 break;
808         }
809         player->cmd = command;
810
811         return MM_ERROR_NONE;
812
813 INVALID_STATE:
814         LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
815                 MMPLAYER_STATE_GET_NAME(current_state), command);
816         return MM_ERROR_PLAYER_INVALID_STATE;
817
818 NOT_COMPLETED_SEEK:
819         LOGW("not completed seek");
820         return MM_ERROR_PLAYER_DOING_SEEK;
821
822 NO_OP:
823         LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
824         return MM_ERROR_PLAYER_NO_OP;
825
826 ALREADY_GOING:
827         LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
828         return MM_ERROR_PLAYER_NO_OP;
829 }
830
831 static gpointer __mmplayer_next_play_thread(gpointer data)
832 {
833         mm_player_t* player = (mm_player_t*) data;
834         MMPlayerGstElement *mainbin = NULL;
835
836         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
837
838         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
839         while (!player->next_play_thread_exit) {
840                 LOGD("next play thread started. waiting for signal.\n");
841                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
842
843                 LOGD("reconfigure pipeline for gapless play.\n");
844
845                 if (player->next_play_thread_exit) {
846                         if (player->gapless.reconfigure) {
847                                 player->gapless.reconfigure = false;
848                                 MMPLAYER_PLAYBACK_UNLOCK(player);
849                         }
850                         LOGD("exiting gapless play thread\n");
851                         break;
852                 }
853
854                 mainbin = player->pipeline->mainbin;
855
856                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
857                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
858                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
859                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
860                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
861
862                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
863         }
864         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
865
866         return NULL;
867 }
868
869 static void
870 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
871 {
872         GSource *source = NULL;
873
874         MMPLAYER_FENTER();
875
876         source = g_main_context_find_source_by_id(context, source_id);
877
878         if (source != NULL) {
879                 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
880                 g_source_destroy(source);
881         }
882
883         MMPLAYER_FLEAVE();
884 }
885
886 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
887 {
888         mm_player_t* player = (mm_player_t*)hplayer;
889         GstMessage *msg = NULL;
890         GQueue *queue = NULL;
891
892         MMPLAYER_FENTER();
893         MMPLAYER_RETURN_IF_FAIL(player);
894
895         /* disconnecting bus watch */
896         if (player->bus_watcher)
897                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
898         player->bus_watcher = 0;
899
900         /* destroy the gst bus msg thread */
901         if (player->bus_msg_thread) {
902                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
903                 player->bus_msg_thread_exit = TRUE;
904                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
905                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
906
907                 LOGD("gst bus msg thread exit.");
908                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
909                 player->bus_msg_thread = NULL;
910
911                 g_mutex_clear(&player->bus_msg_thread_mutex);
912                 g_cond_clear(&player->bus_msg_thread_cond);
913         }
914
915         g_mutex_lock(&player->bus_msg_q_lock);
916         queue = player->bus_msg_q;
917         while (!g_queue_is_empty(queue)) {
918                 msg = (GstMessage *)g_queue_pop_head(queue);
919                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
920                 gst_message_unref(msg);
921         }
922         g_mutex_unlock(&player->bus_msg_q_lock);
923
924         MMPLAYER_FLEAVE();
925 }
926
927 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
928 {
929         mm_player_t *player = (mm_player_t *) data;
930
931         g_return_val_if_fail(player, FALSE);
932         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
933
934         gst_message_ref(msg);
935
936         g_mutex_lock(&player->bus_msg_q_lock);
937         g_queue_push_tail(player->bus_msg_q, msg);
938         g_mutex_unlock(&player->bus_msg_q_lock);
939
940         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
941         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
942         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
943         return TRUE;
944 }
945
946 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
947 {
948         mm_player_t *player = (mm_player_t*)(data);
949         GstMessage *msg = NULL;
950         GstBus *bus = NULL;
951
952         MMPLAYER_FENTER();
953         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
954                                                 player->pipeline &&
955                                                 player->pipeline->mainbin &&
956                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
957                                                 NULL);
958
959         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
960         if (!bus) {
961                 LOGE("cannot get BUS from the pipeline");
962                 return NULL;
963         }
964
965         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
966
967         LOGD("[handle: %p] gst bus msg thread will be started.", player);
968         while (!player->bus_msg_thread_exit) {
969                 g_mutex_lock(&player->bus_msg_q_lock);
970                 msg = g_queue_pop_head(player->bus_msg_q);
971                 g_mutex_unlock(&player->bus_msg_q_lock);
972                 if (msg == NULL) {
973                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
974                         continue;
975                 }
976                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
977                 /* handle the gst msg */
978                 __mmplayer_gst_bus_msg_callback(msg, player);
979                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
980                 gst_message_unref(msg);
981         }
982
983         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
984         gst_object_unref(GST_OBJECT(bus));
985
986         MMPLAYER_FLEAVE();
987         return NULL;
988 }
989
990 static void
991 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
992 {
993         mm_player_t* player = (mm_player_t*) data;
994
995         MMPLAYER_FENTER();
996
997         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
998           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
999           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
1000           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1001
1002           * [1] audio and video will be dumped with filesink.
1003           * [2] autoplugging is done by just using pad caps.
1004           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1005           * and the video will be dumped via filesink.
1006           */
1007         if (player->num_dynamic_pad == 0) {
1008                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1009
1010                 if (!__mmplayer_gst_remove_fakesink(player,
1011                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1012                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1013                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1014                          * source element are not same. To overcome this situation, this function will called
1015                          * several places and several times. Therefore, this is not an error case.
1016                          */
1017                         return;
1018         }
1019
1020         /* create dot before error-return. for debugging */
1021         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1022
1023         player->no_more_pad = TRUE;
1024
1025         MMPLAYER_FLEAVE();
1026 }
1027
1028 static gboolean
1029 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
1030 {
1031         GstElement* parent = NULL;
1032
1033         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1034
1035         /* if we have no fakesink. this meas we are using decodebin which doesn'
1036         t need to add extra fakesink */
1037         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
1038
1039         /* lock */
1040         MMPLAYER_FSINK_LOCK(player);
1041
1042         if (!fakesink->gst)
1043                 goto ERROR;
1044
1045         /* get parent of fakesink */
1046         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
1047         if (!parent) {
1048                 LOGD("fakesink already removed\n");
1049                 goto ERROR;
1050         }
1051
1052         gst_element_set_locked_state(fakesink->gst, TRUE);
1053
1054         /* setting the state to NULL never returns async
1055          * so no need to wait for completion of state transiton
1056          */
1057         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
1058                 LOGE("fakesink state change failure!\n");
1059                 /* FIXIT : should I return here? or try to proceed to next? */
1060                 /* return FALSE; */
1061
1062         /* remove fakesink from it's parent */
1063         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
1064                 LOGE("failed to remove fakesink\n");
1065
1066                 gst_object_unref(parent);
1067
1068                 goto ERROR;
1069         }
1070
1071         gst_object_unref(parent);
1072
1073         LOGD("state-holder removed\n");
1074
1075         gst_element_set_locked_state(fakesink->gst, FALSE);
1076
1077         MMPLAYER_FSINK_UNLOCK(player);
1078         return TRUE;
1079
1080 ERROR:
1081         if (fakesink->gst)
1082                 gst_element_set_locked_state(fakesink->gst, FALSE);
1083
1084         MMPLAYER_FSINK_UNLOCK(player);
1085         return FALSE;
1086 }
1087
1088
1089 static void
1090 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
1091 {
1092         GstPad *sinkpad = NULL;
1093         GstCaps* caps = NULL;
1094         GstElement* new_element = NULL;
1095         GstStructure* str = NULL;
1096         const gchar* name = NULL;
1097
1098         mm_player_t* player = (mm_player_t*) data;
1099
1100         MMPLAYER_FENTER();
1101
1102         MMPLAYER_RETURN_IF_FAIL(element && pad);
1103         MMPLAYER_RETURN_IF_FAIL(player &&
1104                                         player->pipeline &&
1105                                         player->pipeline->mainbin);
1106
1107
1108         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
1109          * num_dynamic_pad will decreased after creating a sinkbin.
1110          */
1111         player->num_dynamic_pad++;
1112         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
1113
1114         caps = gst_pad_query_caps(pad, NULL);
1115
1116         MMPLAYER_CHECK_NULL(caps);
1117
1118         /* clear  previous result*/
1119         player->have_dynamic_pad = FALSE;
1120
1121         str = gst_caps_get_structure(caps, 0);
1122
1123         if (!str) {
1124                 LOGE("cannot get structure from caps.\n");
1125                 goto ERROR;
1126         }
1127
1128         name = gst_structure_get_name(str);
1129         if (!name) {
1130                 LOGE("cannot get mimetype from structure.\n");
1131                 goto ERROR;
1132         }
1133
1134         if (strstr(name, "video")) {
1135                 gint stype = 0;
1136                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1137
1138                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
1139                         if (player->v_stream_caps) {
1140                                 gst_caps_unref(player->v_stream_caps);
1141                                 player->v_stream_caps = NULL;
1142                         }
1143
1144                         new_element = gst_element_factory_make("fakesink", NULL);
1145                         player->num_dynamic_pad--;
1146                         goto NEW_ELEMENT;
1147                 }
1148         }
1149
1150         /* clear  previous result*/
1151         player->have_dynamic_pad = FALSE;
1152
1153         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
1154                 LOGE("failed to autoplug for caps");
1155                 goto ERROR;
1156         }
1157
1158         /* check if there's dynamic pad*/
1159         if (player->have_dynamic_pad) {
1160                 LOGE("using pad caps assums there's no dynamic pad !\n");
1161                 goto ERROR;
1162         }
1163
1164         gst_caps_unref(caps);
1165         caps = NULL;
1166
1167 NEW_ELEMENT:
1168
1169         /* excute new_element if created*/
1170         if (new_element) {
1171                 LOGD("adding new element to pipeline\n");
1172
1173                 /* set state to READY before add to bin */
1174                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
1175
1176                 /* add new element to the pipeline */
1177                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
1178                         LOGE("failed to add autoplug element to bin\n");
1179                         goto ERROR;
1180                 }
1181
1182                 /* get pad from element */
1183                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
1184                 if (!sinkpad) {
1185                         LOGE("failed to get sinkpad from autoplug element\n");
1186                         goto ERROR;
1187                 }
1188
1189                 /* link it */
1190                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1191                         LOGE("failed to link autoplug element\n");
1192                         goto ERROR;
1193                 }
1194
1195                 gst_object_unref(sinkpad);
1196                 sinkpad = NULL;
1197
1198                 /* run. setting PLAYING here since streamming source is live source */
1199                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
1200         }
1201
1202         if (caps)
1203                 gst_caps_unref(caps);
1204
1205         MMPLAYER_FLEAVE();
1206
1207         return;
1208
1209 STATE_CHANGE_FAILED:
1210 ERROR:
1211         /* FIXIT : take care if new_element has already added to pipeline */
1212         if (new_element)
1213                 gst_object_unref(GST_OBJECT(new_element));
1214
1215         if (sinkpad)
1216                 gst_object_unref(GST_OBJECT(sinkpad));
1217
1218         if (caps)
1219                 gst_caps_unref(caps);
1220
1221         /* FIXIT : how to inform this error to MSL ????? */
1222         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
1223          * then post an error to application
1224          */
1225 }
1226
1227 static GstPadProbeReturn
1228 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
1229 {
1230         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
1231         return GST_PAD_PROBE_OK;
1232 }
1233
1234 static GstPadProbeReturn
1235 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
1236 {
1237         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1238         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
1239         mm_player_t* player = (mm_player_t*)data;
1240         GstCaps* caps = NULL;
1241         GstStructure* str = NULL;
1242         const gchar* name = NULL;
1243         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1244
1245
1246         if (GST_EVENT_IS_DOWNSTREAM(event)) {
1247                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1248                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1249                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1250                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
1251                         return ret;
1252         } else if (GST_EVENT_IS_UPSTREAM(event)) {
1253                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1254                         return ret;
1255         }
1256
1257         caps = gst_pad_query_caps(pad, NULL);
1258         if (!caps) {
1259                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
1260                 return ret;
1261         }
1262
1263         str = gst_caps_get_structure(caps, 0);
1264         if (!str) {
1265                 LOGE("failed to get structure from caps");
1266                 goto ERROR;
1267         }
1268
1269         name = gst_structure_get_name(str);
1270         if (!name) {
1271                 LOGE("failed to get name from str");
1272                 goto ERROR;
1273         }
1274
1275         if (strstr(name, "audio")) {
1276                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1277         } else if (strstr(name, "video")) {
1278                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1279         } else {
1280                 /* text track is not supportable */
1281                 LOGE("invalid name %s", name);
1282                 goto ERROR;
1283         }
1284
1285         switch (GST_EVENT_TYPE(event)) {
1286         case GST_EVENT_EOS:
1287                 {
1288                         /* in case of gapless, drop eos event not to send it to sink */
1289                         if (player->gapless.reconfigure && !player->msg_posted) {
1290                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1291                                 ret = GST_PAD_PROBE_DROP;
1292                         }
1293                         break;
1294                 }
1295         case GST_EVENT_STREAM_START:
1296                 {
1297                         gint64 stop_running_time = 0;
1298                         gint64 position_running_time = 0;
1299                         gint64 position = 0;
1300                         gint idx = 0;
1301
1302                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
1303                                 if ((player->gapless.update_segment[idx] == TRUE) ||
1304                                         !(player->selector[idx].event_probe_id)) {
1305                                         /* LOGW("[%d] skip", idx); */
1306                                         continue;
1307                                 }
1308
1309                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
1310                                         stop_running_time =
1311                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
1312                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
1313                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
1314                                         stop_running_time =
1315                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
1316                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
1317                                 } else {
1318                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
1319                                         stop_running_time =
1320                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
1321                                                                 GST_FORMAT_TIME, player->duration);
1322                                 }
1323
1324                                 position_running_time =
1325                                         gst_segment_to_running_time(&player->gapless.segment[idx],
1326                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
1327
1328                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
1329                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
1330                                         idx,
1331                                         GST_TIME_ARGS(stop_running_time),
1332                                         GST_TIME_ARGS(position_running_time),
1333                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
1334                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
1335
1336                                 position_running_time = MAX(position_running_time, stop_running_time);
1337                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
1338                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
1339                                 position_running_time = MAX(0, position_running_time);
1340                                 position = MAX(position, position_running_time);
1341                         }
1342
1343                         if (position != 0) {
1344                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1345                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
1346                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
1347
1348                                 player->gapless.start_time[stream_type] += position;
1349                         }
1350                         break;
1351                 }
1352         case GST_EVENT_FLUSH_STOP:
1353                 {
1354                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1355                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1356                         player->gapless.start_time[stream_type] = 0;
1357                         break;
1358                 }
1359         case GST_EVENT_SEGMENT:
1360                 {
1361                         GstSegment segment;
1362                         GstEvent *tmpev;
1363
1364                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1365                         gst_event_copy_segment(event, &segment);
1366
1367                         if (segment.format == GST_FORMAT_TIME) {
1368                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1369                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1370                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1371                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1372                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1373                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1374
1375                                 /* keep the all the segment ev to cover the seeking */
1376                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1377                                 player->gapless.update_segment[stream_type] = TRUE;
1378
1379                                 if (!player->gapless.running)
1380                                         break;
1381
1382                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1383
1384                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1385
1386                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1387                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1388                                 gst_event_unref(event);
1389                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1390                         }
1391                         break;
1392                 }
1393         case GST_EVENT_QOS:
1394                 {
1395                         gdouble proportion = 0.0;
1396                         GstClockTimeDiff diff = 0;
1397                         GstClockTime timestamp = 0;
1398                         gint64 running_time_diff = -1;
1399                         GstQOSType type = 0;
1400                         GstEvent *tmpev = NULL;
1401
1402                         running_time_diff = player->gapless.segment[stream_type].base;
1403
1404                         if (running_time_diff <= 0) /* don't need to adjust */
1405                                 break;
1406
1407                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
1408                         gst_event_unref(event);
1409
1410                         if (timestamp < running_time_diff) {
1411                                 LOGW("QOS event from previous group");
1412                                 ret = GST_PAD_PROBE_DROP;
1413                                 break;
1414                         }
1415
1416                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1417                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1418                                                 stream_type, GST_TIME_ARGS(timestamp),
1419                                                 GST_TIME_ARGS(running_time_diff),
1420                                                 GST_TIME_ARGS(timestamp - running_time_diff));
1421
1422                         timestamp -= running_time_diff;
1423
1424                         /* That case is invalid for QoS events */
1425                         if (diff < 0 && -diff > timestamp) {
1426                                 LOGW("QOS event from previous group");
1427                                 ret = GST_PAD_PROBE_DROP;
1428                                 break;
1429                         }
1430
1431                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1432                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1433
1434                         break;
1435                 }
1436         default:
1437                 break;
1438         }
1439
1440 ERROR:
1441         if (caps)
1442                 gst_caps_unref(caps);
1443         return ret;
1444 }
1445
1446 static void
1447 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1448 {
1449         mm_player_t* player = NULL;
1450         GstElement* pipeline = NULL;
1451         GstElement* selector = NULL;
1452         GstElement* fakesink = NULL;
1453         GstCaps* caps = NULL;
1454         GstStructure* str = NULL;
1455         const gchar* name = NULL;
1456         GstPad* sinkpad = NULL;
1457         GstPad* srcpad = NULL;
1458         gboolean first_track = FALSE;
1459
1460         enum MainElementID elemId = MMPLAYER_M_NUM;
1461         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1462
1463         /* check handles */
1464         player = (mm_player_t*)data;
1465
1466         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1467         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1468
1469         //LOGD("pad-added signal handling\n");
1470
1471         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1472
1473         /* get mimetype from caps */
1474         caps = gst_pad_query_caps(pad, NULL);
1475         if (!caps) {
1476                 LOGE("cannot get caps from pad.\n");
1477                 goto ERROR;
1478         }
1479
1480         str = gst_caps_get_structure(caps, 0);
1481         if (!str) {
1482                 LOGE("cannot get structure from caps.\n");
1483                 goto ERROR;
1484         }
1485
1486         name = gst_structure_get_name(str);
1487         if (!name) {
1488                 LOGE("cannot get mimetype from structure.\n");
1489                 goto ERROR;
1490         }
1491
1492         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1493         //LOGD("detected mimetype : %s\n", name);
1494
1495         if (strstr(name, "video")) {
1496                 gint stype = 0;
1497
1498                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1499                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1500
1501                 /* don't make video because of not required, and not support multiple track */
1502                 if (stype == MM_DISPLAY_SURFACE_NULL) {
1503                         LOGD("no video sink by null surface");
1504
1505                         gchar *caps_str = gst_caps_to_string(caps);
1506                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1507                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1508                                 player->set_mode.video_zc = TRUE;
1509
1510                         MMPLAYER_FREEIF(caps_str);
1511
1512                         if (player->v_stream_caps) {
1513                                 gst_caps_unref(player->v_stream_caps);
1514                                 player->v_stream_caps = NULL;
1515                         }
1516
1517                         LOGD("create fakesink instead of videobin");
1518
1519                         /* fake sink */
1520                         fakesink = gst_element_factory_make("fakesink", NULL);
1521                         if (fakesink == NULL) {
1522                                 LOGE("ERROR : fakesink create error\n");
1523                                 goto ERROR;
1524                         }
1525
1526                         if (player->ini.set_dump_element_flag)
1527                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
1528
1529                         player->video_fakesink = fakesink;
1530
1531                         /* store it as it's sink element */
1532                         __mmplayer_add_sink(player, player->video_fakesink);
1533
1534                         gst_bin_add(GST_BIN(pipeline), fakesink);
1535
1536                         // link
1537                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
1538
1539                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1540                                 LOGW("failed to link fakesink\n");
1541                                 gst_object_unref(GST_OBJECT(fakesink));
1542                                 goto ERROR;
1543                         }
1544
1545                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
1546                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1547                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
1548                         }
1549
1550                         if (player->set_mode.media_packet_video_stream) {
1551                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
1552
1553                                 MMPLAYER_SIGNAL_CONNECT(player,
1554                                                                                 G_OBJECT(fakesink),
1555                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1556                                                                                 "handoff",
1557                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1558                                                                                 (gpointer)player);
1559
1560                                 MMPLAYER_SIGNAL_CONNECT(player,
1561                                                                                 G_OBJECT(fakesink),
1562                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1563                                                                                 "preroll-handoff",
1564                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1565                                                                                 (gpointer)player);
1566                         }
1567
1568                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
1569                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
1570                         goto DONE;
1571                 }
1572
1573                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1574                         __mmplayer_gst_decode_callback(elem, pad, player);
1575                         goto DONE;
1576                 }
1577
1578                 LOGD("video selector \n");
1579                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
1580                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1581         } else {
1582                 if (strstr(name, "audio")) {
1583                         gint samplerate = 0;
1584                         gint channels = 0;
1585
1586                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1587                                 __mmplayer_gst_decode_callback(elem, pad, player);
1588                                 goto DONE;
1589                         }
1590
1591                         LOGD("audio selector \n");
1592                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
1593                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1594
1595                         gst_structure_get_int(str, "rate", &samplerate);
1596                         gst_structure_get_int(str, "channels", &channels);
1597
1598                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
1599                                 /* fake sink */
1600                                 fakesink = gst_element_factory_make("fakesink", NULL);
1601                                 if (fakesink == NULL) {
1602                                         LOGE("ERROR : fakesink create error\n");
1603                                         goto ERROR;
1604                                 }
1605
1606                                 gst_bin_add(GST_BIN(pipeline), fakesink);
1607
1608                                 /* link */
1609                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1610
1611                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1612                                         LOGW("failed to link fakesink\n");
1613                                         gst_object_unref(GST_OBJECT(fakesink));
1614                                         goto ERROR;
1615                                 }
1616
1617                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1618                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1619
1620                                 goto DONE;
1621                         }
1622                 } else if (strstr(name, "text")) {
1623                         LOGD("text selector \n");
1624                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
1625                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1626                 } else {
1627                         LOGE("wrong elem id \n");
1628                         goto ERROR;
1629                 }
1630         }
1631
1632         selector = player->pipeline->mainbin[elemId].gst;
1633         if (selector == NULL) {
1634                 selector = gst_element_factory_make("input-selector", NULL);
1635                 LOGD("Creating input-selector\n");
1636                 if (selector == NULL) {
1637                         LOGE("ERROR : input-selector create error\n");
1638                         goto ERROR;
1639                 }
1640                 g_object_set(selector, "sync-streams", TRUE, NULL);
1641
1642                 player->pipeline->mainbin[elemId].id = elemId;
1643                 player->pipeline->mainbin[elemId].gst = selector;
1644
1645                 first_track = TRUE;
1646                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
1647
1648                 srcpad = gst_element_get_static_pad(selector, "src");
1649
1650                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1651                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1652                         __mmplayer_gst_selector_blocked, NULL, NULL);
1653                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1654                         __mmplayer_gst_selector_event_probe, player, NULL);
1655
1656                 gst_element_set_state(selector, GST_STATE_PAUSED);
1657                 gst_bin_add(GST_BIN(pipeline), selector);
1658         } else
1659                 LOGD("input-selector is already created.\n");
1660
1661         // link
1662         LOGD("Calling request pad with selector %p \n", selector);
1663         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1664
1665         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
1666
1667         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1668                 LOGW("failed to link selector\n");
1669                 gst_object_unref(GST_OBJECT(selector));
1670                 goto ERROR;
1671         }
1672
1673         if (first_track) {
1674                 LOGD("this is first track --> active track \n");
1675                 g_object_set(selector, "active-pad", sinkpad, NULL);
1676         }
1677
1678         _mmplayer_track_update_info(player, stream_type, sinkpad);
1679
1680
1681 DONE:
1682 ERROR:
1683
1684         if (caps)
1685                 gst_caps_unref(caps);
1686
1687         if (sinkpad) {
1688                 gst_object_unref(GST_OBJECT(sinkpad));
1689                 sinkpad = NULL;
1690         }
1691
1692         if (srcpad) {
1693                 gst_object_unref(GST_OBJECT(srcpad));
1694                 srcpad = NULL;
1695         }
1696
1697         return;
1698 }
1699
1700 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
1701 {
1702         GstPad* srcpad = NULL;
1703         MMHandleType attrs = 0;
1704         gint active_index = 0;
1705
1706         // [link] input-selector :: textbin
1707         srcpad = gst_element_get_static_pad(text_selector, "src");
1708         if (!srcpad) {
1709                 LOGE("failed to get srcpad from selector\n");
1710                 return;
1711         }
1712
1713         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
1714
1715         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
1716         if ((active_index != DEFAULT_TRACK) &&
1717                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
1718                 LOGW("failed to change text track\n");
1719                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
1720         }
1721
1722         player->no_more_pad = TRUE;
1723         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
1724
1725         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1726         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
1727                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
1728                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
1729         }
1730
1731         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1732
1733         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1734                 player->has_closed_caption = TRUE;
1735
1736         attrs = MMPLAYER_GET_ATTRS(player);
1737         if (attrs) {
1738                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1739                 if (mmf_attrs_commit(attrs))
1740                         LOGE("failed to commit.\n");
1741         } else
1742                 LOGE("cannot get content attribute");
1743
1744         if (srcpad) {
1745                 gst_object_unref(GST_OBJECT(srcpad));
1746                 srcpad = NULL;
1747         }
1748 }
1749
1750 static void
1751 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1752 {
1753         mm_player_t* player = (mm_player_t*)data;
1754         GstElement* selector = NULL;
1755         GstElement* queue = NULL;
1756
1757         GstPad* srcpad = NULL;
1758         GstPad* sinkpad = NULL;
1759         GstCaps* caps = NULL;
1760         gchar* caps_str = NULL;
1761
1762         MMPLAYER_FENTER();
1763         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1764
1765         caps = gst_pad_get_current_caps(pad);
1766         caps_str = gst_caps_to_string(caps);
1767         LOGD("deinterleave new caps : %s\n", caps_str);
1768         MMPLAYER_FREEIF(caps_str);
1769         gst_caps_unref(caps);
1770
1771         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
1772                 LOGE("ERROR : queue create error\n");
1773                 goto ERROR;
1774         }
1775
1776         g_object_set(G_OBJECT(queue),
1777                                 "max-size-buffers", 10,
1778                                 "max-size-bytes", 0,
1779                                 "max-size-time", (guint64)0,
1780                                 NULL);
1781
1782         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1783
1784         if (!selector) {
1785                 LOGE("there is no audio channel selector.\n");
1786                 goto ERROR;
1787         }
1788
1789         srcpad = gst_element_get_static_pad(queue, "src");
1790         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1791
1792         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
1793
1794         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1795                 LOGW("failed to link deinterleave - selector\n");
1796                 goto ERROR;
1797         }
1798
1799         gst_element_set_state(queue, GST_STATE_PAUSED);
1800         player->audio_mode.total_track_num++;
1801
1802 ERROR:
1803
1804         if (srcpad) {
1805                 gst_object_unref(GST_OBJECT(srcpad));
1806                 srcpad = NULL;
1807         }
1808
1809         if (sinkpad) {
1810                 gst_object_unref(GST_OBJECT(sinkpad));
1811                 sinkpad = NULL;
1812         }
1813
1814         MMPLAYER_FLEAVE();
1815         return;
1816 }
1817
1818 static void
1819 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
1820 {
1821         mm_player_t* player = NULL;
1822         GstElement* selector = NULL;
1823         GstPad* sinkpad = NULL;
1824         gint active_index = 0;
1825         gchar* change_pad_name = NULL;
1826         GstCaps* caps = NULL;   // no need to unref
1827         gint default_audio_ch = 0;
1828
1829         MMPLAYER_FENTER();
1830         player = (mm_player_t*) data;
1831
1832         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1833
1834         if (!selector) {
1835                 LOGE("there is no audio channel selector.\n");
1836                 goto ERROR;
1837         }
1838
1839         active_index = player->audio_mode.active_pad_index;
1840
1841         if (active_index != default_audio_ch) {
1842                 gint audio_ch = default_audio_ch;
1843
1844                 /*To get the new pad from the selector*/
1845                 change_pad_name = g_strdup_printf("sink%d", active_index);
1846                 if (change_pad_name != NULL) {
1847                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
1848                         if (sinkpad != NULL) {
1849                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
1850                                 g_object_set(selector, "active-pad", sinkpad, NULL);
1851
1852                                 audio_ch = active_index;
1853
1854                                 caps = gst_pad_get_current_caps(sinkpad);
1855                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1856
1857                                 __mmplayer_set_audio_attrs(player, caps);
1858                                 gst_caps_unref(caps);
1859                         }
1860                         MMPLAYER_FREEIF(change_pad_name);
1861                 }
1862
1863                 player->audio_mode.active_pad_index = audio_ch;
1864                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
1865         }
1866
1867 ERROR:
1868
1869         if (sinkpad)
1870                 gst_object_unref(sinkpad);
1871
1872         MMPLAYER_FLEAVE();
1873         return;
1874 }
1875
1876 static void
1877 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
1878 {
1879         mm_player_t* player = NULL;
1880         MMPlayerGstElement *mainbin = NULL;
1881
1882         GstElement* tee = NULL;
1883         GstElement* stereo_queue = NULL;
1884         GstElement* mono_queue = NULL;
1885         GstElement* conv = NULL;
1886         GstElement* filter = NULL;
1887         GstElement* deinterleave = NULL;
1888         GstElement* selector = NULL;
1889
1890         GstPad* srcpad = NULL;
1891         GstPad* selector_srcpad = NULL;
1892         GstPad* sinkpad = NULL;
1893         GstCaps* caps = NULL;
1894         gulong block_id = 0;
1895
1896         MMPLAYER_FENTER();
1897
1898         /* check handles */
1899         player = (mm_player_t*) data;
1900
1901         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1902         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1903
1904         mainbin = player->pipeline->mainbin;
1905
1906         /* tee */
1907         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
1908                 LOGE("ERROR : tee create error\n");
1909                 goto ERROR;
1910         }
1911
1912         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
1913         mainbin[MMPLAYER_M_A_TEE].gst = tee;
1914
1915         gst_element_set_state(tee, GST_STATE_PAUSED);
1916
1917         /* queue */
1918         srcpad = gst_element_get_request_pad(tee, "src_%u");
1919         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1920                 LOGE("ERROR : stereo queue create error\n");
1921                 goto ERROR;
1922         }
1923
1924         g_object_set(G_OBJECT(stereo_queue),
1925                                 "max-size-buffers", 10,
1926                                 "max-size-bytes", 0,
1927                                 "max-size-time", (guint64)0,
1928                                 NULL);
1929
1930         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
1931         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
1932
1933         if (srcpad) {
1934                 gst_object_unref(GST_OBJECT(srcpad));
1935                 srcpad = NULL;
1936         }
1937
1938         srcpad = gst_element_get_request_pad(tee, "src_%u");
1939
1940         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1941                 LOGE("ERROR : mono queue create error\n");
1942                 goto ERROR;
1943         }
1944
1945         g_object_set(G_OBJECT(mono_queue),
1946                                 "max-size-buffers", 10,
1947                                 "max-size-bytes", 0,
1948                                 "max-size-time", (guint64)0,
1949                                 NULL);
1950
1951         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
1952         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
1953
1954         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
1955         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
1956
1957         /* audioconvert */
1958         srcpad = gst_element_get_static_pad(mono_queue, "src");
1959         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
1960                 LOGE("ERROR : audioconvert create error\n");
1961                 goto ERROR;
1962         }
1963
1964         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
1965         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
1966
1967         /* caps filter */
1968         if (srcpad) {
1969                 gst_object_unref(GST_OBJECT(srcpad));
1970                 srcpad = NULL;
1971         }
1972         srcpad = gst_element_get_static_pad(conv, "src");
1973
1974         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
1975                 LOGE("ERROR : capsfilter create error\n");
1976                 goto ERROR;
1977         }
1978
1979         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
1980         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
1981
1982         caps = gst_caps_from_string("audio/x-raw-int, "
1983                                 "width = (int) 16, "
1984                                 "depth = (int) 16, "
1985                                 "channels = (int) 2");
1986
1987         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
1988         gst_caps_unref(caps);
1989
1990         gst_element_set_state(conv, GST_STATE_PAUSED);
1991         gst_element_set_state(filter, GST_STATE_PAUSED);
1992
1993         /* deinterleave */
1994         if (srcpad) {
1995                 gst_object_unref(GST_OBJECT(srcpad));
1996                 srcpad = NULL;
1997         }
1998         srcpad = gst_element_get_static_pad(filter, "src");
1999
2000         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
2001                 LOGE("ERROR : deinterleave create error\n");
2002                 goto ERROR;
2003         }
2004
2005         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
2006
2007         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2008                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
2009
2010         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2011                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
2012
2013         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
2014         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
2015
2016         /* selector */
2017         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
2018         if (selector == NULL) {
2019                 LOGE("ERROR : audio-selector create error\n");
2020                 goto ERROR;
2021         }
2022
2023         g_object_set(selector, "sync-streams", TRUE, NULL);
2024         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
2025
2026         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
2027         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
2028
2029         selector_srcpad = gst_element_get_static_pad(selector, "src");
2030
2031         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
2032         block_id =
2033                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2034                         __mmplayer_gst_selector_blocked, NULL, NULL);
2035
2036         if (srcpad) {
2037                 gst_object_unref(GST_OBJECT(srcpad));
2038                 srcpad = NULL;
2039         }
2040
2041         srcpad = gst_element_get_static_pad(stereo_queue, "src");
2042         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2043
2044         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2045                 LOGW("failed to link queue_stereo - selector\n");
2046                 goto ERROR;
2047         }
2048
2049         player->audio_mode.total_track_num++;
2050
2051         g_object_set(selector, "active-pad", sinkpad, NULL);
2052         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
2053         gst_element_set_state(selector, GST_STATE_PAUSED);
2054
2055         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
2056
2057 ERROR:
2058
2059         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
2060         if (block_id != 0) {
2061                 gst_pad_remove_probe(selector_srcpad, block_id);
2062                 block_id = 0;
2063         }
2064
2065         if (sinkpad) {
2066                 gst_object_unref(GST_OBJECT(sinkpad));
2067                 sinkpad = NULL;
2068         }
2069
2070         if (srcpad) {
2071                 gst_object_unref(GST_OBJECT(srcpad));
2072                 srcpad = NULL;
2073         }
2074
2075         if (selector_srcpad) {
2076                 gst_object_unref(GST_OBJECT(selector_srcpad));
2077                 selector_srcpad = NULL;
2078         }
2079
2080         MMPLAYER_FLEAVE();
2081         return;
2082 }
2083
2084 static void
2085 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
2086 {
2087         mm_player_t* player = NULL;
2088         GstPad* srcpad = NULL;
2089         GstElement* video_selector = NULL;
2090         GstElement* audio_selector = NULL;
2091         GstElement* text_selector = NULL;
2092         MMHandleType attrs = 0;
2093         gint active_index = 0;
2094         gint64 dur_bytes = 0L;
2095
2096         player = (mm_player_t*) data;
2097
2098         LOGD("no-more-pad signal handling\n");
2099
2100         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
2101                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
2102                 LOGW("no need to go more");
2103
2104                 if (player->gapless.reconfigure) {
2105                         player->gapless.reconfigure = FALSE;
2106                         MMPLAYER_PLAYBACK_UNLOCK(player);
2107                 }
2108
2109                 return;
2110         }
2111
2112         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
2113                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
2114                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
2115                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
2116                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
2117
2118                 if (NULL == player->streamer) {
2119                         LOGW("invalid state for buffering");
2120                         goto ERROR;
2121                 }
2122
2123                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
2124                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
2125
2126                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
2127                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
2128
2129                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
2130
2131                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
2132                         LOGE("fail to get duration.\n");
2133
2134                 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
2135                  * use file information was already set on Q2 when it was created. */
2136                 __mm_player_streaming_set_queue2(player->streamer,
2137                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
2138                                                 TRUE,                               /* use_buffering */
2139                                                 buffer_bytes,
2140                                                 init_buffering_time,
2141                                                 1.0,                                /* low percent */
2142                                                 player->ini.http_buffering_limit,   /* high percent */
2143                                                 MUXED_BUFFER_TYPE_MAX,              /* use previous buffer type setting */
2144                                                 NULL,
2145                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
2146         }
2147
2148         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
2149         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
2150         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2151         if (video_selector) {
2152                 // [link] input-selector :: videobin
2153                 srcpad = gst_element_get_static_pad(video_selector, "src");
2154                 if (!srcpad) {
2155                         LOGE("failed to get srcpad from video selector\n");
2156                         goto ERROR;
2157                 }
2158
2159                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
2160                 if (!text_selector && !audio_selector)
2161                         player->no_more_pad = TRUE;
2162
2163                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
2164
2165                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2166                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
2167                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
2168                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
2169                 }
2170         }
2171
2172         if (audio_selector) {
2173                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
2174                 if ((active_index != DEFAULT_TRACK) &&
2175                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
2176                         LOGW("failed to change audio track\n");
2177                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
2178                 }
2179
2180                 // [link] input-selector :: audiobin
2181                 srcpad = gst_element_get_static_pad(audio_selector, "src");
2182                 if (!srcpad) {
2183                         LOGE("failed to get srcpad from selector\n");
2184                         goto ERROR;
2185                 }
2186
2187                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
2188                 if (!text_selector)
2189                         player->no_more_pad = TRUE;
2190
2191                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
2192                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2193                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
2194                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
2195                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
2196                         }
2197
2198                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
2199                 } else {
2200                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
2201
2202                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2203                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
2204                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
2205                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
2206                         }
2207                 }
2208
2209                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
2210
2211                 attrs = MMPLAYER_GET_ATTRS(player);
2212                 if (attrs) {
2213                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
2214                         if (mmf_attrs_commit(attrs))
2215                                 LOGE("failed to commit.\n");
2216                 } else
2217                         LOGE("cannot get content attribute");
2218         } else {
2219                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
2220                         LOGD("There is no audio track : remove audiobin");
2221
2222                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
2223                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
2224
2225                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
2226                         MMPLAYER_FREEIF(player->pipeline->audiobin);
2227                 }
2228
2229                 if (player->num_dynamic_pad == 0)
2230                         __mmplayer_pipeline_complete(NULL, player);
2231         }
2232
2233         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2234                 if (text_selector)
2235                         __mmplayer_handle_text_decode_path(player, text_selector);
2236         }
2237
2238         MMPLAYER_FLEAVE();
2239
2240 ERROR:
2241         if (srcpad) {
2242                 gst_object_unref(GST_OBJECT(srcpad));
2243                 srcpad = NULL;
2244         }
2245
2246         if (player->gapless.reconfigure) {
2247                 player->gapless.reconfigure = FALSE;
2248                 MMPLAYER_PLAYBACK_UNLOCK(player);
2249         }
2250 }
2251
2252 static void
2253 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
2254 {
2255         mm_player_t* player = NULL;
2256         MMHandleType attrs = 0;
2257         GstElement* pipeline = NULL;
2258         GstCaps* caps = NULL;
2259         gchar* caps_str = NULL;
2260         GstStructure* str = NULL;
2261         const gchar* name = NULL;
2262         GstPad* sinkpad = NULL;
2263         GstElement* sinkbin = NULL;
2264         gboolean reusing = FALSE;
2265         GstElement *text_selector = NULL;
2266
2267         /* check handles */
2268         player = (mm_player_t*) data;
2269
2270         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2271         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2272
2273         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2274
2275         attrs = MMPLAYER_GET_ATTRS(player);
2276         if (!attrs) {
2277                 LOGE("cannot get content attribute\n");
2278                 goto ERROR;
2279         }
2280
2281         /* get mimetype from caps */
2282         caps = gst_pad_query_caps(pad, NULL);
2283         if (!caps) {
2284                 LOGE("cannot get caps from pad.\n");
2285                 goto ERROR;
2286         }
2287         caps_str = gst_caps_to_string(caps);
2288
2289         str = gst_caps_get_structure(caps, 0);
2290         if (!str) {
2291                 LOGE("cannot get structure from caps.\n");
2292                 goto ERROR;
2293         }
2294
2295         name = gst_structure_get_name(str);
2296         if (!name) {
2297                 LOGE("cannot get mimetype from structure.\n");
2298                 goto ERROR;
2299         }
2300
2301         //LOGD("detected mimetype : %s\n", name);
2302
2303         if (strstr(name, "audio")) {
2304                 if (player->pipeline->audiobin == NULL) {
2305                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
2306                                 LOGE("failed to create audiobin. continuing without audio\n");
2307                                 goto ERROR;
2308                         }
2309
2310                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2311                         LOGD("creating audiosink bin success\n");
2312                 } else {
2313                         reusing = TRUE;
2314                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2315                         LOGD("reusing audiobin\n");
2316                         __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2317                 }
2318
2319                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
2320                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2321
2322                 player->audiosink_linked  = 1;
2323
2324                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2325                 if (!sinkpad) {
2326                         LOGE("failed to get pad from sinkbin\n");
2327                         goto ERROR;
2328                 }
2329         } else if (strstr(name, "video")) {
2330                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2331                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2332                         player->set_mode.video_zc = TRUE;
2333
2334                 if (player->pipeline->videobin == NULL) {
2335                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
2336                         /* get video surface type */
2337                         int surface_type = 0;
2338                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2339                         LOGD("display_surface_type(%d)\n", surface_type);
2340
2341                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
2342                                 LOGD("not make videobin because it dose not want\n");
2343                                 goto ERROR;
2344                         }
2345
2346                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
2347                                 /* mark video overlay for acquire */
2348                                 if (player->video_overlay_resource == NULL) {
2349                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
2350                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2351                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2352                                                         &player->video_overlay_resource)
2353                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
2354                                                 LOGE("could not mark video_overlay resource for acquire\n");
2355                                                 goto ERROR;
2356                                         }
2357                                 }
2358                         }
2359
2360                         player->interrupted_by_resource = FALSE;
2361                         /* acquire resources for video overlay */
2362                         if (mm_resource_manager_commit(player->resource_manager) !=
2363                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
2364                                 LOGE("could not acquire resources for video playing\n");
2365                                 goto ERROR;
2366                         }
2367
2368                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
2369                                 LOGE("failed to create videobin. continuing without video\n");
2370                                 goto ERROR;
2371                         }
2372
2373                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2374                         LOGD("creating videosink bin success\n");
2375                 } else {
2376                         reusing = TRUE;
2377                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2378                         LOGD("re-using videobin\n");
2379                         __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2380                 }
2381
2382                 player->videosink_linked  = 1;
2383
2384                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2385                 if (!sinkpad) {
2386                         LOGE("failed to get pad from sinkbin\n");
2387                         goto ERROR;
2388                 }
2389         } else if (strstr(name, "text")) {
2390                 if (player->pipeline->textbin == NULL) {
2391                         MMPlayerGstElement* mainbin = NULL;
2392
2393                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
2394                                 LOGE("failed to create text sink bin. continuing without text\n");
2395                                 goto ERROR;
2396                         }
2397
2398                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2399                         LOGD("creating textsink bin success\n");
2400
2401                         /* FIXIT : track number shouldn't be hardcoded */
2402                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2403
2404                         player->textsink_linked  = 1;
2405                         LOGI("player->textsink_linked set to 1\n");
2406
2407                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
2408                         if (!sinkpad) {
2409                                 LOGE("failed to get pad from sinkbin\n");
2410                                 goto ERROR;
2411                         }
2412
2413                         mainbin = player->pipeline->mainbin;
2414
2415                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
2416                                 /* input selector */
2417                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
2418                                 if (!text_selector) {
2419                                         LOGE("failed to create subtitle input selector element\n");
2420                                         goto ERROR;
2421                                 }
2422                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
2423
2424                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
2425                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
2426
2427                                 /* warm up */
2428                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
2429                                         LOGE("failed to set state(READY) to sinkbin\n");
2430                                         goto ERROR;
2431                                 }
2432
2433                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
2434                                         LOGW("failed to add subtitle input selector\n");
2435                                         goto ERROR;
2436                                 }
2437
2438                                 LOGD("created element input-selector");
2439
2440                         } else {
2441                                 LOGD("already having subtitle input selector");
2442                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2443                         }
2444                 } else {
2445                         if (!player->textsink_linked) {
2446                                 LOGD("re-using textbin\n");
2447
2448                                 reusing = TRUE;
2449                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2450
2451                                 player->textsink_linked  = 1;
2452                                 LOGI("player->textsink_linked set to 1\n");
2453                         } else
2454                                 LOGD("ignoring internal subtutle since external subtitle is available");
2455                 }
2456         } else {
2457                 LOGW("unknown type of elementary stream!ignoring it...\n");
2458                 goto ERROR;
2459         }
2460
2461         if (sinkbin) {
2462                 if (!reusing) {
2463                         /* warm up */
2464                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
2465                                 LOGE("failed to set state(READY) to sinkbin\n");
2466                                 goto ERROR;
2467                         }
2468
2469                         /* Added for multi audio support to avoid adding audio bin again*/
2470                         /* add */
2471                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
2472                                 LOGE("failed to add sinkbin to pipeline\n");
2473                                 goto ERROR;
2474                         }
2475                 }
2476
2477                 /* link */
2478                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2479                         LOGE("failed to get pad from sinkbin\n");
2480                         goto ERROR;
2481                 }
2482
2483                 if (!reusing) {
2484                         /* run */
2485                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
2486                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
2487                                 goto ERROR;
2488                         }
2489
2490                         if (text_selector) {
2491                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
2492                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
2493                                         goto ERROR;
2494                                 }
2495                         }
2496                 }
2497
2498                 gst_object_unref(sinkpad);
2499                 sinkpad = NULL;
2500         }
2501
2502         LOGD("[handle: %p] linking sink bin success", player);
2503
2504         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2505          * streaming task. if the task blocked, then buffer will not flow to the next element
2506          *(autoplugging element). so this is special hack for streaming. please try to remove it
2507          */
2508         /* dec stream count. we can remove fakesink if it's zero */
2509         if (player->num_dynamic_pad)
2510                 player->num_dynamic_pad--;
2511
2512         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
2513
2514         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
2515                 __mmplayer_pipeline_complete(NULL, player);
2516
2517 ERROR:
2518
2519         MMPLAYER_FREEIF(caps_str);
2520
2521         if (caps)
2522                 gst_caps_unref(caps);
2523
2524         if (sinkpad)
2525                 gst_object_unref(GST_OBJECT(sinkpad));
2526
2527         /* flusing out new attributes */
2528         if (mmf_attrs_commit(attrs))
2529                 LOGE("failed to comit attributes\n");
2530
2531         return;
2532 }
2533
2534 static gboolean
2535 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
2536 {
2537         int pro_value = 0; // in the case of expection, default will be returned.
2538         int dest_angle = rotation_angle;
2539         int rotation_type = -1;
2540
2541         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2542         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
2543         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
2544
2545         if (rotation_angle >= 360)
2546                 dest_angle = rotation_angle - 360;
2547
2548         /* chech if supported or not */
2549         if (dest_angle % 90) {
2550                 LOGD("not supported rotation angle = %d", rotation_angle);
2551                 return FALSE;
2552         }
2553
2554         /*
2555           * tizenwlsink (A)
2556           * custom_convert - none (B)
2557           * videoflip - none (C)
2558           */
2559         if (player->set_mode.video_zc) {
2560                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
2561                         rotation_type = ROTATION_USING_CUSTOM;
2562                 else // A
2563                         rotation_type = ROTATION_USING_SINK;
2564         } else {
2565                 int surface_type = 0;
2566                 rotation_type = ROTATION_USING_FLIP;
2567
2568                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2569                 LOGD("check display surface type attribute: %d", surface_type);
2570
2571                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
2572                         rotation_type = ROTATION_USING_SINK;
2573                 else
2574                         rotation_type = ROTATION_USING_FLIP; //C
2575
2576                 LOGD("using %d type for rotation", rotation_type);
2577         }
2578
2579         /* get property value for setting */
2580         switch (rotation_type) {
2581         case ROTATION_USING_SINK: // tizenwlsink
2582                 {
2583                         switch (dest_angle) {
2584                         case 0:
2585                                 break;
2586                         case 90:
2587                                 pro_value = 3; // clockwise 90
2588                                 break;
2589                         case 180:
2590                                 pro_value = 2;
2591                                 break;
2592                         case 270:
2593                                 pro_value = 1; // counter-clockwise 90
2594                                 break;
2595                         }
2596                 }
2597                 break;
2598         case ROTATION_USING_CUSTOM:
2599                 {
2600                         gchar *ename = NULL;
2601                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
2602
2603                         if (g_strrstr(ename, "fimcconvert")) {
2604                                 switch (dest_angle) {
2605                                 case 0:
2606                                         break;
2607                                 case 90:
2608                                         pro_value = 90; // clockwise 90
2609                                         break;
2610                                 case 180:
2611                                         pro_value = 180;
2612                                         break;
2613                                 case 270:
2614                                         pro_value = 270; // counter-clockwise 90
2615                                         break;
2616                                 }
2617                         }
2618                 }
2619                 break;
2620         case ROTATION_USING_FLIP: // videoflip
2621                 {
2622                                 switch (dest_angle) {
2623                                 case 0:
2624                                         break;
2625                                 case 90:
2626                                         pro_value = 1; // clockwise 90
2627                                         break;
2628                                 case 180:
2629                                         pro_value = 2;
2630                                         break;
2631                                 case 270:
2632                                         pro_value = 3; // counter-clockwise 90
2633                                         break;
2634                                 }
2635                 }
2636                 break;
2637         }
2638
2639         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
2640
2641         *value = pro_value;
2642
2643         return TRUE;
2644 }
2645
2646 int
2647 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
2648 {
2649         /* check video sinkbin is created */
2650         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2651                 player->pipeline &&
2652                 player->pipeline->videobin &&
2653                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2654                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2655                 MM_ERROR_PLAYER_NOT_INITIALIZED);
2656
2657         return MM_ERROR_NONE;
2658 }
2659
2660 int
2661 __mmplayer_get_video_angle(mm_player_t* player, int *user_angle, int *org_angle)
2662 {
2663         int user_angle_type = 0;
2664         gchar *org_orient = NULL;
2665         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
2666
2667         if (!attrs) {
2668                 LOGE("cannot get content attribute");
2669                 return MM_ERROR_PLAYER_INTERNAL;
2670         }
2671
2672         if (user_angle) {
2673                 /* update user roation */
2674                 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
2675
2676                 /* get angle with user type */
2677                 switch (user_angle_type) {
2678                 case MM_DISPLAY_ROTATION_NONE:
2679                         *user_angle = 0;
2680                         break;
2681                 case MM_DISPLAY_ROTATION_90: /* counter-clockwise 90 */
2682                         *user_angle = 270;
2683                         break;
2684                 case MM_DISPLAY_ROTATION_180:
2685                         *user_angle = 180;
2686                         break;
2687                 case MM_DISPLAY_ROTATION_270: /* clockwise 90 */
2688                         *user_angle = 90;
2689                         break;
2690                 default:
2691                         LOGW("wrong angle type : %d", user_angle_type);
2692                         break;
2693                 }
2694                 LOGD("check user angle: %d", *user_angle);
2695         }
2696
2697         if (org_angle) {
2698                 /* get original orientation */
2699                 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2700
2701                 if (org_orient) {
2702                         if (!strcmp(org_orient, "rotate-90"))
2703                                 *org_angle = 90;
2704                         else if (!strcmp(org_orient, "rotate-180"))
2705                                 *org_angle = 180;
2706                         else if (!strcmp(org_orient, "rotate-270"))
2707                                 *org_angle = 270;
2708                         else
2709                                 LOGD("original rotation is %s", org_orient);
2710                 } else {
2711                         LOGD("content_video_orientation get fail");
2712                 }
2713
2714                 LOGD("check orientation: %d", *org_angle);
2715         }
2716
2717         return MM_ERROR_NONE;
2718 }
2719
2720 void
2721 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
2722 {
2723         int rotation_value = 0;
2724         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
2725         int user_angle = 0;
2726         MMPLAYER_FENTER();
2727
2728         /* check video sinkbin is created */
2729         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2730                 return;
2731
2732         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
2733
2734         /* get rotation value to set */
2735         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
2736         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2737         LOGD("set video param : rotate %d", rotation_value);
2738 }
2739
2740 void
2741 __mmplayer_video_param_set_display_visible(mm_player_t* player)
2742 {
2743         MMHandleType attrs = 0;
2744         int visible = 0;
2745         MMPLAYER_FENTER();
2746
2747         /* check video sinkbin is created */
2748         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2749                 return;
2750
2751         attrs = MMPLAYER_GET_ATTRS(player);
2752         MMPLAYER_RETURN_IF_FAIL(attrs);
2753
2754         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2755         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2756         LOGD("set video param : visible %d", visible);
2757 }
2758
2759 void
2760 __mmplayer_video_param_set_display_method(mm_player_t* player)
2761 {
2762         MMHandleType attrs = 0;
2763         int display_method = 0;
2764         MMPLAYER_FENTER();
2765
2766         /* check video sinkbin is created */
2767         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2768                 return;
2769
2770         attrs = MMPLAYER_GET_ATTRS(player);
2771         MMPLAYER_RETURN_IF_FAIL(attrs);
2772
2773         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2774         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2775         LOGD("set video param : method %d", display_method);
2776 }
2777
2778 void
2779 __mmplayer_video_param_set_roi_area(mm_player_t* player)
2780 {
2781         MMHandleType attrs = 0;
2782         void *handle = NULL;
2783         /*set wl_display*/
2784         int win_roi_x = 0;
2785         int win_roi_y = 0;
2786         int win_roi_width = 0;
2787         int win_roi_height = 0;
2788         MMPLAYER_FENTER();
2789
2790         /* check video sinkbin is created */
2791         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2792                 return;
2793
2794         attrs = MMPLAYER_GET_ATTRS(player);
2795         MMPLAYER_RETURN_IF_FAIL(attrs);
2796
2797         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2798
2799         if (handle) {
2800                 /* It should be set after setting window */
2801                 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2802                 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2803                 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2804                 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2805
2806                 /* After setting window handle, set display roi area */
2807                 gst_video_overlay_set_display_roi_area(
2808                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2809                          win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2810                 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2811                         win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2812
2813         }
2814 }
2815 void
2816 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
2817 {
2818         MMHandleType attrs = 0;
2819         void *handle = NULL;
2820
2821         /* check video sinkbin is created */
2822         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2823                 return;
2824
2825         attrs = MMPLAYER_GET_ATTRS(player);
2826         MMPLAYER_RETURN_IF_FAIL(attrs);
2827
2828         /* common case if using overlay surface */
2829         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2830
2831         if (handle) {
2832                 /* default is using wl_surface_id */
2833                 unsigned int wl_surface_id      = 0;
2834                 wl_surface_id = *(int*)handle;
2835                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2836                 gst_video_overlay_set_wl_window_wl_surface_id(
2837                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2838                                 *(int*)handle);
2839         } else
2840                 /* FIXIT : is it error case? */
2841                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2842 }
2843
2844
2845 int
2846 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2847 {
2848         bool update_all_param = FALSE;
2849         MMPLAYER_FENTER();
2850
2851         /* check video sinkbin is created */
2852         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2853                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2854
2855         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2856                 LOGE("can not find tizenwlsink");
2857                 return MM_ERROR_PLAYER_INTERNAL;
2858         }
2859
2860         LOGD("param_name : %s", param_name);
2861         if (!g_strcmp0(param_name, "update_all_param"))
2862                 update_all_param = TRUE;
2863
2864         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2865                 __mmplayer_video_param_set_display_overlay(player);
2866         if (update_all_param || !g_strcmp0(param_name, "display_method"))
2867                 __mmplayer_video_param_set_display_method(player);
2868         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2869                 __mmplayer_video_param_set_display_visible(player);
2870         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2871                 __mmplayer_video_param_set_display_rotation(player);
2872         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2873                 __mmplayer_video_param_set_roi_area(player);
2874
2875         return MM_ERROR_NONE;
2876 }
2877
2878 int
2879 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2880 {
2881         MMHandleType attrs = 0;
2882         int surface_type = 0;
2883         int ret = MM_ERROR_NONE;
2884
2885         MMPLAYER_FENTER();
2886
2887         /* check video sinkbin is created */
2888         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2889                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2890
2891         attrs = MMPLAYER_GET_ATTRS(player);
2892         if (!attrs) {
2893                 LOGE("cannot get content attribute");
2894                 return MM_ERROR_PLAYER_INTERNAL;
2895         }
2896         LOGD("param_name : %s", param_name);
2897
2898         /* update display surface */
2899         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2900         LOGD("check display surface type attribute: %d", surface_type);
2901
2902         /* configuring display */
2903         switch (surface_type) {
2904         case MM_DISPLAY_SURFACE_OVERLAY:
2905                 {
2906                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2907                         if (ret != MM_ERROR_NONE)
2908                                 return ret;
2909                 }
2910                 break;
2911         }
2912
2913         MMPLAYER_FLEAVE();
2914
2915         return MM_ERROR_NONE;
2916 }
2917
2918 int
2919 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2920 {
2921         gboolean disable_overlay = FALSE;
2922         mm_player_t* player = (mm_player_t*) hplayer;
2923         int ret = MM_ERROR_NONE;
2924
2925         MMPLAYER_FENTER();
2926         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2927         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2928                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2929                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2930
2931         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2932                 LOGW("Display control is not supported");
2933                 return MM_ERROR_PLAYER_INTERNAL;
2934         }
2935
2936         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2937
2938         if (audio_only == (bool)disable_overlay) {
2939                 LOGE("It's the same with current setting: (%d)", audio_only);
2940                 return MM_ERROR_NONE;
2941         }
2942
2943         if (audio_only) {
2944                 LOGE("disable overlay");
2945                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2946
2947                 /* release overlay resource */
2948                 if (player->video_overlay_resource != NULL) {
2949                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
2950                                         player->video_overlay_resource);
2951                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2952                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2953                                 goto ERROR;
2954                         }
2955                         player->video_overlay_resource = NULL;
2956                 }
2957
2958                 ret = mm_resource_manager_commit(player->resource_manager);
2959                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2960                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2961                         goto ERROR;
2962                 }
2963         } else {
2964                 /* mark video overlay for acquire */
2965                 if (player->video_overlay_resource == NULL) {
2966                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2967                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2968                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2969                                         &player->video_overlay_resource);
2970                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2971                                 LOGE("could not prepare for video_overlay resource\n");
2972                                 goto ERROR;
2973                         }
2974                 }
2975
2976                 player->interrupted_by_resource = FALSE;
2977                 /* acquire resources for video overlay */
2978                 ret = mm_resource_manager_commit(player->resource_manager);
2979                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2980                         LOGE("could not acquire resources for video playing\n");
2981                         goto ERROR;
2982                 }
2983
2984                 LOGD("enable overlay");
2985                 __mmplayer_video_param_set_display_overlay(player);
2986                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2987         }
2988
2989 ERROR:
2990         MMPLAYER_FLEAVE();
2991         return MM_ERROR_NONE;
2992 }
2993
2994 int
2995 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2996 {
2997         mm_player_t* player = (mm_player_t*) hplayer;
2998         gboolean disable_overlay = FALSE;
2999
3000         MMPLAYER_FENTER();
3001
3002         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3003         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3004         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3005                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3006                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3007
3008         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3009                 LOGW("Display control is not supported");
3010                 return MM_ERROR_PLAYER_INTERNAL;
3011         }
3012
3013         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3014
3015         *paudio_only = (bool)(disable_overlay);
3016
3017         LOGD("audio_only : %d", *paudio_only);
3018
3019         MMPLAYER_FLEAVE();
3020
3021         return MM_ERROR_NONE;
3022 }
3023
3024 static int
3025 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3026 {
3027         GList* bucket = element_bucket;
3028         MMPlayerGstElement* element = NULL;
3029         MMPlayerGstElement* prv_element = NULL;
3030         gint successful_link_count = 0;
3031
3032         MMPLAYER_FENTER();
3033
3034         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3035
3036         prv_element = (MMPlayerGstElement*)bucket->data;
3037         bucket = bucket->next;
3038
3039         for (; bucket; bucket = bucket->next) {
3040                 element = (MMPlayerGstElement*)bucket->data;
3041
3042                 if (element && element->gst) {
3043                         /* If next element is audio appsrc then make a separate audio pipeline */
3044                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
3045                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
3046                                 prv_element = element;
3047                                 continue;
3048                         }
3049
3050                         if (prv_element && prv_element->gst) {
3051                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
3052                                         LOGD("linking [%s] to [%s] success\n",
3053                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3054                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
3055                                         successful_link_count++;
3056                                 } else {
3057                                         LOGD("linking [%s] to [%s] failed\n",
3058                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3059                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
3060                                         return -1;
3061                                 }
3062                         }
3063                 }
3064
3065                 prv_element = element;
3066         }
3067
3068         MMPLAYER_FLEAVE();
3069
3070         return successful_link_count;
3071 }
3072
3073 static int
3074 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
3075 {
3076         GList* bucket = element_bucket;
3077         MMPlayerGstElement* element = NULL;
3078         int successful_add_count = 0;
3079
3080         MMPLAYER_FENTER();
3081
3082         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
3083         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
3084
3085         for (; bucket; bucket = bucket->next) {
3086                 element = (MMPlayerGstElement*)bucket->data;
3087
3088                 if (element && element->gst) {
3089                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
3090                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
3091                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
3092                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
3093                                 return 0;
3094                         }
3095                         successful_add_count++;
3096                 }
3097         }
3098
3099         MMPLAYER_FLEAVE();
3100
3101         return successful_add_count;
3102 }
3103
3104 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
3105 {
3106         mm_player_t* player = (mm_player_t*) data;
3107         GstCaps *caps = NULL;
3108         GstStructure *str = NULL;
3109         const char *name;
3110
3111         MMPLAYER_FENTER();
3112
3113         MMPLAYER_RETURN_IF_FAIL(pad)
3114         MMPLAYER_RETURN_IF_FAIL(unused)
3115         MMPLAYER_RETURN_IF_FAIL(data)
3116
3117         caps = gst_pad_get_current_caps(pad);
3118         if (!caps)
3119                 return;
3120
3121         str = gst_caps_get_structure(caps, 0);
3122         if (!str)
3123                 goto ERROR;
3124
3125         name = gst_structure_get_name(str);
3126         if (!name)
3127                 goto ERROR;
3128
3129         LOGD("name = %s\n", name);
3130
3131         if (strstr(name, "audio")) {
3132                 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
3133
3134                 if (player->audio_stream_changed_cb) {
3135                         LOGE("call the audio stream changed cb\n");
3136                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
3137                 }
3138         } else if (strstr(name, "video")) {
3139                 if ((name = gst_structure_get_string(str, "format")))
3140                         player->set_mode.video_zc = name[0] == 'S';
3141
3142                 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
3143
3144                 if (player->video_stream_changed_cb) {
3145                         LOGE("call the video stream changed cb\n");
3146                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
3147                 }
3148         } else
3149                 goto ERROR;
3150
3151 ERROR:
3152
3153         gst_caps_unref(caps);
3154
3155         MMPLAYER_FLEAVE();
3156
3157         return;
3158 }
3159
3160
3161
3162 /**
3163  * This function is to create audio pipeline for playing.
3164  *
3165  * @param       player          [in]    handle of player
3166  *
3167  * @return      This function returns zero on success.
3168  * @remark
3169  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
3170  */
3171 /* macro for code readability. just for sinkbin-creation functions */
3172 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
3173 do {\
3174         x_bin[x_id].id = x_id;\
3175         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
3176         if (!x_bin[x_id].gst) {\
3177                 LOGE("failed to create %s \n", x_factory);\
3178                 goto ERROR;\
3179         } else {\
3180                 if (x_player->ini.set_dump_element_flag)\
3181                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
3182         } \
3183         if (x_add_bucket)\
3184                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
3185 } while (0);
3186
3187 void
3188 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
3189 {
3190         GList *l = NULL;
3191
3192         MMPLAYER_FENTER();
3193         MMPLAYER_RETURN_IF_FAIL(player);
3194
3195         if (player->audio_stream_buff_list) {
3196                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
3197                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
3198                         if (tmp) {
3199                                 if (send_all) {
3200                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
3201                                         __mmplayer_audio_stream_send_data(player, tmp);
3202                                 }
3203                                 if (tmp->pcm_data)
3204                                         g_free(tmp->pcm_data);
3205                                 g_free(tmp);
3206                         }
3207                 }
3208                 g_list_free(player->audio_stream_buff_list);
3209                 player->audio_stream_buff_list = NULL;
3210         }
3211
3212         MMPLAYER_FLEAVE();
3213 }
3214
3215 static void
3216 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
3217 {
3218         MMPlayerAudioStreamDataType audio_stream = { 0, };
3219
3220         MMPLAYER_FENTER();
3221         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
3222
3223         audio_stream.bitrate = a_buffer->bitrate;
3224         audio_stream.channel = a_buffer->channel;
3225         audio_stream.depth = a_buffer->depth;
3226         audio_stream.is_little_endian = a_buffer->is_little_endian;
3227         audio_stream.channel_mask = a_buffer->channel_mask;
3228         audio_stream.data_size = a_buffer->data_size;
3229         audio_stream.data = a_buffer->pcm_data;
3230
3231         /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
3232         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
3233
3234         MMPLAYER_FLEAVE();
3235 }
3236
3237 static void
3238 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3239 {
3240         mm_player_t* player = (mm_player_t*) data;
3241
3242         gint channel = 0;
3243         gint rate = 0;
3244         gint depth = 0;
3245         gint endianness = 0;
3246         guint64 channel_mask = 0;
3247         void *a_data = NULL;
3248         gint a_size = 0;
3249         mm_player_audio_stream_buff_t *a_buffer = NULL;
3250         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3251         GList *l = NULL;
3252
3253         MMPLAYER_FENTER();
3254         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
3255
3256         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3257         a_data = mapinfo.data;
3258         a_size = mapinfo.size;
3259
3260         GstCaps *caps = gst_pad_get_current_caps(pad);
3261         GstStructure *structure = gst_caps_get_structure(caps, 0);
3262
3263         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
3264         gst_structure_get_int(structure, "rate", &rate);
3265         gst_structure_get_int(structure, "channels", &channel);
3266         gst_structure_get_int(structure, "depth", &depth);
3267         gst_structure_get_int(structure, "endianness", &endianness);
3268         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
3269         gst_caps_unref(GST_CAPS(caps));
3270
3271         /* In case of the sync is false, use buffer list.              *
3272          * The num of buffer list depends on the num of audio channels */
3273         if (player->audio_stream_buff_list) {
3274                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
3275                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
3276                         if (tmp) {
3277                                 if (channel_mask == tmp->channel_mask) {
3278                                         /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
3279                                         if (tmp->data_size + a_size < tmp->buff_size) {
3280                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
3281                                                 tmp->data_size += a_size;
3282                                         } else {
3283                                                 /* send data to client */
3284                                                 __mmplayer_audio_stream_send_data(player, tmp);
3285
3286                                                 if (a_size > tmp->buff_size) {
3287                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
3288                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
3289                                                         if (tmp->pcm_data == NULL) {
3290                                                                 LOGE("failed to realloc data.");
3291                                                                 goto DONE;
3292                                                         }
3293                                                         tmp->buff_size = a_size;
3294                                                 }
3295                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
3296                                                 memcpy(tmp->pcm_data, a_data, a_size);
3297                                                 tmp->data_size = a_size;
3298                                         }
3299                                         goto DONE;
3300                                 }
3301                         } else {
3302                                 LOGE("data is empty in list.");
3303                                 goto DONE;
3304                         }
3305                 }
3306         }
3307
3308         /* create new audio stream data */
3309         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
3310         if (a_buffer == NULL) {
3311                 LOGE("failed to alloc data.");
3312                 goto DONE;
3313         }
3314         a_buffer->bitrate = rate;
3315         a_buffer->channel = channel;
3316         a_buffer->depth = depth;
3317         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
3318         a_buffer->channel_mask = channel_mask;
3319         a_buffer->data_size = a_size;
3320
3321         if (!player->audio_stream_sink_sync) {
3322                 /* If sync is FALSE, use buffer list to reduce the IPC. */
3323                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
3324                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
3325                 if (a_buffer->pcm_data == NULL) {
3326                         LOGE("failed to alloc data.");
3327                         g_free(a_buffer);
3328                         goto DONE;
3329                 }
3330                 memcpy(a_buffer->pcm_data, a_data, a_size);
3331                 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
3332                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
3333         } else {
3334                 /* If sync is TRUE, send data directly. */
3335                 a_buffer->pcm_data = a_data;
3336                 __mmplayer_audio_stream_send_data(player, a_buffer);
3337                 g_free(a_buffer);
3338         }
3339
3340 DONE:
3341         gst_buffer_unmap(buffer, &mapinfo);
3342         MMPLAYER_FLEAVE();
3343 }
3344
3345 static void
3346 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3347 {
3348         mm_player_t* player = (mm_player_t*)data;
3349         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
3350         GstPad* sinkpad = NULL;
3351         GstElement *queue = NULL, *sink = NULL;
3352
3353         MMPLAYER_FENTER();
3354         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3355
3356         queue = gst_element_factory_make("queue", NULL);
3357         if (queue == NULL) {
3358                 LOGD("fail make queue\n");
3359                 goto ERROR;
3360         }
3361
3362         sink = gst_element_factory_make("fakesink", NULL);
3363         if (sink == NULL) {
3364                 LOGD("fail make fakesink\n");
3365                 goto ERROR;
3366         }
3367
3368         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
3369
3370         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
3371                 LOGW("failed to link queue & sink\n");
3372                 goto ERROR;
3373         }
3374
3375         sinkpad = gst_element_get_static_pad(queue, "sink");
3376
3377         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3378                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
3379                 goto ERROR;
3380         }
3381
3382         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
3383
3384         gst_object_unref(sinkpad);
3385         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
3386         g_object_set(sink, "signal-handoffs", TRUE, NULL);
3387
3388         gst_element_set_state(sink, GST_STATE_PAUSED);
3389         gst_element_set_state(queue, GST_STATE_PAUSED);
3390
3391         MMPLAYER_SIGNAL_CONNECT(player,
3392                 G_OBJECT(sink),
3393                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3394                 "handoff",
3395                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3396                 (gpointer)player);
3397
3398         MMPLAYER_FLEAVE();
3399         return;
3400
3401 ERROR:
3402         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
3403         if (queue) {
3404                 gst_object_unref(GST_OBJECT(queue));
3405                 queue = NULL;
3406         }
3407         if (sink) {
3408                 gst_object_unref(GST_OBJECT(sink));
3409                 sink = NULL;
3410         }
3411         if (sinkpad) {
3412                 gst_object_unref(GST_OBJECT(sinkpad));
3413                 sinkpad = NULL;
3414         }
3415
3416         return;
3417 }
3418
3419 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
3420 {
3421         #define MAX_PROPS_LEN 128
3422         gint latency_mode = 0;
3423         gchar *stream_type = NULL;
3424         gchar *latency = NULL;
3425         gint stream_id = 0;
3426         gchar stream_props[MAX_PROPS_LEN] = {0,};
3427         GstStructure *props = NULL;
3428
3429         /* set volume table
3430          * It should be set after player creation through attribute.
3431          * But, it can not be changed during playing.
3432          */
3433         MMPLAYER_FENTER();
3434         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
3435         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
3436
3437         if (!stream_type) {
3438                 LOGE("stream_type is null.\n");
3439         } else {
3440                 if (player->sound.focus_id)
3441                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
3442                                         stream_type, stream_id, player->sound.focus_id);
3443                 else
3444                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
3445                                         stream_type, stream_id);
3446                 props = gst_structure_from_string(stream_props, NULL);
3447                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
3448                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
3449                         stream_type, stream_id, player->sound.focus_id, stream_props);
3450                 gst_structure_free(props);
3451         }
3452
3453         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
3454
3455         switch (latency_mode) {
3456         case AUDIO_LATENCY_MODE_LOW:
3457                 latency = g_strndup("low", 3);
3458                 break;
3459         case AUDIO_LATENCY_MODE_MID:
3460                 latency = g_strndup("mid", 3);
3461                 break;
3462         case AUDIO_LATENCY_MODE_HIGH:
3463                 latency = g_strndup("high", 4);
3464                 break;
3465         };
3466
3467         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
3468                         "latency", latency,
3469                         NULL);
3470
3471         LOGD("audiosink property - latency=%s \n", latency);
3472
3473         g_free(latency);
3474
3475         MMPLAYER_FLEAVE();
3476 }
3477
3478 static int
3479 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
3480 {
3481         MMPlayerGstElement* first_element = NULL;
3482         MMPlayerGstElement* audiobin = NULL;
3483         MMHandleType attrs = 0;
3484         GstPad *pad = NULL;
3485         GstPad *ghostpad = NULL;
3486         GList* element_bucket = NULL;
3487         gboolean link_audio_sink_now = TRUE;
3488         int i = 0;
3489         GstCaps *acaps;
3490
3491         MMPLAYER_FENTER();
3492
3493         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3494
3495         /* alloc handles */
3496         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3497         if (!audiobin) {
3498                 LOGE("failed to allocate memory for audiobin\n");
3499                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3500         }
3501
3502         attrs = MMPLAYER_GET_ATTRS(player);
3503
3504         /* create bin */
3505         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3506         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3507         if (!audiobin[MMPLAYER_A_BIN].gst) {
3508                 LOGE("failed to create audiobin\n");
3509                 goto ERROR;
3510         }
3511
3512         /* take it */
3513         player->pipeline->audiobin = audiobin;
3514
3515         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
3516
3517         /* Adding audiotp plugin for reverse trickplay feature */
3518 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
3519
3520         /* converter */
3521         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
3522
3523         /* replaygain volume */
3524         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
3525         if (player->sound.rg_enable)
3526                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
3527         else
3528                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
3529
3530         /* resampler */
3531         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
3532
3533         if (player->set_mode.pcm_extraction) {
3534                 // pcm extraction only and no sound output
3535                 if (player->audio_stream_render_cb_ex) {
3536                         char *caps_str = NULL;
3537                         GstCaps* caps = NULL;
3538                         gchar *format = NULL;
3539
3540                         /* capsfilter */
3541                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3542
3543                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
3544
3545                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
3546
3547                         caps = gst_caps_new_simple("audio/x-raw",
3548                                         "format", G_TYPE_STRING, format,
3549                                         "rate", G_TYPE_INT, player->pcm_samplerate,
3550                                         "channels", G_TYPE_INT, player->pcm_channel,
3551                                         NULL);
3552                         caps_str = gst_caps_to_string(caps);
3553                         LOGD("new caps : %s\n", caps_str);
3554
3555                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3556
3557                         /* clean */
3558                         gst_caps_unref(caps);
3559                         MMPLAYER_FREEIF(caps_str);
3560
3561                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
3562
3563                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3564                         /* raw pad handling signal */
3565                         MMPLAYER_SIGNAL_CONNECT(player,
3566                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
3567                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3568                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
3569                 } else {
3570                         int dst_samplerate = 0;
3571                         int dst_channels = 0;
3572                         int dst_depth = 0;
3573                         char *caps_str = NULL;
3574                         GstCaps* caps = NULL;
3575
3576                         /* get conf. values */
3577                         mm_attrs_multiple_get(player->attrs,
3578                                                 NULL,
3579                                                 "pcm_extraction_samplerate", &dst_samplerate,
3580                                                 "pcm_extraction_channels", &dst_channels,
3581                                                 "pcm_extraction_depth", &dst_depth,
3582                                                 NULL);
3583
3584                         /* capsfilter */
3585                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3586                         caps = gst_caps_new_simple("audio/x-raw",
3587                                         "rate", G_TYPE_INT, dst_samplerate,
3588                                         "channels", G_TYPE_INT, dst_channels,
3589                                         "depth", G_TYPE_INT, dst_depth,
3590                                         NULL);
3591                         caps_str = gst_caps_to_string(caps);
3592                         LOGD("new caps : %s\n", caps_str);
3593
3594                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3595
3596                         /* clean */
3597                         gst_caps_unref(caps);
3598                         MMPLAYER_FREEIF(caps_str);
3599
3600                         /* fake sink */
3601                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
3602
3603                         /* set sync */
3604                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3605                 }
3606         } else {
3607                 // normal playback
3608                 //GstCaps* caps = NULL;
3609                 gint channels = 0;
3610
3611                 /* for logical volume control */
3612                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
3613                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3614
3615                 if (player->sound.mute) {
3616                         LOGD("mute enabled\n");
3617                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3618                 }
3619
3620 #if 0
3621                 /*capsfilter */
3622                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
3623                 caps = gst_caps_from_string("audio/x-raw-int, "
3624                                         "endianness = (int) LITTLE_ENDIAN, "
3625                                         "signed = (boolean) true, "
3626                                         "width = (int) 16, "
3627                                         "depth = (int) 16");
3628                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3629                 gst_caps_unref(caps);
3630 #endif
3631
3632                 /* check if multi-channels */
3633                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
3634                         GstPad *srcpad = NULL;
3635                         GstCaps *caps = NULL;
3636
3637                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
3638                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
3639                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3640                                         GstStructure *str = gst_caps_get_structure(caps, 0);
3641                                         if (str)
3642                                                 gst_structure_get_int(str, "channels", &channels);
3643                                         gst_caps_unref(caps);
3644                                 }
3645                                 gst_object_unref(srcpad);
3646                         }
3647                 }
3648
3649                 /* audio effect element. if audio effect is enabled */
3650                 if ((strcmp(player->ini.audioeffect_element, ""))
3651                         && (channels <= 2)
3652                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3653                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
3654
3655                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
3656
3657                         if ((!player->bypass_audio_effect)
3658                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3659                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
3660                                         if (!_mmplayer_audio_effect_custom_apply(player))
3661                                                 LOGI("apply audio effect(custom) setting success\n");
3662                                 }
3663                         }
3664
3665                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
3666                                 && (player->set_mode.rich_audio))
3667                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
3668                 }
3669
3670                 /* create audio sink */
3671                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
3672                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
3673                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
3674
3675                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
3676                 if (player->is_360_feature_enabled &&
3677                         player->is_content_spherical &&
3678                         channels == 4 &&
3679                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
3680                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
3681                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
3682
3683                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
3684
3685                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
3686
3687                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
3688                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
3689                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
3690                         gst_caps_unref(acaps);
3691
3692                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
3693                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
3694                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
3695                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
3696
3697                         player->is_openal_plugin_used = TRUE;
3698
3699                         if (player->video360_yaw_radians <= M_PI &&
3700                                         player->video360_yaw_radians >= -M_PI &&
3701                                         player->video360_pitch_radians <= M_PI_2 &&
3702                                         player->video360_pitch_radians >= -M_PI_2) {
3703                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3704                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3705                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3706                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3707                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3708                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
3709                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
3710                         }
3711                 } else {
3712                         if (player->is_360_feature_enabled && player->is_content_spherical)
3713                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
3714                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
3715                 }
3716
3717                 /* qos on */
3718                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
3719                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
3720
3721
3722                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
3723                         (player->videodec_linked && player->ini.use_system_clock)) {
3724                         LOGD("system clock will be used.\n");
3725                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
3726                 }
3727
3728                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
3729                         __mmplayer_gst_set_audiosink_property(player, attrs);
3730         }
3731
3732         if (audiobin[MMPLAYER_A_SINK].gst) {
3733                 GstPad *sink_pad = NULL;
3734                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
3735                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3736                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
3737                 gst_object_unref(GST_OBJECT(sink_pad));
3738         }
3739
3740         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3741
3742         /* adding created elements to bin */
3743         LOGD("adding created elements to bin\n");
3744         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
3745                 LOGE("failed to add elements\n");
3746                 goto ERROR;
3747         }
3748
3749         /* linking elements in the bucket by added order. */
3750         LOGD("Linking elements in the bucket by added order.\n");
3751         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3752                 LOGE("failed to link elements\n");
3753                 goto ERROR;
3754         }
3755
3756         /* get first element's sinkpad for creating ghostpad */
3757         first_element = (MMPlayerGstElement *)element_bucket->data;
3758         if (!first_element) {
3759                 LOGE("failed to get first elem\n");
3760                 goto ERROR;
3761         }
3762
3763         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3764         if (!pad) {
3765                 LOGE("failed to get pad from first element of audiobin\n");
3766                 goto ERROR;
3767         }
3768
3769         ghostpad = gst_ghost_pad_new("sink", pad);
3770         if (!ghostpad) {
3771                 LOGE("failed to create ghostpad\n");
3772                 goto ERROR;
3773         }
3774
3775         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3776                 LOGE("failed to add ghostpad to audiobin\n");
3777                 goto ERROR;
3778         }
3779
3780         gst_object_unref(pad);
3781
3782         g_list_free(element_bucket);
3783         MMPLAYER_FLEAVE();
3784
3785         return MM_ERROR_NONE;
3786
3787 ERROR:
3788
3789         LOGD("ERROR : releasing audiobin\n");
3790
3791         if (pad)
3792                 gst_object_unref(GST_OBJECT(pad));
3793
3794         if (ghostpad)
3795                 gst_object_unref(GST_OBJECT(ghostpad));
3796
3797         if (element_bucket)
3798                 g_list_free(element_bucket);
3799
3800         /* release element which are not added to bin */
3801         for (i = 1; i < MMPLAYER_A_NUM; i++) {
3802                 /* NOTE : skip bin */
3803                 if (audiobin[i].gst) {
3804                         GstObject* parent = NULL;
3805                         parent = gst_element_get_parent(audiobin[i].gst);
3806
3807                         if (!parent) {
3808                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3809                                 audiobin[i].gst = NULL;
3810                         } else
3811                                 gst_object_unref(GST_OBJECT(parent));
3812                 }
3813         }
3814
3815         /* release audiobin with it's childs */
3816         if (audiobin[MMPLAYER_A_BIN].gst)
3817                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3818
3819         MMPLAYER_FREEIF(audiobin);
3820
3821         player->pipeline->audiobin = NULL;
3822
3823         return MM_ERROR_PLAYER_INTERNAL;
3824 }
3825
3826 static GstPadProbeReturn
3827 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3828 {
3829         mm_player_t* player = (mm_player_t*) u_data;
3830         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
3831         GstMapInfo probe_info = GST_MAP_INFO_INIT;
3832
3833         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
3834
3835         if (player->audio_stream_cb && probe_info.size && probe_info.data)
3836                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
3837
3838         return GST_PAD_PROBE_OK;
3839 }
3840
3841 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
3842 {
3843         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3844 }
3845
3846 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
3847 {
3848         int ret = MM_ERROR_NONE;
3849         GList *l = NULL;
3850         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3851         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3852
3853         MMPLAYER_VIDEO_BO_LOCK(player);
3854
3855         if (player->video_bo_list) {
3856                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3857                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3858                         if (tmp && tmp->bo == bo) {
3859                                 tmp->using = FALSE;
3860                                 LOGD("release bo %p", bo);
3861                                 tbm_bo_unref(tmp->bo);
3862                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3863                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
3864                                 return ret;
3865                         }
3866                 }
3867         } else {
3868                 /* hw codec is running or the list was reset for DRC. */
3869                 LOGW("there is no bo list.");
3870         }
3871         MMPLAYER_VIDEO_BO_UNLOCK(player);
3872
3873         LOGW("failed to find bo %p", bo);
3874         return ret;
3875 }
3876
3877 static void
3878 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3879 {
3880         GList *l = NULL;
3881
3882         MMPLAYER_FENTER();
3883         MMPLAYER_RETURN_IF_FAIL(player);
3884
3885         MMPLAYER_VIDEO_BO_LOCK(player);
3886         if (player->video_bo_list) {
3887                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3888                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3889                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3890                         if (tmp) {
3891                                 if (tmp->bo)
3892                                         tbm_bo_unref(tmp->bo);
3893                                 g_free(tmp);
3894                         }
3895                 }
3896                 g_list_free(player->video_bo_list);
3897                 player->video_bo_list = NULL;
3898         }
3899         player->video_bo_size = 0;
3900         MMPLAYER_VIDEO_BO_UNLOCK(player);
3901
3902         MMPLAYER_FLEAVE();
3903         return;
3904 }
3905
3906 static void*
3907 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3908 {
3909         GList *l = NULL;
3910         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3911         gboolean ret = TRUE;
3912
3913         /* check DRC, if it is, destroy the prev bo list to create again */
3914         if (player->video_bo_size != size) {
3915                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3916                 __mmplayer_video_stream_destroy_bo_list(player);
3917                 player->video_bo_size = size;
3918         }
3919
3920         MMPLAYER_VIDEO_BO_LOCK(player);
3921
3922         if ((!player->video_bo_list) ||
3923                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3924
3925                 /* create bo list */
3926                 int idx = 0;
3927                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3928
3929                 if (player->video_bo_list) {
3930                         /* if bo list did not created all, try it again. */
3931                         idx = g_list_length(player->video_bo_list);
3932                         LOGD("bo list exist(len: %d)", idx);
3933                 }
3934
3935                 for (; idx < player->ini.num_of_video_bo; idx++) {
3936                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3937                         if (!bo_info) {
3938                                 LOGE("Fail to alloc bo_info.");
3939                                 break;
3940                         }
3941                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3942                         if (!bo_info->bo) {
3943                                 LOGE("Fail to tbm_bo_alloc.");
3944                                 g_free(bo_info);
3945                                 break;
3946                         }
3947                         bo_info->using = FALSE;
3948                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3949                 }
3950
3951                 /* update video num buffers */
3952                 player->video_num_buffers = idx;
3953                 if (idx == player->ini.num_of_video_bo)
3954                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3955
3956                 if (idx == 0) {
3957                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3958                         return NULL;
3959                 }
3960
3961                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3962         }
3963
3964         while (TRUE) {
3965                 /* get bo from list*/
3966                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3967                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3968                         if (tmp && (tmp->using == FALSE)) {
3969                                 LOGD("found bo %p to use", tmp->bo);
3970                                 tmp->using = TRUE;
3971                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3972                                 return tbm_bo_ref(tmp->bo);
3973                         }
3974                 }
3975                 if (!ret) {
3976                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3977                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3978                         return NULL;
3979                 }
3980
3981                 if (player->ini.video_bo_timeout <= 0) {
3982                         MMPLAYER_VIDEO_BO_WAIT(player);
3983                 } else {
3984                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3985                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3986                 }
3987                 continue;
3988         }
3989 }
3990
3991 static void
3992 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3993 {
3994         mm_player_t* player = (mm_player_t*)data;
3995         MMPLAYER_FENTER();
3996         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3997
3998         /* send prerolled pkt */
3999         player->video_stream_prerolled = FALSE;
4000
4001         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4002
4003         /* not to send prerolled pkt again */
4004         player->video_stream_prerolled = TRUE;
4005 }
4006
4007 static void
4008 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4009 {
4010         mm_player_t* player = (mm_player_t*)data;
4011         GstCaps *caps = NULL;
4012         MMPlayerVideoStreamDataType *stream = NULL;
4013         MMVideoBuffer *video_buffer = NULL;
4014         GstMemory *dataBlock = NULL;
4015         GstMemory *metaBlock = NULL;
4016         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4017         GstStructure *structure = NULL;
4018         const gchar *string_format = NULL;
4019         unsigned int fourcc = 0;
4020
4021         MMPLAYER_FENTER();
4022         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4023
4024         if (player->video_stream_prerolled) {
4025                 player->video_stream_prerolled = FALSE;
4026                 LOGD("skip the prerolled pkt not to send it again");
4027                 return;
4028         }
4029
4030         caps = gst_pad_get_current_caps(pad);
4031         if (caps == NULL) {
4032                 LOGE("Caps is NULL.");
4033                 return;
4034         }
4035
4036         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4037
4038         /* clear stream data structure */
4039         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4040         if (!stream) {
4041                 LOGE("failed to alloc mem for video data");
4042                 return;
4043         }
4044
4045         structure = gst_caps_get_structure(caps, 0);
4046         gst_structure_get_int(structure, "width", &(stream->width));
4047         gst_structure_get_int(structure, "height", &(stream->height));
4048         string_format = gst_structure_get_string(structure, "format");
4049         if (string_format)
4050                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
4051         stream->format = util_get_pixtype(fourcc);
4052         gst_caps_unref(caps);
4053         caps = NULL;
4054
4055         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
4056
4057     /*
4058         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
4059                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
4060     */
4061
4062         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
4063                 LOGE("Wrong condition!!");
4064                 goto ERROR;
4065         }
4066
4067         /* set size and timestamp */
4068         dataBlock = gst_buffer_peek_memory(buffer, 0);
4069         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
4070         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
4071
4072         /* check zero-copy */
4073         if (player->set_mode.video_zc &&
4074                 player->set_mode.media_packet_video_stream &&
4075                 gst_buffer_n_memory(buffer) > 1) {
4076                 metaBlock = gst_buffer_peek_memory(buffer, 1);
4077                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
4078                 video_buffer = (MMVideoBuffer *)mapinfo.data;
4079         }
4080
4081         if (video_buffer) { /* hw codec */
4082                 /* set tbm bo */
4083                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
4084                         int i = 0;
4085
4086                         /* copy pointer of tbm bo, stride, elevation */
4087                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
4088                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
4089                                 i++;
4090                         }
4091                 } else {
4092                         LOGE("Not support video buffer format");
4093                         goto ERROR;
4094                 }
4095                 memcpy(stream->stride, video_buffer->stride_width,
4096                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4097                 memcpy(stream->elevation, video_buffer->stride_height,
4098                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4099
4100                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
4101                 stream->internal_buffer = gst_buffer_ref(buffer);
4102         } else { /* sw codec */
4103                 int i = 0;
4104                 int j = 0;
4105                 int k = 0;
4106                 int ret = TBM_SURFACE_ERROR_NONE;
4107                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
4108                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
4109                 int size = 0;
4110                 unsigned char *src = NULL;
4111                 unsigned char *dest = NULL;
4112                 tbm_bo_handle thandle;
4113                 tbm_surface_h surface;
4114                 tbm_surface_info_s info;
4115                 gboolean gst_ret;
4116
4117                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
4118                 if (!gst_ret) {
4119                         LOGE("fail to gst_memory_map");
4120                         goto ERROR;
4121                 }
4122
4123
4124                 if (stream->format == MM_PIXEL_FORMAT_I420) {
4125                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
4126
4127                         ret = tbm_surface_get_info(surface, &info);
4128
4129                         if (ret != TBM_SURFACE_ERROR_NONE) {
4130                                 tbm_surface_destroy(surface);
4131                                 goto ERROR;
4132                         }
4133                         tbm_surface_destroy(surface);
4134
4135                         src_stride[0] = GST_ROUND_UP_4(stream->width);
4136                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
4137                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
4138                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
4139                         stream->stride[0] = info.planes[0].stride;
4140                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
4141                         stream->stride[1] = info.planes[1].stride;
4142                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
4143                         stream->stride[2] = info.planes[2].stride;
4144                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
4145                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
4146                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
4147                         stream->stride[0] = stream->width * 4;
4148                         stream->elevation[0] = stream->height;
4149                         size = stream->stride[0] * stream->height;
4150                 } else {
4151                         LOGE("Not support format %d", stream->format);
4152                         goto ERROR;
4153                 }
4154
4155                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
4156                 if (!stream->bo[0]) {
4157                         LOGE("Fail to tbm_bo_alloc!!");
4158                         goto ERROR;
4159                 }
4160
4161                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
4162                 if (thandle.ptr && mapinfo.data) {
4163                         if (stream->format == MM_PIXEL_FORMAT_I420) {
4164                                 for (i = 0; i < 3; i++) {
4165                                         src = mapinfo.data + src_offset[i];
4166                                         dest = thandle.ptr + info.planes[i].offset;
4167
4168                                         if (i > 0) k = 1;
4169                                         for (j = 0; j < stream->height>>k; j++) {
4170                                                 memcpy(dest, src, stream->width>>k);
4171                                                 src += src_stride[i];
4172                                                 dest += stream->stride[i];
4173                                         }
4174                                 }
4175                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
4176                                 memcpy(thandle.ptr, mapinfo.data, size);
4177                         } else {
4178                                 LOGE("Not support format %d", stream->format);
4179                                 goto ERROR;
4180                         }
4181                 } else {
4182                         LOGE("data pointer is wrong. dest : %p, src : %p",
4183                                         thandle.ptr, mapinfo.data);
4184                         goto ERROR;
4185                 }
4186                 tbm_bo_unmap(stream->bo[0]);
4187         }
4188
4189         if (player->video_stream_cb) { /* This has been already checked at the entry */
4190                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
4191                         LOGE("failed to send video stream data.");
4192                         goto ERROR;
4193                 }
4194         }
4195
4196         if (metaBlock)
4197                 gst_memory_unmap(metaBlock, &mapinfo);
4198         else
4199                 gst_memory_unmap(dataBlock, &mapinfo);
4200
4201         return;
4202
4203 ERROR:
4204         LOGE("release video stream resource.");
4205         if (metaBlock) {
4206                 int i = 0;
4207                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
4208                         if (stream->bo[i])
4209                                 tbm_bo_unref(stream->bo[i]);
4210                 }
4211                 gst_memory_unmap(metaBlock, &mapinfo);
4212
4213                 /* unref gst buffer */
4214                 if (stream->internal_buffer)
4215                         gst_buffer_unref(stream->internal_buffer);
4216         } else if (dataBlock) {
4217                 if (stream->bo[0])
4218                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
4219                 gst_memory_unmap(dataBlock, &mapinfo);
4220         }
4221
4222         g_free(stream);
4223         return;
4224 }
4225
4226 static int
4227 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
4228 {
4229         gchar* video_csc = "videoconvert"; /* default colorspace converter */
4230         GList* element_bucket = NULL;
4231
4232         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4233
4234         MMPLAYER_FENTER();
4235
4236         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
4237                 LOGD("do not need to add video filters.");
4238                 return MM_ERROR_NONE;
4239         }
4240
4241         /* in case of sw codec except 360 playback,
4242          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
4243         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
4244         LOGD("using video converter: %s", video_csc);
4245
4246         /* set video rotator */
4247         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
4248
4249         *bucket = element_bucket;
4250         MMPLAYER_FLEAVE();
4251         return MM_ERROR_NONE;
4252
4253 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
4254         g_list_free(element_bucket);
4255
4256         *bucket = NULL;
4257         MMPLAYER_FLEAVE();
4258         return MM_ERROR_PLAYER_INTERNAL;
4259 }
4260
4261 /**
4262  * This function is to create video pipeline.
4263  *
4264  * @param       player          [in]    handle of player
4265  *              caps            [in]    src caps of decoder
4266  *              surface_type    [in]    surface type for video rendering
4267  *
4268  * @return      This function returns zero on success.
4269  * @remark
4270  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
4271  */
4272 /**
4273   * VIDEO PIPELINE
4274   * - video overlay surface(arm/x86) : tizenwlsink
4275   */
4276 static int
4277 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
4278 {
4279         GstPad *pad = NULL;
4280         MMHandleType attrs;
4281         GList*element_bucket = NULL;
4282         MMPlayerGstElement* first_element = NULL;
4283         MMPlayerGstElement* videobin = NULL;
4284         gchar *videosink_element = NULL;
4285
4286         MMPLAYER_FENTER();
4287
4288         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4289
4290         /* alloc handles */
4291         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
4292         if (!videobin)
4293                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4294
4295         player->pipeline->videobin = videobin;
4296
4297         attrs = MMPLAYER_GET_ATTRS(player);
4298         if (!attrs) {
4299                 LOGE("cannot get content attribute");
4300                 return MM_ERROR_PLAYER_INTERNAL;
4301         }
4302
4303         /* create bin */
4304         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
4305         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
4306         if (!videobin[MMPLAYER_V_BIN].gst) {
4307                 LOGE("failed to create videobin");
4308                 goto ERROR;
4309         }
4310
4311         int enable_video_decoded_cb = 0;
4312         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
4313
4314         if (player->is_360_feature_enabled && player->is_content_spherical) {
4315                 LOGD("video360 elem will be added.");
4316
4317                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
4318                                 "video-360", TRUE, player);
4319
4320                 /* Set spatial media metadata and/or user settings to the element.
4321                  * */
4322                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4323                                 "projection-type", player->video360_metadata.projection_type, NULL);
4324
4325                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4326                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
4327
4328                 if (player->video360_metadata.full_pano_width_pixels &&
4329                                 player->video360_metadata.full_pano_height_pixels &&
4330                                 player->video360_metadata.cropped_area_image_width &&
4331                                 player->video360_metadata.cropped_area_image_height) {
4332                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4333                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
4334                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
4335                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
4336                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
4337                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
4338                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
4339                                         NULL);
4340                 }
4341
4342                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
4343                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4344                                         "horizontal-fov", player->video360_horizontal_fov,
4345                                         "vertical-fov", player->video360_vertical_fov, NULL);
4346                 }
4347
4348                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
4349                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4350                                         "zoom", 1.0f / player->video360_zoom, NULL);
4351                 }
4352
4353                 if (player->video360_yaw_radians <= M_PI &&
4354                                 player->video360_yaw_radians >= -M_PI &&
4355                                 player->video360_pitch_radians <= M_PI_2 &&
4356                                 player->video360_pitch_radians >= -M_PI_2) {
4357                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4358                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4359                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4360                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4361                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4362                                         "pose-yaw", player->video360_metadata.init_view_heading,
4363                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
4364                 }
4365
4366                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4367                                 "passthrough", !player->is_video360_enabled, NULL);
4368         }
4369
4370         /* set video sink */
4371         switch (surface_type) {
4372         case MM_DISPLAY_SURFACE_OVERLAY:
4373                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
4374                         goto ERROR;
4375                 if (strlen(player->ini.videosink_element_overlay) > 0)
4376                         videosink_element = player->ini.videosink_element_overlay;
4377                 else
4378                         goto ERROR;
4379                 break;
4380         case MM_DISPLAY_SURFACE_NULL:
4381                 if (strlen(player->ini.videosink_element_fake) > 0)
4382                         videosink_element = player->ini.videosink_element_fake;
4383                 else
4384                         goto ERROR;
4385                 break;
4386         case MM_DISPLAY_SURFACE_REMOTE:
4387                 if (strlen(player->ini.videosink_element_fake) > 0)
4388                         videosink_element = player->ini.videosink_element_fake;
4389                 else
4390                         goto ERROR;
4391                 break;
4392         default:
4393                 LOGE("unidentified surface type");
4394                 goto ERROR;
4395         }
4396         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
4397
4398         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
4399
4400         /* additional setting for sink plug-in */
4401         switch (surface_type) {
4402         case MM_DISPLAY_SURFACE_OVERLAY:
4403         {
4404                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
4405                 if (!use_tbm) {
4406                         LOGD("selected videosink name: %s", videosink_element);
4407
4408                         /* support shard memory with S/W codec on HawkP */
4409                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
4410                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4411                                         "use-tbm", use_tbm, NULL);
4412                         }
4413                 } else {
4414                         if (attrs) {
4415                                 int gapless = 0;
4416
4417                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4418
4419                                 if (gapless > 0) {
4420                                         LOGD("disable last-sample");
4421                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4422                                 }
4423                         }
4424                 }
4425                 if (player->set_mode.media_packet_video_stream) {
4426                         int enable = 0;
4427                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
4428                         if (enable)
4429                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
4430
4431                         MMPLAYER_SIGNAL_CONNECT(player,
4432                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4433                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4434                                                                         "handoff",
4435                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4436                                                                         (gpointer)player);
4437
4438                         MMPLAYER_SIGNAL_CONNECT(player,
4439                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4440                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4441                                                                         "preroll-handoff",
4442                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4443                                                                         (gpointer)player);
4444                 }
4445                 break;
4446         }
4447         case MM_DISPLAY_SURFACE_REMOTE:
4448         {
4449                 if (player->set_mode.media_packet_video_stream) {
4450                         LOGE("add data probe at videosink");
4451                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4452                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
4453
4454                         MMPLAYER_SIGNAL_CONNECT(player,
4455                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4456                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4457                                                                         "handoff",
4458                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4459                                                                         (gpointer)player);
4460
4461                         MMPLAYER_SIGNAL_CONNECT(player,
4462                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4463                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4464                                                                         "preroll-handoff",
4465                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4466                                                                         (gpointer)player);
4467                         if (attrs) {
4468                                 int gapless = 0;
4469
4470                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4471
4472                                 if (gapless > 0) {
4473                                         LOGD("disable last-sample");
4474                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4475                                 }
4476                         }
4477                 }
4478                 break;
4479         }
4480         default:
4481                 break;
4482         }
4483
4484         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
4485                 goto ERROR;
4486
4487         if (videobin[MMPLAYER_V_SINK].gst) {
4488                 GstPad *sink_pad = NULL;
4489                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
4490                 if (sink_pad) {
4491                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4492                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4493                         gst_object_unref(GST_OBJECT(sink_pad));
4494                 } else
4495                         LOGW("failed to get sink pad from videosink\n");
4496         }
4497
4498         /* store it as it's sink element */
4499         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
4500
4501         /* adding created elements to bin */
4502         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
4503                 LOGE("failed to add elements\n");
4504                 goto ERROR;
4505         }
4506
4507         /* Linking elements in the bucket by added order */
4508         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4509                 LOGE("failed to link elements\n");
4510                 goto ERROR;
4511         }
4512
4513         /* get first element's sinkpad for creating ghostpad */
4514         if (element_bucket)
4515                 first_element = (MMPlayerGstElement *)element_bucket->data;
4516         if (!first_element) {
4517                 LOGE("failed to get first element from bucket\n");
4518                 goto ERROR;
4519         }
4520
4521         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4522         if (!pad) {
4523                 LOGE("failed to get pad from first element\n");
4524                 goto ERROR;
4525         }
4526
4527         /* create ghostpad */
4528         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
4529         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
4530                 LOGE("failed to add ghostpad to videobin\n");
4531                 goto ERROR;
4532         }
4533         gst_object_unref(pad);
4534
4535         /* done. free allocated variables */
4536         if (element_bucket)
4537                 g_list_free(element_bucket);
4538
4539         MMPLAYER_FLEAVE();
4540
4541         return MM_ERROR_NONE;
4542
4543 ERROR:
4544         LOGE("ERROR : releasing videobin\n");
4545
4546         g_list_free(element_bucket);
4547
4548         if (pad)
4549                 gst_object_unref(GST_OBJECT(pad));
4550
4551         /* release videobin with it's childs */
4552         if (videobin[MMPLAYER_V_BIN].gst)
4553                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
4554
4555
4556         MMPLAYER_FREEIF(videobin);
4557
4558         player->pipeline->videobin = NULL;
4559
4560         return MM_ERROR_PLAYER_INTERNAL;
4561 }
4562
4563 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
4564 {
4565         GList *element_bucket = NULL;
4566         MMPlayerGstElement *textbin = player->pipeline->textbin;
4567
4568         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
4569         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
4570         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
4571                                                         "signal-handoffs", FALSE,
4572                                                         NULL);
4573
4574         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
4575         MMPLAYER_SIGNAL_CONNECT(player,
4576                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
4577                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
4578                                                         "handoff",
4579                                                         G_CALLBACK(__mmplayer_update_subtitle),
4580                                                         (gpointer)player);
4581
4582         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
4583         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
4584
4585         if (!player->play_subtitle) {
4586                 LOGD("add textbin sink as sink element of whole pipeline.\n");
4587                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
4588         }
4589
4590         /* adding created elements to bin */
4591         LOGD("adding created elements to bin\n");
4592         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
4593                 LOGE("failed to add elements\n");
4594                 goto ERROR;
4595         }
4596
4597         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
4598         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
4599         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
4600
4601         /* linking elements in the bucket by added order. */
4602         LOGD("Linking elements in the bucket by added order.\n");
4603         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4604                 LOGE("failed to link elements\n");
4605                 goto ERROR;
4606         }
4607
4608         /* done. free allocated variables */
4609         g_list_free(element_bucket);
4610
4611         if (textbin[MMPLAYER_T_QUEUE].gst) {
4612                 GstPad *pad = NULL;
4613                 GstPad *ghostpad = NULL;
4614
4615                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
4616                 if (!pad) {
4617                         LOGE("failed to get sink pad of text queue");
4618                         goto ERROR;
4619                 }
4620
4621                 ghostpad = gst_ghost_pad_new("text_sink", pad);
4622                 gst_object_unref(pad);
4623
4624                 if (!ghostpad) {
4625                         LOGE("failed to create ghostpad of textbin\n");
4626                         goto ERROR;
4627                 }
4628
4629                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
4630                         LOGE("failed to add ghostpad to textbin\n");
4631                         gst_object_unref(ghostpad);
4632                         goto ERROR;
4633                 }
4634         }
4635
4636         return MM_ERROR_NONE;
4637
4638 ERROR:
4639         g_list_free(element_bucket);
4640
4641         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
4642                 LOGE("remove textbin sink from sink list");
4643                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
4644         }
4645
4646         /* release element at __mmplayer_gst_create_text_sink_bin */
4647         return MM_ERROR_PLAYER_INTERNAL;
4648 }
4649
4650 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
4651 {
4652         MMPlayerGstElement *textbin = NULL;
4653         GList *element_bucket = NULL;
4654         int surface_type = 0;
4655         gint i = 0;
4656
4657         MMPLAYER_FENTER();
4658
4659         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4660
4661         /* alloc handles */
4662         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
4663         if (!textbin) {
4664                 LOGE("failed to allocate memory for textbin\n");
4665                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4666         }
4667
4668         /* create bin */
4669         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
4670         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
4671         if (!textbin[MMPLAYER_T_BIN].gst) {
4672                 LOGE("failed to create textbin\n");
4673                 goto ERROR;
4674         }
4675
4676         /* take it */
4677         player->pipeline->textbin = textbin;
4678
4679         /* fakesink */
4680         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
4681         LOGD("surface type for subtitle : %d", surface_type);
4682         switch (surface_type) {
4683         case MM_DISPLAY_SURFACE_OVERLAY:
4684         case MM_DISPLAY_SURFACE_NULL:
4685         case MM_DISPLAY_SURFACE_REMOTE:
4686                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
4687                         LOGE("failed to make plain text elements\n");
4688                         goto ERROR;
4689                 }
4690                 break;
4691         default:
4692                 goto ERROR;
4693                 break;
4694         }
4695
4696         MMPLAYER_FLEAVE();
4697
4698         return MM_ERROR_NONE;
4699
4700 ERROR:
4701
4702         LOGD("ERROR : releasing textbin\n");
4703
4704         g_list_free(element_bucket);
4705
4706         /* release signal */
4707         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4708
4709         /* release element which are not added to bin */
4710         for (i = 1; i < MMPLAYER_T_NUM; i++) {
4711                 /* NOTE : skip bin */
4712                 if (textbin[i].gst) {
4713                         GstObject* parent = NULL;
4714                         parent = gst_element_get_parent(textbin[i].gst);
4715
4716                         if (!parent) {
4717                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
4718                                 textbin[i].gst = NULL;
4719                         } else {
4720                                 gst_object_unref(GST_OBJECT(parent));
4721                         }
4722                 }
4723         }
4724
4725         /* release textbin with it's childs */
4726         if (textbin[MMPLAYER_T_BIN].gst)
4727                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4728
4729         MMPLAYER_FREEIF(player->pipeline->textbin);
4730         player->pipeline->textbin = NULL;
4731
4732         MMPLAYER_FLEAVE();
4733         return MM_ERROR_PLAYER_INTERNAL;
4734 }
4735
4736
4737 static int
4738 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
4739 {
4740         MMPlayerGstElement* mainbin = NULL;
4741         MMPlayerGstElement* textbin = NULL;
4742         MMHandleType attrs = 0;
4743         GstElement *subsrc = NULL;
4744         GstElement *subparse = NULL;
4745         gchar *subtitle_uri = NULL;
4746         const gchar *charset = NULL;
4747         GstPad *pad = NULL;
4748
4749         MMPLAYER_FENTER();
4750
4751         /* get mainbin */
4752         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4753                                                                 player->pipeline &&
4754                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4755
4756         mainbin = player->pipeline->mainbin;
4757
4758         attrs = MMPLAYER_GET_ATTRS(player);
4759         if (!attrs) {
4760                 LOGE("cannot get content attribute\n");
4761                 return MM_ERROR_PLAYER_INTERNAL;
4762         }
4763
4764         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4765         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4766                 LOGE("subtitle uri is not proper filepath.\n");
4767                 return MM_ERROR_PLAYER_INVALID_URI;
4768         }
4769
4770         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4771                 LOGE("failed to get storage info of subtitle path");
4772                 return MM_ERROR_PLAYER_INVALID_URI;
4773         }
4774
4775         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
4776
4777         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4778         player->subtitle_language_list = NULL;
4779         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4780
4781         /* create the subtitle source */
4782         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4783         if (!subsrc) {
4784                 LOGE("failed to create filesrc element\n");
4785                 goto ERROR;
4786         }
4787         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4788
4789         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4790         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4791
4792         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4793                 LOGW("failed to add queue\n");
4794                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4795                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4796                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4797                 goto ERROR;
4798         }
4799
4800         /* subparse */
4801         subparse = gst_element_factory_make("subparse", "subtitle_parser");
4802         if (!subparse) {
4803                 LOGE("failed to create subparse element\n");
4804                 goto ERROR;
4805         }
4806
4807         charset = util_get_charset(subtitle_uri);
4808         if (charset) {
4809                 LOGD("detected charset is %s\n", charset);
4810                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4811         }
4812
4813         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4814         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4815
4816         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4817                 LOGW("failed to add subparse\n");
4818                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4819                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4820                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4821                 goto ERROR;
4822         }
4823
4824         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4825                 LOGW("failed to link subsrc and subparse\n");
4826                 goto ERROR;
4827         }
4828
4829         player->play_subtitle = TRUE;
4830         player->adjust_subtitle_pos = 0;
4831
4832         LOGD("play subtitle using subtitle file\n");
4833
4834         if (player->pipeline->textbin == NULL) {
4835                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4836                         LOGE("failed to create text sink bin. continuing without text\n");
4837                         goto ERROR;
4838                 }
4839
4840                 textbin = player->pipeline->textbin;
4841
4842                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4843                         LOGW("failed to add textbin\n");
4844
4845                         /* release signal */
4846                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4847
4848                         /* release textbin with it's childs */
4849                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4850                         MMPLAYER_FREEIF(player->pipeline->textbin);
4851                         player->pipeline->textbin = textbin = NULL;
4852                         goto ERROR;
4853                 }
4854
4855                 LOGD("link text input selector and textbin ghost pad");
4856
4857                 player->textsink_linked = 1;
4858                 player->external_text_idx = 0;
4859                 LOGI("player->textsink_linked set to 1\n");
4860         } else {
4861                 textbin = player->pipeline->textbin;
4862                 LOGD("text bin has been created. reuse it.");
4863                 player->external_text_idx = 1;
4864         }
4865
4866         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4867                 LOGW("failed to link subparse and textbin\n");
4868                 goto ERROR;
4869         }
4870
4871         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4872         if (!pad) {
4873                 LOGE("failed to get sink pad from textsink to probe data");
4874                 goto ERROR;
4875         }
4876
4877         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4878                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4879
4880         gst_object_unref(pad);
4881         pad = NULL;
4882
4883         /* create dot. for debugging */
4884         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4885         MMPLAYER_FLEAVE();
4886
4887         return MM_ERROR_NONE;
4888
4889 ERROR:
4890         /* release text pipeline resource */
4891         player->textsink_linked = 0;
4892
4893         /* release signal */
4894         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4895
4896         if (player->pipeline->textbin) {
4897                 LOGE("remove textbin");
4898
4899                 /* release textbin with it's childs */
4900                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4901                 MMPLAYER_FREEIF(player->pipeline->textbin);
4902                 player->pipeline->textbin = NULL;
4903
4904         }
4905
4906         /* release subtitle elem */
4907         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4908         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4909
4910         return MM_ERROR_PLAYER_INTERNAL;
4911 }
4912
4913 gboolean
4914 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4915 {
4916         mm_player_t* player = (mm_player_t*) data;
4917         MMMessageParamType msg = {0, };
4918         GstClockTime duration = 0;
4919         gpointer text = NULL;
4920         guint text_size = 0;
4921         gboolean ret = TRUE;
4922         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4923
4924         MMPLAYER_FENTER();
4925
4926         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4927         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4928
4929         if (player->is_subtitle_force_drop) {
4930                 LOGW("subtitle is dropped forcedly.");
4931                 return ret;
4932         }
4933
4934         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4935         text = mapinfo.data;
4936         text_size = mapinfo.size;
4937         duration = GST_BUFFER_DURATION(buffer);
4938
4939         if (player->set_mode.subtitle_off) {
4940                 LOGD("subtitle is OFF.\n");
4941                 return TRUE;
4942         }
4943
4944         if (!text || (text_size == 0)) {
4945                 LOGD("There is no subtitle to be displayed.\n");
4946                 return TRUE;
4947         }
4948
4949         msg.data = (void *) text;
4950         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4951
4952         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
4953
4954         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4955         gst_buffer_unmap(buffer, &mapinfo);
4956
4957         MMPLAYER_FLEAVE();
4958
4959         return ret;
4960 }
4961
4962 static GstPadProbeReturn
4963 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4964 {
4965         mm_player_t *player = (mm_player_t *) u_data;
4966         GstClockTime cur_timestamp = 0;
4967         gint64 adjusted_timestamp = 0;
4968         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4969
4970         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4971
4972         if (player->set_mode.subtitle_off) {
4973                 LOGD("subtitle is OFF.\n");
4974                 return TRUE;
4975         }
4976
4977         if (player->adjust_subtitle_pos == 0) {
4978                 LOGD("nothing to do");
4979                 return TRUE;
4980         }
4981
4982         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4983         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4984
4985         if (adjusted_timestamp < 0) {
4986                 LOGD("adjusted_timestamp under zero");
4987                 MMPLAYER_FLEAVE();
4988                 return FALSE;
4989         }
4990
4991         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4992         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4993                                 GST_TIME_ARGS(cur_timestamp),
4994                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4995
4996         return GST_PAD_PROBE_OK;
4997 }
4998 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4999 {
5000         MMPLAYER_FENTER();
5001
5002         /* check player and subtitlebin are created */
5003         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5004         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5005
5006         if (position == 0) {
5007                 LOGD("nothing to do\n");
5008                 MMPLAYER_FLEAVE();
5009                 return MM_ERROR_NONE;
5010         }
5011
5012         switch (format) {
5013         case MM_PLAYER_POS_FORMAT_TIME:
5014                 {
5015                         /* check current postion */
5016                         player->adjust_subtitle_pos = position;
5017
5018                         LOGD("save adjust_subtitle_pos in player") ;
5019                 }
5020                 break;
5021
5022         default:
5023                 {
5024                         LOGW("invalid format.\n");
5025                         MMPLAYER_FLEAVE();
5026                         return MM_ERROR_INVALID_ARGUMENT;
5027                 }
5028         }
5029
5030         MMPLAYER_FLEAVE();
5031
5032         return MM_ERROR_NONE;
5033 }
5034
5035 static void
5036 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
5037 {
5038         GstElement *appsrc = element;
5039         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
5040         GstBuffer *buffer = NULL;
5041         GstFlowReturn ret = GST_FLOW_OK;
5042         gint len = size;
5043
5044         MMPLAYER_RETURN_IF_FAIL(element);
5045         MMPLAYER_RETURN_IF_FAIL(buf);
5046
5047         buffer = gst_buffer_new();
5048
5049         if (buf->offset >= buf->len) {
5050                 LOGD("call eos appsrc\n");
5051                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
5052                 return;
5053         }
5054
5055         if (buf->len - buf->offset < size)
5056                 len = buf->len - buf->offset;
5057
5058         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
5059         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
5060         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
5061
5062         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
5063         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
5064
5065         buf->offset += len;
5066 }
5067
5068 static gboolean
5069 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
5070 {
5071         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
5072
5073         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
5074
5075         buf->offset  = (int)size;
5076
5077         return TRUE;
5078 }
5079
5080 static gboolean
5081 __mmplayer_gst_create_decoder(mm_player_t *player,
5082                                                                 MMPlayerTrackType track,
5083                                                                 GstPad* srcpad,
5084                                                                 enum MainElementID elemId,
5085                                                                 const gchar* name)
5086 {
5087         gboolean ret = TRUE;
5088         GstPad *sinkpad = NULL;
5089
5090         MMPLAYER_FENTER();
5091
5092         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5093                                                 player->pipeline &&
5094                                                 player->pipeline->mainbin, FALSE);
5095         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
5096         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
5097         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
5098
5099         GstElement *decodebin = NULL;
5100         GstCaps *dec_caps = NULL;
5101
5102         /* create decodebin */
5103         decodebin = gst_element_factory_make("decodebin", name);
5104
5105         if (!decodebin) {
5106                 LOGE("error : fail to create decodebin for %d decoder\n", track);
5107                 ret = FALSE;
5108                 goto ERROR;
5109         }
5110
5111         /* raw pad handling signal */
5112         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5113                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
5114
5115         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5116         before looking for any elements that can handle that stream.*/
5117         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5118                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
5119
5120         /* This signal is emitted when a element is added to the bin.*/
5121         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5122                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
5123
5124         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5125                 LOGE("failed to add new decodebin\n");
5126                 ret = FALSE;
5127                 goto ERROR;
5128         }
5129
5130         dec_caps = gst_pad_query_caps(srcpad, NULL);
5131         if (dec_caps) {
5132                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
5133                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
5134                 gst_caps_unref(dec_caps);
5135         }
5136
5137         player->pipeline->mainbin[elemId].id = elemId;
5138         player->pipeline->mainbin[elemId].gst = decodebin;
5139
5140         sinkpad = gst_element_get_static_pad(decodebin, "sink");
5141
5142         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5143                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
5144                 gst_object_unref(GST_OBJECT(decodebin));
5145         }
5146
5147         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
5148                 LOGE("failed to sync second level decodebin state with parent\n");
5149
5150         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
5151
5152 ERROR:
5153         if (sinkpad) {
5154                 gst_object_unref(GST_OBJECT(sinkpad));
5155                 sinkpad = NULL;
5156         }
5157         MMPLAYER_FLEAVE();
5158
5159         return ret;
5160 }
5161
5162 /**
5163  * This function is to create  audio or video pipeline for playing.
5164  *
5165  * @param       player          [in]    handle of player
5166  *
5167  * @return      This function returns zero on success.
5168  * @remark
5169  * @see
5170  */
5171 static int
5172 __mmplayer_gst_create_pipeline(mm_player_t* player)
5173 {
5174         GstBus  *bus = NULL;
5175         MMPlayerGstElement *mainbin = NULL;
5176         MMHandleType attrs = 0;
5177         GstElement* element = NULL;
5178         GstElement* elem_src_audio = NULL;
5179         GstElement* elem_src_subtitle = NULL;
5180         GstElement* es_video_queue = NULL;
5181         GstElement* es_audio_queue = NULL;
5182         GstElement* es_subtitle_queue = NULL;
5183         GList* element_bucket = NULL;
5184         gboolean need_state_holder = TRUE;
5185         gint i = 0;
5186 #ifdef SW_CODEC_ONLY
5187         int surface_type = 0;
5188 #endif
5189         MMPLAYER_FENTER();
5190
5191         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192
5193         /* get profile attribute */
5194         attrs = MMPLAYER_GET_ATTRS(player);
5195         if (!attrs) {
5196                 LOGE("cannot get content attribute\n");
5197                 goto INIT_ERROR;
5198         }
5199
5200         /* create pipeline handles */
5201         if (player->pipeline) {
5202                 LOGW("pipeline should be released before create new one\n");
5203                 goto INIT_ERROR;
5204         }
5205
5206         player->video360_metadata.is_spherical = -1;
5207         player->is_openal_plugin_used = FALSE;
5208
5209         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
5210         if (player->pipeline == NULL)
5211                 goto INIT_ERROR;
5212
5213         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
5214
5215         /* create mainbin */
5216         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
5217         if (mainbin == NULL)
5218                 goto INIT_ERROR;
5219
5220         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
5221
5222         /* create pipeline */
5223         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
5224         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
5225         if (!mainbin[MMPLAYER_M_PIPE].gst) {
5226                 LOGE("failed to create pipeline\n");
5227                 goto INIT_ERROR;
5228         }
5229         player->demux_pad_index = 0;
5230         player->subtitle_language_list = NULL;
5231
5232         player->is_subtitle_force_drop = FALSE;
5233         player->last_multiwin_status = FALSE;
5234
5235         _mmplayer_track_initialize(player);
5236         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5237
5238         /* create source element */
5239         switch (player->profile.uri_type) {
5240         /* rtsp streamming */
5241         case MM_PLAYER_URI_TYPE_URL_RTSP:
5242                 {
5243                         gchar *user_agent;
5244
5245                         element = gst_element_factory_make("rtspsrc", "rtsp source");
5246
5247                         if (!element) {
5248                                 LOGE("failed to create streaming source element\n");
5249                                 break;
5250                         }
5251
5252                         /* make it zero */
5253                         user_agent = NULL;
5254
5255                         /* get attribute */
5256                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
5257
5258                         SECURE_LOGD("user_agent : %s\n", user_agent);
5259
5260                         /* setting property to streaming source */
5261                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5262                         if (user_agent)
5263                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
5264
5265                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5266                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
5267                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5268                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
5269                 }
5270                 break;
5271
5272         /* http streaming*/
5273         case MM_PLAYER_URI_TYPE_URL_HTTP:
5274                 {
5275                         gchar *user_agent, *cookies, **cookie_list;
5276                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
5277                         user_agent = cookies = NULL;
5278                         cookie_list = NULL;
5279                         gint mode = MM_PLAYER_PD_MODE_NONE;
5280
5281                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
5282
5283                         player->pd_mode = mode;
5284
5285                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
5286
5287                         if (!MMPLAYER_IS_HTTP_PD(player)) {
5288                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
5289                                 if (!element) {
5290                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
5291                                         break;
5292                                 }
5293                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
5294
5295                                 /* get attribute */
5296                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
5297                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
5298
5299                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
5300                                         LOGD("get timeout from ini\n");
5301                                         http_timeout = player->ini.http_timeout;
5302                                 }
5303
5304                                 /* get attribute */
5305                                 SECURE_LOGD("location : %s\n", player->profile.uri);
5306                                 SECURE_LOGD("cookies : %s\n", cookies);
5307                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
5308                                 LOGD("timeout : %d\n",  http_timeout);
5309
5310                                 /* setting property to streaming source */
5311                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5312                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
5313                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
5314
5315                                 /* parsing cookies */
5316                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
5317                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
5318                                         g_strfreev(cookie_list);
5319                                 }
5320                                 if (user_agent)
5321                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
5322
5323                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
5324                                         LOGW("it's dash. and it's still experimental feature.");
5325                         } else {
5326                                 // progressive download
5327                                 gchar* location = NULL;
5328
5329                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5330                                         gchar *path = NULL;
5331
5332                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
5333
5334                                         MMPLAYER_FREEIF(player->pd_file_save_path);
5335
5336                                         LOGD("PD Location : %s\n", path);
5337
5338                                         if (path) {
5339                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
5340                                                         LOGE("failed to get storage info");
5341                                                         break;
5342                                                 }
5343                                                 player->pd_file_save_path = g_strdup(path);
5344                                         } else {
5345                                                 LOGE("can't find pd location so, it should be set \n");
5346                                                 break;
5347                                         }
5348                                 }
5349
5350                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
5351                                 if (!element) {
5352                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
5353                                         break;
5354                                 }
5355
5356                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
5357                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
5358                                 else
5359                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5360                                 g_object_get(element, "location", &location, NULL);
5361                                 LOGD("PD_LOCATION [%s].\n", location);
5362                                 if (location)
5363                                         g_free(location);
5364                         }
5365                 }
5366                 break;
5367
5368         /* file source */
5369         case MM_PLAYER_URI_TYPE_FILE:
5370                 {
5371                         LOGD("using filesrc for 'file://' handler.\n");
5372                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
5373                                 LOGE("failed to get storage info");
5374                                 break;
5375                         }
5376
5377                         element = gst_element_factory_make("filesrc", "source");
5378                         if (!element) {
5379                                 LOGE("failed to create filesrc\n");
5380                                 break;
5381                         }
5382
5383                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
5384                 }
5385                 break;
5386
5387         case MM_PLAYER_URI_TYPE_SS:
5388                 {
5389                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
5390                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
5391                         if (!element) {
5392                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
5393                                 break;
5394                         }
5395
5396                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
5397                                 LOGD("get timeout from ini\n");
5398                                 http_timeout = player->ini.http_timeout;
5399                         }
5400
5401                         /* setting property to streaming source */
5402                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5403                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
5404                 }
5405                 break;
5406         case MM_PLAYER_URI_TYPE_MS_BUFF:
5407                 {
5408                         LOGD("MS buff src is selected\n");
5409
5410                         if (player->v_stream_caps) {
5411                                 element = gst_element_factory_make("appsrc", "video_appsrc");
5412                                 if (!element) {
5413                                         LOGF("failed to create video app source element[appsrc].\n");
5414                                         break;
5415                                 }
5416
5417                                 if (player->a_stream_caps) {
5418                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
5419                                         if (!elem_src_audio) {
5420                                                 LOGF("failed to create audio app source element[appsrc].\n");
5421                                                 break;
5422                                         }
5423                                 }
5424                         } else if (player->a_stream_caps) {
5425                                 /* no video, only audio pipeline*/
5426                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
5427                                 if (!element) {
5428                                         LOGF("failed to create audio app source element[appsrc].\n");
5429                                         break;
5430                                 }
5431                         }
5432
5433                         if (player->s_stream_caps) {
5434                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
5435                                 if (!elem_src_subtitle) {
5436                                         LOGF("failed to create subtitle app source element[appsrc].\n");
5437                                         break;
5438                                 }
5439                         }
5440
5441                         LOGD("setting app sources properties.\n");
5442                         LOGD("location : %s\n", player->profile.uri);
5443
5444                         if (player->v_stream_caps && element) {
5445                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
5446                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
5447                                                                                                 "caps", player->v_stream_caps, NULL);
5448
5449                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
5450                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
5451                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
5452                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
5453
5454                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
5455                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
5456                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5457                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
5458
5459                                 if (player->a_stream_caps && elem_src_audio) {
5460                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
5461                                                                                                                         "caps", player->a_stream_caps, NULL);
5462
5463                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5464                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5465                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5466                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5467
5468                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
5469                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
5470                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5471                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
5472                                 }
5473                         } else if (player->a_stream_caps && element) {
5474                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
5475                                                                                                 "caps", player->a_stream_caps, NULL);
5476
5477                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5478                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5479                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5480                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5481
5482                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
5483                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
5484                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5485                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
5486                         }
5487
5488                         if (player->s_stream_caps && elem_src_subtitle) {
5489                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
5490                                                                                                                  "caps", player->s_stream_caps, NULL);
5491
5492                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
5493                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
5494                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
5495                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
5496
5497                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
5498
5499                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5500                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
5501                         }
5502
5503                         if (player->v_stream_caps && element) {
5504                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5505                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
5506                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5507                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
5508
5509                                 if (player->a_stream_caps && elem_src_audio) {
5510                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5511                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
5512                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5513                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
5514                                 }
5515                         } else if (player->a_stream_caps && element) {
5516                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5517                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
5518                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5519                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
5520                         }
5521
5522                         if (player->s_stream_caps && elem_src_subtitle)
5523                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5524                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
5525
5526                         need_state_holder = FALSE;
5527
5528                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
5529                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
5530                                 LOGE("failed to commit\n");
5531                 }
5532                 break;
5533         /* appsrc */
5534         case MM_PLAYER_URI_TYPE_MEM:
5535                 {
5536                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
5537
5538                         LOGD("mem src is selected\n");
5539
5540                         element = gst_element_factory_make("appsrc", "mem-source");
5541                         if (!element) {
5542                                 LOGE("failed to create appsrc element\n");
5543                                 break;
5544                         }
5545
5546                         g_object_set(element, "stream-type", stream_type, NULL);
5547                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
5548                         g_object_set(element, "blocksize", (guint64)20480, NULL);
5549
5550                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5551                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
5552                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5553                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
5554                 }
5555                 break;
5556         case MM_PLAYER_URI_TYPE_URL:
5557                 break;
5558
5559         case MM_PLAYER_URI_TYPE_TEMP:
5560                 break;
5561
5562         case MM_PLAYER_URI_TYPE_NONE:
5563         default:
5564                 break;
5565         }
5566
5567         /* check source element is OK */
5568         if (!element) {
5569                 LOGE("no source element was created.\n");
5570                 goto INIT_ERROR;
5571         }
5572
5573         /* take source element */
5574         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
5575         mainbin[MMPLAYER_M_SRC].gst = element;
5576         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
5577
5578         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5579                 player->streamer = __mm_player_streaming_create();
5580                 __mm_player_streaming_initialize(player->streamer);
5581         }
5582
5583         if (MMPLAYER_IS_HTTP_PD(player)) {
5584                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
5585
5586                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
5587                 element = gst_element_factory_make("queue2", "queue2");
5588                 if (!element) {
5589                         LOGE("failed to create http streaming buffer element\n");
5590                         goto INIT_ERROR;
5591                 }
5592
5593                 /* take it */
5594                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5595                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
5596                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
5597
5598                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
5599
5600                 player->streamer->is_pd_mode = TRUE;
5601
5602                 __mm_player_streaming_set_queue2(player->streamer,
5603                                 element,
5604                                 TRUE,
5605                                 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
5606                                 pre_buffering_time,
5607                                 1.0,
5608                                 player->ini.http_buffering_limit,
5609                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
5610                                 NULL,
5611                                 0);
5612         }
5613         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5614                 if (player->v_stream_caps) {
5615                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
5616                         if (!es_video_queue) {
5617                                 LOGE("create es_video_queue for es player failed\n");
5618                                 goto INIT_ERROR;
5619                         }
5620                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
5621                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
5622                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
5623                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
5624
5625                         /* Adding audio appsrc to bucket */
5626                         if (player->a_stream_caps && elem_src_audio) {
5627                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
5628                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
5629                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
5630
5631                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
5632                                 if (!es_audio_queue) {
5633                                         LOGE("create es_audio_queue for es player failed\n");
5634                                         goto INIT_ERROR;
5635                                 }
5636                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
5637
5638                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
5639                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
5640                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
5641                         }
5642                 } else if (player->a_stream_caps) {
5643                         /* Only audio stream, no video */
5644                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
5645                         if (!es_audio_queue) {
5646                                 LOGE("create es_audio_queue for es player failed\n");
5647                                 goto INIT_ERROR;
5648                         }
5649                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
5650                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
5651                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
5652                 }
5653
5654                 if (player->s_stream_caps && elem_src_subtitle) {
5655                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5656                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
5657                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
5658
5659                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
5660                         if (!es_subtitle_queue) {
5661                                 LOGE("create es_subtitle_queue for es player failed\n");
5662                                 goto INIT_ERROR;
5663                         }
5664                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
5665                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
5666                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
5667                 }
5668         }
5669
5670         /* create autoplugging element if src element is not a rtsp src */
5671         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
5672                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
5673                 element = NULL;
5674                 enum MainElementID elemId = MMPLAYER_M_NUM;
5675
5676                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
5677                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
5678                         elemId = MMPLAYER_M_AUTOPLUG;
5679                         element = __mmplayer_create_decodebin(player);
5680                         if (element) {
5681                                 /* default size of mq in decodebin is 2M
5682                                  * but it can cause blocking issue during seeking depends on content. */
5683                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
5684                         }
5685                         need_state_holder = FALSE;
5686                 } else {
5687                         elemId = MMPLAYER_M_TYPEFIND;
5688                         element = gst_element_factory_make("typefind", "typefinder");
5689                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
5690                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
5691                 }
5692
5693                 /* check autoplug element is OK */
5694                 if (!element) {
5695                         LOGE("can not create element(%d)\n", elemId);
5696                         goto INIT_ERROR;
5697                 }
5698
5699                 mainbin[elemId].id = elemId;
5700                 mainbin[elemId].gst = element;
5701
5702                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
5703         }
5704
5705         /* add elements to pipeline */
5706         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
5707                 LOGE("Failed to add elements to pipeline\n");
5708                 goto INIT_ERROR;
5709         }
5710
5711
5712         /* linking elements in the bucket by added order. */
5713         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5714                 LOGE("Failed to link some elements\n");
5715                 goto INIT_ERROR;
5716         }
5717
5718
5719         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
5720         if (need_state_holder) {
5721                 /* create */
5722                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
5723                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
5724
5725                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
5726                         LOGE("fakesink element could not be created\n");
5727                         goto INIT_ERROR;
5728                 }
5729                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
5730
5731                 /* take ownership of fakesink. we are reusing it */
5732                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
5733
5734                 /* add */
5735                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
5736                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
5737                         LOGE("failed to add fakesink to bin\n");
5738                         goto INIT_ERROR;
5739                 }
5740         }
5741
5742         /* now we have completed mainbin. take it */
5743         player->pipeline->mainbin = mainbin;
5744
5745         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5746                 GstPad *srcpad = NULL;
5747
5748                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
5749                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
5750                         if (srcpad) {
5751                                 __mmplayer_gst_create_decoder(player,
5752                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
5753                                                                                                 srcpad,
5754                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
5755                                                                                                 "video_decodebin");
5756
5757                                 gst_object_unref(GST_OBJECT(srcpad));
5758                                 srcpad = NULL;
5759                         }
5760                 }
5761
5762                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
5763                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
5764                         if (srcpad) {
5765                                 __mmplayer_gst_create_decoder(player,
5766                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
5767                                                                                                 srcpad,
5768                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
5769                                                                                                 "audio_decodebin");
5770
5771                                 gst_object_unref(GST_OBJECT(srcpad));
5772                                 srcpad = NULL;
5773                         } // else error
5774                 } //  else error
5775
5776                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
5777                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
5778         }
5779
5780         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
5781         if (__mmplayer_check_subtitle(player)) {
5782                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
5783                         LOGE("fail to create text pipeline");
5784         }
5785
5786         /* connect bus callback */
5787         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
5788         if (!bus) {
5789                 LOGE("cannot get bus from pipeline.\n");
5790                 goto INIT_ERROR;
5791         }
5792
5793         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
5794
5795         player->context.thread_default = g_main_context_get_thread_default();
5796
5797         if (player->context.thread_default == NULL) {
5798                 player->context.thread_default = g_main_context_default();
5799                 LOGD("thread-default context is the global default context");
5800         }
5801         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
5802
5803         /* set sync handler to get tag synchronously */
5804         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
5805
5806         /* finished */
5807         gst_object_unref(GST_OBJECT(bus));
5808         g_list_free(element_bucket);
5809
5810         /* create gst bus_msb_cb thread */
5811         g_mutex_init(&player->bus_msg_thread_mutex);
5812         g_cond_init(&player->bus_msg_thread_cond);
5813         player->bus_msg_thread_exit = FALSE;
5814         player->bus_msg_thread =
5815                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
5816         if (!player->bus_msg_thread) {
5817                 LOGE("failed to create gst BUS msg thread");
5818                 g_mutex_clear(&player->bus_msg_thread_mutex);
5819                 g_cond_clear(&player->bus_msg_thread_cond);
5820                 goto INIT_ERROR;
5821         }
5822
5823         MMPLAYER_FLEAVE();
5824
5825         return MM_ERROR_NONE;
5826
5827 INIT_ERROR:
5828         __mmplayer_gst_destroy_pipeline(player);
5829         g_list_free(element_bucket);
5830
5831         if (mainbin) {
5832                 /* release element which are not added to bin */
5833                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
5834                         /* NOTE : skip pipeline */
5835                         if (mainbin[i].gst) {
5836                                 GstObject* parent = NULL;
5837                                 parent = gst_element_get_parent(mainbin[i].gst);
5838
5839                                 if (!parent) {
5840                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
5841                                         mainbin[i].gst = NULL;
5842                                 } else
5843                                         gst_object_unref(GST_OBJECT(parent));
5844                         }
5845                 }
5846
5847                 /* release pipeline with it's childs */
5848                 if (mainbin[MMPLAYER_M_PIPE].gst)
5849                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5850
5851                 MMPLAYER_FREEIF(mainbin);
5852         }
5853
5854         MMPLAYER_FREEIF(player->pipeline);
5855         return MM_ERROR_PLAYER_INTERNAL;
5856 }
5857
5858 static void
5859 __mmplayer_reset_gapless_state(mm_player_t* player)
5860 {
5861         MMPLAYER_FENTER();
5862         MMPLAYER_RETURN_IF_FAIL(player
5863                 && player->pipeline
5864                 && player->pipeline->audiobin
5865                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
5866
5867         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
5868
5869         MMPLAYER_FLEAVE();
5870         return;
5871 }
5872
5873 static int
5874 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
5875 {
5876         gint timeout = 0;
5877         int ret = MM_ERROR_NONE;
5878
5879         MMPLAYER_FENTER();
5880
5881         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
5882
5883         /* cleanup stuffs */
5884         MMPLAYER_FREEIF(player->type);
5885         player->have_dynamic_pad = FALSE;
5886         player->no_more_pad = FALSE;
5887         player->num_dynamic_pad = 0;
5888         player->demux_pad_index = 0;
5889         player->use_deinterleave = FALSE;
5890         player->max_audio_channels = 0;
5891         player->video_share_api_delta = 0;
5892         player->video_share_clock_delta = 0;
5893         player->video_hub_download_mode = 0;
5894
5895         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5896         player->subtitle_language_list = NULL;
5897         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5898
5899         __mmplayer_reset_gapless_state(player);
5900
5901         if (player->streamer) {
5902                 __mm_player_streaming_deinitialize(player->streamer);
5903                 __mm_player_streaming_destroy(player->streamer);
5904                 player->streamer = NULL;
5905         }
5906
5907         /* cleanup unlinked mime type */
5908         MMPLAYER_FREEIF(player->unlinked_audio_mime);
5909         MMPLAYER_FREEIF(player->unlinked_video_mime);
5910         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
5911
5912         /* cleanup running stuffs */
5913         __mmplayer_cancel_eos_timer(player);
5914
5915         /* cleanup gst stuffs */
5916         if (player->pipeline) {
5917                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
5918                 GstTagList* tag_list = player->pipeline->tag_list;
5919
5920                 /* first we need to disconnect all signal hander */
5921                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
5922
5923                 if (mainbin) {
5924                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
5925                         MMPlayerGstElement* videobin = player->pipeline->videobin;
5926                         MMPlayerGstElement* textbin = player->pipeline->textbin;
5927                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
5928                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
5929                         gst_object_unref(bus);
5930
5931                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5932                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
5933                         if (ret != MM_ERROR_NONE) {
5934                                 LOGE("fail to change state to NULL\n");
5935                                 return MM_ERROR_PLAYER_INTERNAL;
5936                         }
5937
5938                         LOGW("succeeded in changing state to NULL\n");
5939
5940                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5941
5942                         /* free fakesink */
5943                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
5944                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
5945
5946                         /* free avsysaudiosink
5947                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
5948                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
5949                         */
5950                         MMPLAYER_FREEIF(audiobin);
5951                         MMPLAYER_FREEIF(videobin);
5952                         MMPLAYER_FREEIF(textbin);
5953                         MMPLAYER_FREEIF(mainbin);
5954                 }
5955
5956                 if (tag_list)
5957                         gst_tag_list_free(tag_list);
5958
5959                 MMPLAYER_FREEIF(player->pipeline);
5960         }
5961         MMPLAYER_FREEIF(player->album_art);
5962
5963         if (player->v_stream_caps) {
5964                 gst_caps_unref(player->v_stream_caps);
5965                 player->v_stream_caps = NULL;
5966         }
5967         if (player->a_stream_caps) {
5968                 gst_caps_unref(player->a_stream_caps);
5969                 player->a_stream_caps = NULL;
5970         }
5971
5972         if (player->s_stream_caps) {
5973                 gst_caps_unref(player->s_stream_caps);
5974                 player->s_stream_caps = NULL;
5975         }
5976         _mmplayer_track_destroy(player);
5977
5978         if (player->sink_elements)
5979                 g_list_free(player->sink_elements);
5980         player->sink_elements = NULL;
5981
5982         if (player->bufmgr) {
5983                 tbm_bufmgr_deinit(player->bufmgr);
5984                 player->bufmgr = NULL;
5985         }
5986
5987         LOGW("finished destroy pipeline\n");
5988
5989         MMPLAYER_FLEAVE();
5990
5991         return ret;
5992 }
5993
5994 static int __gst_realize(mm_player_t* player)
5995 {
5996         gint timeout = 0;
5997         int ret = MM_ERROR_NONE;
5998
5999         MMPLAYER_FENTER();
6000
6001         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6002
6003         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
6004
6005         ret = __mmplayer_gst_create_pipeline(player);
6006         if (ret) {
6007                 LOGE("failed to create pipeline\n");
6008                 return ret;
6009         }
6010
6011         /* set pipeline state to READY */
6012         /* NOTE : state change to READY must be performed sync. */
6013         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6014         ret = __mmplayer_gst_set_state(player,
6015                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
6016
6017         if (ret != MM_ERROR_NONE) {
6018                 /* return error if failed to set state */
6019                 LOGE("failed to set READY state");
6020                 return ret;
6021         }
6022
6023         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
6024
6025         /* create dot before error-return. for debugging */
6026         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
6027
6028         MMPLAYER_FLEAVE();
6029
6030         return ret;
6031 }
6032
6033 static int __gst_unrealize(mm_player_t* player)
6034 {
6035         int ret = MM_ERROR_NONE;
6036
6037         MMPLAYER_FENTER();
6038
6039         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6040
6041         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
6042         MMPLAYER_PRINT_STATE(player);
6043
6044         /* release miscellaneous information */
6045         __mmplayer_release_misc(player);
6046
6047         /* destroy pipeline */
6048         ret = __mmplayer_gst_destroy_pipeline(player);
6049         if (ret != MM_ERROR_NONE) {
6050                 LOGE("failed to destory pipeline\n");
6051                 return ret;
6052         }
6053
6054         /* release miscellaneous information.
6055            these info needs to be released after pipeline is destroyed. */
6056         __mmplayer_release_misc_post(player);
6057
6058         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
6059
6060         MMPLAYER_FLEAVE();
6061
6062         return ret;
6063 }
6064
6065 static int
6066 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
6067 {
6068         MMPLAYER_FENTER();
6069
6070         if (!player) {
6071                 LOGW("set_message_callback is called with invalid player handle\n");
6072                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6073         }
6074
6075         player->msg_cb = callback;
6076         player->msg_cb_param = user_param;
6077
6078         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
6079
6080         MMPLAYER_FLEAVE();
6081
6082         return MM_ERROR_NONE;
6083 }
6084
6085 static int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
6086 {
6087         int ret = MM_ERROR_PLAYER_INVALID_URI;
6088         char *path = NULL;
6089
6090         MMPLAYER_FENTER();
6091
6092         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
6093         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
6094         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
6095
6096         memset(data, 0, sizeof(MMPlayerParseProfile));
6097
6098         if ((path = strstr(uri, "es_buff://"))) {
6099                 if (strlen(path)) {
6100                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6101                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
6102                         ret = MM_ERROR_NONE;
6103                 }
6104         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
6105                 if (strlen(path)) {
6106                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6107                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6108                         ret = MM_ERROR_NONE;
6109                 }
6110         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
6111                 if (strlen(path)) {
6112                         gchar *tmp = NULL;
6113                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6114                         tmp = g_ascii_strdown(uri, strlen(uri));
6115
6116                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
6117                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
6118                         else
6119                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
6120
6121                         ret = MM_ERROR_NONE;
6122                         g_free(tmp);
6123                 }
6124         } else if ((path = strstr(uri, "rtspu://"))) {
6125                 if (strlen(path)) {
6126                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6127                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6128                         ret = MM_ERROR_NONE;
6129                 }
6130         } else if ((path = strstr(uri, "rtspr://"))) {
6131                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
6132                 char *separater = strstr(path, "*");
6133
6134                 if (separater) {
6135                         int urgent_len = 0;
6136                         char *urgent = separater + strlen("*");
6137
6138                         if ((urgent_len = strlen(urgent))) {
6139                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
6140                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
6141                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6142                                 ret = MM_ERROR_NONE;
6143                         }
6144                 }
6145         } else if ((path = strstr(uri, "mms://"))) {
6146                 if (strlen(path)) {
6147                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6148                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
6149                         ret = MM_ERROR_NONE;
6150                 }
6151         } else if ((path = strstr(uri, "mem://"))) {
6152                 if (strlen(path)) {
6153                         int mem_size = 0;
6154                         char *buffer = NULL;
6155                         char *seperator = strchr(path, ',');
6156                         char ext[100] = {0,}, size[100] = {0,};
6157
6158                         if (seperator) {
6159                                 if ((buffer = strstr(path, "ext="))) {
6160                                         buffer += strlen("ext=");
6161
6162                                         if (strlen(buffer)) {
6163                                                 strncpy(ext, buffer, 99);
6164
6165                                                 if ((seperator = strchr(ext, ','))
6166                                                         || (seperator = strchr(ext, ' '))
6167                                                         || (seperator = strchr(ext, '\0'))) {
6168                                                         seperator[0] = '\0';
6169                                                 }
6170                                         }
6171                                 }
6172
6173                                 if ((buffer = strstr(path, "size="))) {
6174                                         buffer += strlen("size=");
6175
6176                                         if (strlen(buffer) > 0) {
6177                                                 strncpy(size, buffer, 99);
6178
6179                                                 if ((seperator = strchr(size, ','))
6180                                                         || (seperator = strchr(size, ' '))
6181                                                         || (seperator = strchr(size, '\0'))) {
6182                                                         seperator[0] = '\0';
6183                                                 }
6184
6185                                                 mem_size = atoi(size);
6186                                         }
6187                                 }
6188                         }
6189
6190                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
6191                         if (mem_size && param) {
6192                                 if (data->input_mem.buf)
6193                                         free(data->input_mem.buf);
6194                                 data->input_mem.buf = malloc(mem_size);
6195
6196                                 if (data->input_mem.buf) {
6197                                         memcpy(data->input_mem.buf, param, mem_size);
6198                                         data->input_mem.len = mem_size;
6199                                         ret = MM_ERROR_NONE;
6200                                 } else {
6201                                         LOGE("failed to alloc mem %d", mem_size);
6202                                         ret = MM_ERROR_PLAYER_INTERNAL;
6203                                 }
6204
6205                                 data->input_mem.offset = 0;
6206                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
6207                         }
6208                 }
6209         } else {
6210                 gchar *location = NULL;
6211                 GError *err = NULL;
6212
6213                 if ((path = strstr(uri, "file://"))) {
6214
6215                         location = g_filename_from_uri(uri, NULL, &err);
6216
6217                         if (!location || (err != NULL)) {
6218                           LOGE("Invalid URI '%s' for filesrc: %s", path,
6219                                  (err != NULL) ? err->message : "unknown error");
6220
6221                           if (err) g_error_free(err);
6222                           if (location) g_free(location);
6223
6224                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6225                           goto exit;
6226                         }
6227
6228                         LOGD("path from uri: %s", location);
6229                 }
6230
6231                 path = (location != NULL) ? (location) : ((char*)uri);
6232                 int file_stat = MM_ERROR_NONE;
6233
6234                 file_stat = util_exist_file_path(path);
6235
6236                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
6237                 if (file_stat == MM_ERROR_NONE) {
6238                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
6239
6240                         if (util_is_sdp_file(path)) {
6241                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
6242                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6243                         } else {
6244                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
6245                         }
6246                         ret = MM_ERROR_NONE;
6247                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
6248                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
6249                 } else {
6250                         LOGE("invalid uri, could not play..\n");
6251                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6252                 }
6253
6254                 if (location) g_free(location);
6255         }
6256
6257 exit:
6258         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
6259                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
6260         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
6261                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
6262
6263         /* dump parse result */
6264         SECURE_LOGW("incomming uri : %s\n", uri);
6265         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
6266                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
6267
6268         MMPLAYER_FLEAVE();
6269
6270         return ret;
6271 }
6272
6273 static gboolean
6274 __mmplayer_can_do_interrupt(mm_player_t *player)
6275 {
6276         if (!player || !player->pipeline || !player->attrs) {
6277                 LOGW("not initialized");
6278                 goto FAILED;
6279         }
6280
6281         if (player->set_mode.pcm_extraction) {
6282                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
6283                 goto FAILED;
6284         }
6285
6286         /* check if seeking */
6287         if (player->seek_state != MMPLAYER_SEEK_NONE) {
6288                 MMMessageParamType msg_param;
6289                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6290                 msg_param.code = MM_ERROR_PLAYER_SEEK;
6291                 player->seek_state = MMPLAYER_SEEK_NONE;
6292                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6293                 goto FAILED;
6294         }
6295
6296         /* check other thread */
6297         if (!MMPLAYER_CMD_TRYLOCK(player)) {
6298                 LOGW("locked already, cmd state : %d", player->cmd);
6299
6300                 /* check application command */
6301                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
6302                         LOGW("playing.. should wait cmd lock then, will be interrupted");
6303
6304                         /* lock will be released at mrp_resource_release_cb() */
6305                         MMPLAYER_CMD_LOCK(player);
6306                         goto INTERRUPT;
6307                 }
6308                 LOGW("nothing to do");
6309                 goto FAILED;
6310         } else {
6311                 LOGW("can interrupt immediately");
6312                 goto INTERRUPT;
6313         }
6314
6315 FAILED:    /* with CMD UNLOCKED */
6316         return FALSE;
6317
6318 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
6319         return TRUE;
6320 }
6321
6322 static int
6323 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
6324                 void *user_data)
6325 {
6326         mm_player_t *player = NULL;
6327
6328         MMPLAYER_FENTER();
6329
6330         if (user_data == NULL) {
6331                 LOGE("- user_data is null\n");
6332                 return FALSE;
6333         }
6334         player = (mm_player_t *)user_data;
6335
6336         /* do something to release resource here.
6337          * player stop and interrupt forwarding */
6338         if (!__mmplayer_can_do_interrupt(player)) {
6339                 LOGW("no need to interrupt, so leave");
6340         } else {
6341                 MMMessageParamType msg = {0, };
6342                 gint64 pos = 0;
6343
6344                 player->interrupted_by_resource = TRUE;
6345
6346                 /* get last play position */
6347                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
6348                         LOGW("failed to get play position.");
6349                 } else {
6350                         msg.union_type = MM_MSG_UNION_TIME;
6351                         msg.time.elapsed = pos;
6352                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
6353                 }
6354                 LOGD("video resource conflict so, resource will be freed by unrealizing");
6355                 if (_mmplayer_unrealize((MMHandleType)player))
6356                         LOGW("failed to unrealize");
6357
6358                 /* lock is called in __mmplayer_can_do_interrupt() */
6359                 MMPLAYER_CMD_UNLOCK(player);
6360         }
6361
6362         if (res == player->video_overlay_resource)
6363                 player->video_overlay_resource = FALSE;
6364         else
6365                 player->video_decoder_resource = FALSE;
6366
6367         MMPLAYER_FLEAVE();
6368
6369         return FALSE;
6370 }
6371
6372 int
6373 _mmplayer_create_player(MMHandleType handle)
6374 {
6375         int ret = MM_ERROR_PLAYER_INTERNAL;
6376         bool enabled = false;
6377
6378         mm_player_t* player = MM_PLAYER_CAST(handle);
6379
6380         MMPLAYER_FENTER();
6381
6382         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6383
6384         /* initialize player state */
6385         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
6386         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
6387         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
6388         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
6389
6390         /* check current state */
6391         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
6392
6393         /* construct attributes */
6394         player->attrs = _mmplayer_construct_attribute(handle);
6395
6396         if (!player->attrs) {
6397                 LOGE("Failed to construct attributes\n");
6398                 return ret;
6399         }
6400
6401         /* initialize gstreamer with configured parameter */
6402         if (!__mmplayer_init_gstreamer(player)) {
6403                 LOGE("Initializing gstreamer failed\n");
6404                 _mmplayer_deconstruct_attribute(handle);
6405                 return ret;
6406         }
6407
6408         /* create lock. note that g_tread_init() has already called in gst_init() */
6409         g_mutex_init(&player->fsink_lock);
6410
6411         /* create update tag lock */
6412         g_mutex_init(&player->update_tag_lock);
6413
6414         /* create next play mutex */
6415         g_mutex_init(&player->next_play_thread_mutex);
6416
6417         /* create next play cond */
6418         g_cond_init(&player->next_play_thread_cond);
6419
6420         /* create next play thread */
6421         player->next_play_thread =
6422                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
6423         if (!player->next_play_thread) {
6424                 LOGE("failed to create next play thread");
6425                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
6426                 g_mutex_clear(&player->next_play_thread_mutex);
6427                 g_cond_clear(&player->next_play_thread_cond);
6428                 goto ERROR;
6429         }
6430
6431         player->bus_msg_q = g_queue_new();
6432         if (!player->bus_msg_q) {
6433                 LOGE("failed to create queue for bus_msg");
6434                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
6435                 goto ERROR;
6436         }
6437
6438         ret = _mmplayer_initialize_video_capture(player);
6439         if (ret != MM_ERROR_NONE) {
6440                 LOGE("failed to initialize video capture\n");
6441                 goto ERROR;
6442         }
6443
6444         /* initialize resource manager */
6445         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
6446                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
6447                         &player->resource_manager)) {
6448                 LOGE("failed to initialize resource manager\n");
6449                 goto ERROR;
6450         }
6451
6452         if (MMPLAYER_IS_HTTP_PD(player)) {
6453                 player->pd_downloader = NULL;
6454                 player->pd_file_save_path = NULL;
6455         }
6456
6457         /* create video bo lock and cond */
6458         g_mutex_init(&player->video_bo_mutex);
6459         g_cond_init(&player->video_bo_cond);
6460
6461         /* create media stream callback mutex */
6462         g_mutex_init(&player->media_stream_cb_lock);
6463
6464         /* create subtitle info lock and cond */
6465         g_mutex_init(&player->subtitle_info_mutex);
6466         g_cond_init(&player->subtitle_info_cond);
6467
6468         player->streaming_type = STREAMING_SERVICE_NONE;
6469
6470         /* give default value of audio effect setting */
6471         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
6472         player->sound.rg_enable = false;
6473         player->playback_rate = DEFAULT_PLAYBACK_RATE;
6474
6475         player->play_subtitle = FALSE;
6476         player->use_deinterleave = FALSE;
6477         player->max_audio_channels = 0;
6478         player->video_share_api_delta = 0;
6479         player->video_share_clock_delta = 0;
6480         player->has_closed_caption = FALSE;
6481         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
6482         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
6483         player->pending_resume = FALSE;
6484         if (player->ini.dump_element_keyword[0][0] == '\0')
6485                 player->ini.set_dump_element_flag = FALSE;
6486         else
6487                 player->ini.set_dump_element_flag = TRUE;
6488
6489         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6490         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6491         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6492
6493         /* Set video360 settings to their defaults for just-created player.
6494          * */
6495
6496         player->is_360_feature_enabled = FALSE;
6497         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
6498                 LOGI("spherical feature info: %d", enabled);
6499                 if (enabled)
6500                         player->is_360_feature_enabled = TRUE;
6501         } else {
6502                 LOGE("failed to get spherical feature info");
6503         }
6504
6505         player->is_content_spherical = FALSE;
6506         player->is_video360_enabled = TRUE;
6507         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
6508         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
6509         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
6510         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
6511         player->video360_zoom = 1.0f;
6512         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
6513         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
6514
6515         /* set player state to null */
6516         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
6517         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
6518
6519         return MM_ERROR_NONE;
6520
6521 ERROR:
6522         /* free lock */
6523         g_mutex_clear(&player->fsink_lock);
6524
6525         /* free update tag lock */
6526         g_mutex_clear(&player->update_tag_lock);
6527
6528         g_queue_free(player->bus_msg_q);
6529
6530         /* free next play thread */
6531         if (player->next_play_thread) {
6532                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
6533                 player->next_play_thread_exit = TRUE;
6534                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
6535                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
6536
6537                 g_thread_join(player->next_play_thread);
6538                 player->next_play_thread = NULL;
6539
6540                 g_mutex_clear(&player->next_play_thread_mutex);
6541                 g_cond_clear(&player->next_play_thread_cond);
6542         }
6543
6544         /* release attributes */
6545         _mmplayer_deconstruct_attribute(handle);
6546
6547         MMPLAYER_FLEAVE();
6548
6549         return ret;
6550 }
6551
6552 static gboolean
6553 __mmplayer_init_gstreamer(mm_player_t* player)
6554 {
6555         static gboolean initialized = FALSE;
6556         static const int max_argc = 50;
6557         gint* argc = NULL;
6558         gchar** argv = NULL;
6559         gchar** argv2 = NULL;
6560         GError *err = NULL;
6561         int i = 0;
6562         int arg_count = 0;
6563
6564         if (initialized) {
6565                 LOGD("gstreamer already initialized.\n");
6566                 return TRUE;
6567         }
6568
6569         /* alloc */
6570         argc = malloc(sizeof(int));
6571         argv = malloc(sizeof(gchar*) * max_argc);
6572         argv2 = malloc(sizeof(gchar*) * max_argc);
6573
6574         if (!argc || !argv || !argv2)
6575                 goto ERROR;
6576
6577         memset(argv, 0, sizeof(gchar*) * max_argc);
6578         memset(argv2, 0, sizeof(gchar*) * max_argc);
6579
6580         /* add initial */
6581         *argc = 1;
6582         argv[0] = g_strdup("mmplayer");
6583
6584         /* add gst_param */
6585         for (i = 0; i < 5; i++) {
6586                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
6587                 if (strlen(player->ini.gst_param[i]) > 0) {
6588                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
6589                         (*argc)++;
6590                 }
6591         }
6592
6593         /* we would not do fork for scanning plugins */
6594         argv[*argc] = g_strdup("--gst-disable-registry-fork");
6595         (*argc)++;
6596
6597         /* check disable registry scan */
6598         if (player->ini.skip_rescan) {
6599                 argv[*argc] = g_strdup("--gst-disable-registry-update");
6600                 (*argc)++;
6601         }
6602
6603         /* check disable segtrap */
6604         if (player->ini.disable_segtrap) {
6605                 argv[*argc] = g_strdup("--gst-disable-segtrap");
6606                 (*argc)++;
6607         }
6608
6609         LOGD("initializing gstreamer with following parameter\n");
6610         LOGD("argc : %d\n", *argc);
6611         arg_count = *argc;
6612
6613         for (i = 0; i < arg_count; i++) {
6614                 argv2[i] = argv[i];
6615                 LOGD("argv[%d] : %s\n", i, argv2[i]);
6616         }
6617
6618         /* initializing gstreamer */
6619         if (!gst_init_check(argc, &argv, &err)) {
6620                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6621                 if (err)
6622                         g_error_free(err);
6623
6624                 goto ERROR;
6625         }
6626         /* release */
6627         for (i = 0; i < arg_count; i++) {
6628                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
6629                 MMPLAYER_FREEIF(argv2[i]);
6630         }
6631
6632         MMPLAYER_FREEIF(argv);
6633         MMPLAYER_FREEIF(argv2);
6634         MMPLAYER_FREEIF(argc);
6635
6636         /* done */
6637         initialized = TRUE;
6638
6639         return TRUE;
6640
6641 ERROR:
6642
6643         /* release */
6644         for (i = 0; i < arg_count; i++) {
6645                 LOGD("free[%d] : %s\n", i, argv2[i]);
6646                 MMPLAYER_FREEIF(argv2[i]);
6647         }
6648
6649         MMPLAYER_FREEIF(argv);
6650         MMPLAYER_FREEIF(argv2);
6651         MMPLAYER_FREEIF(argc);
6652
6653         return FALSE;
6654 }
6655
6656 int
6657 __mmplayer_destroy_streaming_ext(mm_player_t* player)
6658 {
6659         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6660
6661         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
6662                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
6663                 MMPLAYER_FREEIF(player->pd_file_save_path);
6664         }
6665
6666         return MM_ERROR_NONE;
6667 }
6668
6669 static void
6670 __mmplayer_check_async_state_transition(mm_player_t* player)
6671 {
6672         GstState element_state = GST_STATE_VOID_PENDING;
6673         GstState element_pending_state = GST_STATE_VOID_PENDING;
6674         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
6675         GstElement * element = NULL;
6676         gboolean async = FALSE;
6677
6678         /* check player handle */
6679         MMPLAYER_RETURN_IF_FAIL(player &&
6680                                                 player->pipeline &&
6681                                                 player->pipeline->mainbin &&
6682                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
6683
6684         if (player->attrs)
6685                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6686
6687         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
6688                 LOGD("don't need to check the pipeline state");
6689                 return;
6690         }
6691
6692         MMPLAYER_PRINT_STATE(player);
6693
6694         /* wait for state transition */
6695         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
6696         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
6697
6698         if (ret == GST_STATE_CHANGE_FAILURE) {
6699                 LOGE(" [%s] state : %s   pending : %s \n",
6700                         GST_ELEMENT_NAME(element),
6701                         gst_element_state_get_name(element_state),
6702                         gst_element_state_get_name(element_pending_state));
6703
6704                 /* dump state of all element */
6705                 __mmplayer_dump_pipeline_state(player);
6706
6707                 return;
6708         }
6709
6710         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
6711         return;
6712 }
6713
6714 int
6715 _mmplayer_destroy(MMHandleType handle)
6716 {
6717         mm_player_t* player = MM_PLAYER_CAST(handle);
6718
6719         MMPLAYER_FENTER();
6720
6721         /* check player handle */
6722         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6723
6724         /* destroy can called at anytime */
6725         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
6726
6727         /* check async state transition */
6728         __mmplayer_check_async_state_transition(player);
6729
6730         __mmplayer_destroy_streaming_ext(player);
6731
6732         /* release next play thread */
6733         if (player->next_play_thread) {
6734                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
6735                 player->next_play_thread_exit = TRUE;
6736                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
6737                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
6738
6739                 LOGD("waitting for next play thread exit\n");
6740                 g_thread_join(player->next_play_thread);
6741                 g_mutex_clear(&player->next_play_thread_mutex);
6742                 g_cond_clear(&player->next_play_thread_cond);
6743                 LOGD("next play thread released\n");
6744         }
6745
6746         _mmplayer_release_video_capture(player);
6747
6748         /* de-initialize resource manager */
6749         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
6750                         player->resource_manager))
6751                 LOGE("failed to deinitialize resource manager\n");
6752
6753         /* release pipeline */
6754         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
6755                 LOGE("failed to destory pipeline\n");
6756                 return MM_ERROR_PLAYER_INTERNAL;
6757         }
6758
6759         g_queue_free(player->bus_msg_q);
6760
6761         /* release subtitle info lock and cond */
6762         g_mutex_clear(&player->subtitle_info_mutex);
6763         g_cond_clear(&player->subtitle_info_cond);
6764
6765         __mmplayer_release_dump_list(player->dump_list);
6766
6767         /* release miscellaneous information */
6768         __mmplayer_release_misc(player);
6769
6770         /* release miscellaneous information.
6771            these info needs to be released after pipeline is destroyed. */
6772         __mmplayer_release_misc_post(player);
6773
6774         /* release attributes */
6775         _mmplayer_deconstruct_attribute(handle);
6776
6777         /* release lock */
6778         g_mutex_clear(&player->fsink_lock);
6779
6780         /* release lock */
6781         g_mutex_clear(&player->update_tag_lock);
6782
6783         /* release video bo lock and cond */
6784         g_mutex_clear(&player->video_bo_mutex);
6785         g_cond_clear(&player->video_bo_cond);
6786
6787         /* release media stream callback lock */
6788         g_mutex_clear(&player->media_stream_cb_lock);
6789
6790         MMPLAYER_FLEAVE();
6791
6792         return MM_ERROR_NONE;
6793 }
6794
6795 int
6796 __mmplayer_realize_streaming_ext(mm_player_t* player)
6797 {
6798         int ret = MM_ERROR_NONE;
6799
6800         MMPLAYER_FENTER();
6801         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6802
6803         if (MMPLAYER_IS_HTTP_PD(player)) {
6804                 gboolean bret = FALSE;
6805
6806                 player->pd_downloader = _mmplayer_create_pd_downloader();
6807                 if (!player->pd_downloader) {
6808                         LOGE("Unable to create PD Downloader...");
6809                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6810                 }
6811
6812                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6813
6814                 if (FALSE == bret) {
6815                         LOGE("Unable to create PD Downloader...");
6816                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6817                 }
6818         }
6819
6820         MMPLAYER_FLEAVE();
6821         return ret;
6822 }
6823
6824 int
6825 _mmplayer_realize(MMHandleType hplayer)
6826 {
6827         mm_player_t* player = (mm_player_t*)hplayer;
6828         char *uri = NULL;
6829         void *param = NULL;
6830         MMHandleType attrs = 0;
6831         int ret = MM_ERROR_NONE;
6832
6833         MMPLAYER_FENTER();
6834
6835         /* check player handle */
6836         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
6837
6838         /* check current state */
6839         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
6840
6841         attrs = MMPLAYER_GET_ATTRS(player);
6842         if (!attrs) {
6843                 LOGE("fail to get attributes.\n");
6844                 return MM_ERROR_PLAYER_INTERNAL;
6845         }
6846         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6847         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
6848
6849         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
6850                 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
6851
6852                 if (ret != MM_ERROR_NONE) {
6853                         LOGE("failed to parse profile\n");
6854                         return ret;
6855                 }
6856         }
6857
6858         if (uri && (strstr(uri, "es_buff://"))) {
6859                 if (strstr(uri, "es_buff://push_mode"))
6860                         player->es_player_push_mode = TRUE;
6861                 else
6862                         player->es_player_push_mode = FALSE;
6863         }
6864
6865         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
6866                 LOGW("mms protocol is not supported format.\n");
6867                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6868         }
6869
6870         if (MMPLAYER_IS_STREAMING(player))
6871                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
6872         else
6873                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
6874
6875         player->smooth_streaming = FALSE;
6876         player->videodec_linked  = 0;
6877         player->videosink_linked = 0;
6878         player->audiodec_linked  = 0;
6879         player->audiosink_linked = 0;
6880         player->textsink_linked = 0;
6881         player->is_external_subtitle_present = FALSE;
6882         player->is_external_subtitle_added_now = FALSE;
6883         /* set the subtitle ON default */
6884         player->is_subtitle_off = FALSE;
6885
6886         /* realize pipeline */
6887         ret = __gst_realize(player);
6888         if (ret != MM_ERROR_NONE)
6889                 LOGE("fail to realize the player.\n");
6890         else
6891                 ret = __mmplayer_realize_streaming_ext(player);
6892
6893         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
6894
6895         MMPLAYER_FLEAVE();
6896
6897         return ret;
6898 }
6899
6900 int
6901 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
6902 {
6903         MMPLAYER_FENTER();
6904         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6905
6906         /* destroy can called at anytime */
6907         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6908                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
6909
6910         MMPLAYER_FLEAVE();
6911         return MM_ERROR_NONE;
6912 }
6913
6914 int
6915 _mmplayer_unrealize(MMHandleType hplayer)
6916 {
6917         mm_player_t* player = (mm_player_t*)hplayer;
6918         int ret = MM_ERROR_NONE;
6919
6920         MMPLAYER_FENTER();
6921
6922         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6923
6924         MMPLAYER_CMD_UNLOCK(player);
6925         /* destroy the gst bus msg thread which is created during realize.
6926            this funct have to be called before getting cmd lock. */
6927         __mmplayer_bus_msg_thread_destroy(player);
6928         MMPLAYER_CMD_LOCK(player);
6929
6930         /* check current state */
6931         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
6932
6933         /* check async state transition */
6934         __mmplayer_check_async_state_transition(player);
6935
6936         __mmplayer_unrealize_streaming_ext(player);
6937
6938         /* unrealize pipeline */
6939         ret = __gst_unrealize(player);
6940
6941         /* set asm stop if success */
6942         if (MM_ERROR_NONE == ret) {
6943                 if (!player->interrupted_by_resource) {
6944                         if (player->video_decoder_resource != NULL) {
6945                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
6946                                                 player->video_decoder_resource);
6947                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6948                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
6949                                 else
6950                                         player->video_decoder_resource = NULL;
6951                         }
6952
6953                         if (player->video_overlay_resource != NULL) {
6954                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
6955                                                 player->video_overlay_resource);
6956                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6957                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
6958                                 else
6959                                         player->video_overlay_resource = NULL;
6960                         }
6961
6962                         ret = mm_resource_manager_commit(player->resource_manager);
6963                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6964                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
6965                 }
6966         } else
6967                 LOGE("failed and don't change asm state to stop");
6968
6969         MMPLAYER_FLEAVE();
6970
6971         return ret;
6972 }
6973
6974 int
6975 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
6976 {
6977         mm_player_t* player = (mm_player_t*)hplayer;
6978
6979         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6980
6981         return __gst_set_message_callback(player, callback, user_param);
6982 }
6983
6984 int
6985 _mmplayer_get_state(MMHandleType hplayer, int* state)
6986 {
6987         mm_player_t *player = (mm_player_t*)hplayer;
6988
6989         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
6990
6991         *state = MMPLAYER_CURRENT_STATE(player);
6992
6993         return MM_ERROR_NONE;
6994 }
6995
6996
6997 int
6998 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
6999 {
7000         mm_player_t* player = (mm_player_t*) hplayer;
7001         GstElement* vol_element = NULL;
7002         int i = 0;
7003
7004         MMPLAYER_FENTER();
7005
7006         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7007
7008         LOGD("volume [L]=%f:[R]=%f\n",
7009                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
7010
7011         /* invalid factor range or not */
7012         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
7013                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
7014                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
7015                         return MM_ERROR_INVALID_ARGUMENT;
7016                 }
7017         }
7018
7019         /* not support to set other value into each channel */
7020         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
7021                 return MM_ERROR_INVALID_ARGUMENT;
7022
7023         /* Save volume to handle. Currently the first array element will be saved. */
7024         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
7025
7026         /* check pipeline handle */
7027         if (!player->pipeline || !player->pipeline->audiobin) {
7028                 LOGD("audiobin is not created yet\n");
7029                 LOGD("but, current stored volume will be set when it's created.\n");
7030
7031                 /* NOTE : stored volume will be used in create_audiobin
7032                  * returning MM_ERROR_NONE here makes application to able to
7033                  * set volume at anytime.
7034                  */
7035                 return MM_ERROR_NONE;
7036         }
7037
7038         /* setting volume to volume element */
7039         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7040
7041         if (vol_element) {
7042                 LOGD("volume is set [%f]\n", player->sound.volume);
7043                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
7044         }
7045
7046         MMPLAYER_FLEAVE();
7047
7048         return MM_ERROR_NONE;
7049 }
7050
7051
7052 int
7053 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
7054 {
7055         mm_player_t* player = (mm_player_t*) hplayer;
7056         int i = 0;
7057
7058         MMPLAYER_FENTER();
7059
7060         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7061         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
7062
7063         /* returning stored volume */
7064         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
7065                 volume->level[i] = player->sound.volume;
7066
7067         MMPLAYER_FLEAVE();
7068
7069         return MM_ERROR_NONE;
7070 }
7071
7072 int
7073 _mmplayer_set_mute(MMHandleType hplayer, int mute)
7074 {
7075         mm_player_t* player = (mm_player_t*) hplayer;
7076         GstElement* vol_element = NULL;
7077
7078         MMPLAYER_FENTER();
7079
7080         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7081
7082         /* mute value shoud 0 or 1 */
7083         if (mute != 0 && mute != 1) {
7084                 LOGE("bad mute value\n");
7085
7086                 /* FIXIT : definitly, we need _BAD_PARAM error code */
7087                 return MM_ERROR_INVALID_ARGUMENT;
7088         }
7089
7090         player->sound.mute = mute;
7091
7092         /* just hold mute value if pipeline is not ready */
7093         if (!player->pipeline || !player->pipeline->audiobin) {
7094                 LOGD("pipeline is not ready. holding mute value\n");
7095                 return MM_ERROR_NONE;
7096         }
7097
7098         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7099
7100         /* NOTE : volume will only created when the bt is enabled */
7101         if (vol_element) {
7102                 LOGD("mute : %d\n", mute);
7103                 g_object_set(vol_element, "mute", mute, NULL);
7104         } else
7105                 LOGD("volume elemnet is not created. using volume in audiosink\n");
7106
7107         MMPLAYER_FLEAVE();
7108
7109         return MM_ERROR_NONE;
7110 }
7111
7112 int
7113 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
7114 {
7115         mm_player_t* player = (mm_player_t*) hplayer;
7116
7117         MMPLAYER_FENTER();
7118
7119         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7120         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
7121
7122         /* just hold mute value if pipeline is not ready */
7123         if (!player->pipeline || !player->pipeline->audiobin) {
7124                 LOGD("pipeline is not ready. returning stored value\n");
7125                 *pmute = player->sound.mute;
7126                 return MM_ERROR_NONE;
7127         }
7128
7129         *pmute = player->sound.mute;
7130
7131         MMPLAYER_FLEAVE();
7132
7133         return MM_ERROR_NONE;
7134 }
7135
7136 int
7137 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
7138 {
7139         mm_player_t* player = (mm_player_t*) hplayer;
7140
7141         MMPLAYER_FENTER();
7142
7143         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7144
7145         player->video_stream_changed_cb = callback;
7146         player->video_stream_changed_cb_user_param = user_param;
7147         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
7148
7149         MMPLAYER_FLEAVE();
7150
7151         return MM_ERROR_NONE;
7152 }
7153
7154 int
7155 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
7156 {
7157         mm_player_t* player = (mm_player_t*) hplayer;
7158
7159         MMPLAYER_FENTER();
7160
7161         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7162
7163         player->audio_stream_changed_cb = callback;
7164         player->audio_stream_changed_cb_user_param = user_param;
7165         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
7166
7167         MMPLAYER_FLEAVE();
7168
7169         return MM_ERROR_NONE;
7170 }
7171
7172 int
7173 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
7174 {
7175         mm_player_t* player = (mm_player_t*) hplayer;
7176
7177         MMPLAYER_FENTER();
7178
7179         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7180
7181         player->audio_stream_render_cb_ex = callback;
7182         player->audio_stream_cb_user_param = user_param;
7183         player->audio_stream_sink_sync = sync;
7184         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);
7185
7186         MMPLAYER_FLEAVE();
7187
7188         return MM_ERROR_NONE;
7189 }
7190
7191 int
7192 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
7193 {
7194         mm_player_t* player = (mm_player_t*) hplayer;
7195
7196         MMPLAYER_FENTER();
7197
7198         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7199
7200         if (callback && !player->bufmgr)
7201                 player->bufmgr = tbm_bufmgr_init(-1);
7202
7203         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
7204         player->video_stream_cb = callback;
7205         player->video_stream_cb_user_param = user_param;
7206
7207         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
7208
7209         MMPLAYER_FLEAVE();
7210
7211         return MM_ERROR_NONE;
7212 }
7213
7214 int
7215 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
7216 {
7217         mm_player_t* player = (mm_player_t*) hplayer;
7218
7219         MMPLAYER_FENTER();
7220
7221         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7222
7223         player->audio_stream_cb = callback;
7224         player->audio_stream_cb_user_param = user_param;
7225         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
7226
7227         MMPLAYER_FLEAVE();
7228
7229         return MM_ERROR_NONE;
7230 }
7231
7232 static int
7233 __mmplayer_start_streaming_ext(mm_player_t *player)
7234 {
7235         gint ret = MM_ERROR_NONE;
7236
7237         MMPLAYER_FENTER();
7238         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7239
7240         if (MMPLAYER_IS_HTTP_PD(player)) {
7241                 if (!player->pd_downloader) {
7242                         ret = __mmplayer_realize_streaming_ext(player);
7243
7244                         if (ret != MM_ERROR_NONE) {
7245                                 LOGE("failed to realize streaming ext\n");
7246                                 return ret;
7247                         }
7248                 }
7249
7250                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
7251                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
7252                         if (!ret) {
7253                                 LOGE("ERROR while starting PD...\n");
7254                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7255                         }
7256                         ret = MM_ERROR_NONE;
7257                 }
7258         }
7259
7260         MMPLAYER_FLEAVE();
7261         return ret;
7262 }
7263
7264 int
7265 _mmplayer_start(MMHandleType hplayer)
7266 {
7267         mm_player_t* player = (mm_player_t*) hplayer;
7268         gint ret = MM_ERROR_NONE;
7269
7270         MMPLAYER_FENTER();
7271
7272         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7273
7274         /* check current state */
7275         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
7276
7277         /* PD - start streaming */
7278         ret = __mmplayer_start_streaming_ext(player);
7279         if (ret != MM_ERROR_NONE) {
7280                 LOGE("failed to start streaming ext 0x%X", ret);
7281                 return ret;
7282         }
7283
7284         /* start pipeline */
7285         ret = __mmplayer_gst_start(player);
7286         if (ret != MM_ERROR_NONE)
7287                 LOGE("failed to start player.\n");
7288
7289         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7290                 LOGD("force playing start even during buffering");
7291                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7292         }
7293
7294         MMPLAYER_FLEAVE();
7295
7296         return ret;
7297 }
7298
7299 /* NOTE: post "not supported codec message" to application
7300  * when one codec is not found during AUTOPLUGGING in MSL.
7301  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
7302  * And, if any codec is not found, don't send message here.
7303  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
7304  */
7305 int
7306 __mmplayer_handle_missed_plugin(mm_player_t* player)
7307 {
7308         MMMessageParamType msg_param;
7309         memset(&msg_param, 0, sizeof(MMMessageParamType));
7310         gboolean post_msg_direct = FALSE;
7311
7312         MMPLAYER_FENTER();
7313
7314         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7315
7316         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
7317                         player->not_supported_codec, player->can_support_codec);
7318
7319         if (player->not_found_demuxer) {
7320                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7321                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
7322
7323                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7324                 MMPLAYER_FREEIF(msg_param.data);
7325
7326                 return MM_ERROR_NONE;
7327         }
7328
7329         if (player->not_supported_codec) {
7330                 if (player->can_support_codec) {
7331                         // There is one codec to play
7332                         post_msg_direct = TRUE;
7333                 } else {
7334                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
7335                                 post_msg_direct = TRUE;
7336                 }
7337
7338                 if (post_msg_direct) {
7339                         MMMessageParamType msg_param;
7340                         memset(&msg_param, 0, sizeof(MMMessageParamType));
7341
7342                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
7343                                 LOGW("not found AUDIO codec, posting error code to application.\n");
7344
7345                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7346                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7347                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
7348                                 LOGW("not found VIDEO codec, posting error code to application.\n");
7349
7350                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
7351                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
7352                         }
7353
7354                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7355
7356                         MMPLAYER_FREEIF(msg_param.data);
7357
7358                         return MM_ERROR_NONE;
7359                 } else {
7360                         // no any supported codec case
7361                         LOGW("not found any codec, posting error code to application.\n");
7362
7363                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
7364                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7365                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7366                         } else {
7367                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7368                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
7369                         }
7370
7371                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7372
7373                         MMPLAYER_FREEIF(msg_param.data);
7374                 }
7375         }
7376
7377         MMPLAYER_FLEAVE();
7378
7379         return MM_ERROR_NONE;
7380 }
7381
7382 static void __mmplayer_check_pipeline(mm_player_t* player)
7383 {
7384         GstState element_state = GST_STATE_VOID_PENDING;
7385         GstState element_pending_state = GST_STATE_VOID_PENDING;
7386         gint timeout = 0;
7387         int ret = MM_ERROR_NONE;
7388
7389         if (player->gapless.reconfigure) {
7390                 LOGW("pipeline is under construction.\n");
7391
7392                 MMPLAYER_PLAYBACK_LOCK(player);
7393                 MMPLAYER_PLAYBACK_UNLOCK(player);
7394
7395                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7396
7397                 /* wait for state transition */
7398                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
7399
7400                 if (ret == GST_STATE_CHANGE_FAILURE)
7401                         LOGE("failed to change pipeline state within %d sec\n", timeout);
7402         }
7403 }
7404
7405 /* NOTE : it should be able to call 'stop' anytime*/
7406 int
7407 _mmplayer_stop(MMHandleType hplayer)
7408 {
7409         mm_player_t* player = (mm_player_t*)hplayer;
7410         int ret = MM_ERROR_NONE;
7411
7412         MMPLAYER_FENTER();
7413
7414         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7415
7416         /* check current state */
7417         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
7418
7419         /* check pipline building state */
7420         __mmplayer_check_pipeline(player);
7421         __mmplayer_reset_gapless_state(player);
7422
7423         /* NOTE : application should not wait for EOS after calling STOP */
7424         __mmplayer_cancel_eos_timer(player);
7425
7426         __mmplayer_unrealize_streaming_ext(player);
7427
7428         /* reset */
7429         player->seek_state = MMPLAYER_SEEK_NONE;
7430
7431         /* stop pipeline */
7432         ret = __mmplayer_gst_stop(player);
7433
7434         if (ret != MM_ERROR_NONE)
7435                 LOGE("failed to stop player.\n");
7436
7437         MMPLAYER_FLEAVE();
7438
7439         return ret;
7440 }
7441
7442 int
7443 _mmplayer_pause(MMHandleType hplayer)
7444 {
7445         mm_player_t* player = (mm_player_t*)hplayer;
7446         gint64 pos_nsec = 0;
7447         gboolean async = FALSE;
7448         gint ret = MM_ERROR_NONE;
7449
7450         MMPLAYER_FENTER();
7451
7452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7453
7454         /* check current state */
7455         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
7456
7457         /* check pipline building state */
7458         __mmplayer_check_pipeline(player);
7459
7460         switch (MMPLAYER_CURRENT_STATE(player)) {
7461         case MM_PLAYER_STATE_READY:
7462                 {
7463                         /* check prepare async or not.
7464                          * In the case of streaming playback, it's recommned to avoid blocking wait.
7465                          */
7466                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
7467                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
7468
7469                         /* Changing back sync of rtspsrc to async */
7470                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
7471                                 LOGD("async prepare working mode for rtsp");
7472                                 async = TRUE;
7473                         }
7474                 }
7475                 break;
7476
7477         case MM_PLAYER_STATE_PLAYING:
7478                 {
7479                         /* NOTE : store current point to overcome some bad operation
7480                         *(returning zero when getting current position in paused state) of some
7481                         * elements
7482                         */
7483                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7484                                 LOGW("getting current position failed in paused\n");
7485
7486                         player->last_position = pos_nsec;
7487
7488                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7489                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7490                            This causes problem is position calculation during normal pause resume scenarios also.
7491                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
7492                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7493                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7494                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7495                         }
7496                 }
7497                 break;
7498         }
7499
7500         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
7501                 LOGD("doing async pause in case of ms buff src");
7502                 async = TRUE;
7503         }
7504
7505         /* pause pipeline */
7506         ret = __mmplayer_gst_pause(player, async);
7507
7508         if (ret != MM_ERROR_NONE)
7509                 LOGE("failed to pause player. ret : 0x%x\n", ret);
7510
7511         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
7512                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
7513                         LOGE("failed to update display_rotation");
7514         }
7515
7516         MMPLAYER_FLEAVE();
7517
7518         return ret;
7519 }
7520
7521 /* in case of streaming, pause could take long time.*/
7522 int
7523 _mmplayer_abort_pause(MMHandleType hplayer)
7524 {
7525         mm_player_t* player = (mm_player_t*)hplayer;
7526         int ret = MM_ERROR_NONE;
7527
7528         MMPLAYER_FENTER();
7529
7530         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7531                                                 player->pipeline &&
7532                                                 player->pipeline->mainbin,
7533                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7534
7535         LOGD("set the pipeline state to READY");
7536
7537         /* set state to READY */
7538         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7539                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7540         if (ret != MM_ERROR_NONE) {
7541                 LOGE("fail to change state to READY");
7542                 return MM_ERROR_PLAYER_INTERNAL;
7543         }
7544
7545         LOGD("succeeded in changing state to READY");
7546         return ret;
7547 }
7548
7549
7550 int
7551 _mmplayer_resume(MMHandleType hplayer)
7552 {
7553         mm_player_t* player = (mm_player_t*)hplayer;
7554         int ret = MM_ERROR_NONE;
7555         gboolean async = FALSE;
7556
7557         MMPLAYER_FENTER();
7558
7559         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7560
7561         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
7562                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
7563                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
7564                         return ret;
7565                 }
7566
7567                 /* Changing back sync mode rtspsrc to async */
7568                 LOGD("async resume for rtsp case");
7569                 async = TRUE;
7570         }
7571
7572         /* check current state */
7573         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
7574
7575         ret = __mmplayer_gst_resume(player, async);
7576         if (ret != MM_ERROR_NONE)
7577                 LOGE("failed to resume player.\n");
7578
7579         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7580                 LOGD("force resume even during buffering");
7581                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7582         }
7583
7584         MMPLAYER_FLEAVE();
7585
7586         return ret;
7587 }
7588
7589 int
7590 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
7591 {
7592         mm_player_t* player = (mm_player_t*)hplayer;
7593         gint64 pos_nsec = 0;
7594         int ret = MM_ERROR_NONE;
7595         int mute = FALSE;
7596         signed long long start = 0, stop = 0;
7597         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7598         MMPLAYER_FENTER();
7599
7600         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7601         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
7602
7603         /* The sound of video is not supported under 0.0 and over 2.0. */
7604         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
7605                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7606                         mute = TRUE;
7607         }
7608         _mmplayer_set_mute(hplayer, mute);
7609
7610         if (player->playback_rate == rate)
7611                 return MM_ERROR_NONE;
7612
7613         /* If the position is reached at start potion during fast backward, EOS is posted.
7614          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7615          * */
7616         player->playback_rate = rate;
7617
7618         current_state = MMPLAYER_CURRENT_STATE(player);
7619
7620         if (current_state != MM_PLAYER_STATE_PAUSED)
7621                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7622
7623         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7624
7625         if ((current_state == MM_PLAYER_STATE_PAUSED)
7626                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
7627                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
7628                 pos_nsec = player->last_position;
7629         }
7630
7631         if (rate >= 0) {
7632                 start = pos_nsec;
7633                 stop = GST_CLOCK_TIME_NONE;
7634         } else {
7635                 start = GST_CLOCK_TIME_NONE;
7636                 stop = pos_nsec;
7637         }
7638
7639         if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7640                                 player->playback_rate,
7641                                 GST_FORMAT_TIME,
7642                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
7643                                 GST_SEEK_TYPE_SET, start,
7644                                 GST_SEEK_TYPE_SET, stop)) {
7645                 LOGE("failed to set speed playback\n");
7646                 return MM_ERROR_PLAYER_SEEK;
7647         }
7648
7649         LOGD("succeeded to set speed playback as %0.1f\n", rate);
7650
7651         MMPLAYER_FLEAVE();
7652
7653         return MM_ERROR_NONE;;
7654 }
7655
7656 int
7657 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
7658 {
7659         mm_player_t* player = (mm_player_t*)hplayer;
7660         int ret = MM_ERROR_NONE;
7661
7662         MMPLAYER_FENTER();
7663
7664         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7665
7666         /* check pipline building state */
7667         __mmplayer_check_pipeline(player);
7668
7669         ret = __mmplayer_gst_set_position(player, format, position, FALSE);
7670
7671         MMPLAYER_FLEAVE();
7672
7673         return ret;
7674 }
7675
7676 int
7677 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
7678 {
7679         mm_player_t* player = (mm_player_t*)hplayer;
7680         int ret = MM_ERROR_NONE;
7681
7682         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7683
7684         ret = __mmplayer_gst_get_position(player, format, position);
7685
7686         return ret;
7687 }
7688
7689 int
7690 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
7691 {
7692         mm_player_t* player = (mm_player_t*)hplayer;
7693         int ret = MM_ERROR_NONE;
7694
7695         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7696         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
7697
7698         *duration = player->duration;
7699         return ret;
7700 }
7701
7702 int
7703 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
7704 {
7705         mm_player_t* player = (mm_player_t*)hplayer;
7706         int ret = MM_ERROR_NONE;
7707
7708         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7709
7710         ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
7711
7712         return ret;
7713 }
7714
7715 int
7716 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
7717 {
7718         mm_player_t* player = (mm_player_t*)hplayer;
7719         int ret = MM_ERROR_NONE;
7720
7721         MMPLAYER_FENTER();
7722
7723         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7724
7725         ret = __gst_adjust_subtitle_position(player, format, position);
7726
7727         MMPLAYER_FLEAVE();
7728
7729         return ret;
7730 }
7731
7732 static gboolean
7733 __mmplayer_is_midi_type(gchar* str_caps)
7734 {
7735         if ((g_strrstr(str_caps, "audio/midi")) ||
7736                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
7737                 (g_strrstr(str_caps, "application/x-smaf")) ||
7738                 (g_strrstr(str_caps, "audio/x-imelody")) ||
7739                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
7740                 (g_strrstr(str_caps, "audio/xmf")) ||
7741                 (g_strrstr(str_caps, "audio/mxmf"))) {
7742                 LOGD("midi\n");
7743                 return TRUE;
7744         }
7745
7746         return FALSE;
7747 }
7748
7749 static gboolean
7750 __mmplayer_is_only_mp3_type(gchar *str_caps)
7751 {
7752         if (g_strrstr(str_caps, "application/x-id3") ||
7753                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
7754                 return TRUE;
7755         return FALSE;
7756 }
7757
7758 static void
7759 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
7760 {
7761         GstStructure* caps_structure = NULL;
7762         gint samplerate = 0;
7763         gint channels = 0;
7764
7765         MMPLAYER_FENTER();
7766         MMPLAYER_RETURN_IF_FAIL(player && caps);
7767
7768         caps_structure = gst_caps_get_structure(caps, 0);
7769
7770         /* set stream information */
7771         gst_structure_get_int(caps_structure, "rate", &samplerate);
7772         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
7773
7774         gst_structure_get_int(caps_structure, "channels", &channels);
7775         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
7776
7777         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
7778 }
7779
7780 static void
7781 __mmplayer_update_content_type_info(mm_player_t* player)
7782 {
7783         MMPLAYER_FENTER();
7784         MMPLAYER_RETURN_IF_FAIL(player && player->type);
7785
7786         if (__mmplayer_is_midi_type(player->type)) {
7787                 player->bypass_audio_effect = TRUE;
7788         } else if (g_strrstr(player->type, "application/x-hls")) {
7789                 /* If it can't know exact type when it parses uri because of redirection case,
7790                  * it will be fixed by typefinder or when doing autoplugging.
7791                  */
7792                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7793                 if (player->streamer) {
7794                         player->streamer->is_adaptive_streaming = TRUE;
7795                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
7796                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
7797                 }
7798         } else if (g_strrstr(player->type, "application/dash+xml")) {
7799                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7800                 if (player->streamer) {
7801                         player->streamer->is_adaptive_streaming = TRUE;
7802                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
7803                 }
7804         }
7805
7806         LOGD("uri type : %d", player->profile.uri_type);
7807         MMPLAYER_FLEAVE();
7808 }
7809
7810 static void
7811 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
7812 GstCaps *caps, gpointer data)
7813 {
7814         mm_player_t* player = (mm_player_t*)data;
7815         GstPad* pad = NULL;
7816
7817         MMPLAYER_FENTER();
7818
7819         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
7820
7821         /* store type string */
7822         MMPLAYER_FREEIF(player->type);
7823         player->type = gst_caps_to_string(caps);
7824         if (player->type) {
7825                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
7826                                 player, player->type, probability, gst_caps_get_size(caps));
7827         }
7828
7829         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
7830                 (g_strrstr(player->type, "audio/x-raw-int"))) {
7831                 LOGE("not support media format\n");
7832
7833                 if (player->msg_posted == FALSE) {
7834                         MMMessageParamType msg_param;
7835                         memset(&msg_param, 0, sizeof(MMMessageParamType));
7836
7837                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
7838                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7839
7840                         /* don't post more if one was sent already */
7841                         player->msg_posted = TRUE;
7842                 }
7843                 return;
7844         }
7845
7846         __mmplayer_update_content_type_info(player);
7847
7848         pad = gst_element_get_static_pad(tf, "src");
7849         if (!pad) {
7850                 LOGE("fail to get typefind src pad.\n");
7851                 return;
7852         }
7853
7854         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
7855                 gboolean async = FALSE;
7856                 LOGE("failed to autoplug %s\n", player->type);
7857
7858                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
7859
7860                 if (async && player->msg_posted == FALSE)
7861                         __mmplayer_handle_missed_plugin(player);
7862
7863                 goto DONE;
7864         }
7865
7866 DONE:
7867         gst_object_unref(GST_OBJECT(pad));
7868
7869         MMPLAYER_FLEAVE();
7870
7871         return;
7872 }
7873
7874 static GstElement *
7875 __mmplayer_create_decodebin(mm_player_t* player)
7876 {
7877         GstElement *decodebin = NULL;
7878
7879         MMPLAYER_FENTER();
7880
7881         /* create decodebin */
7882         decodebin = gst_element_factory_make("decodebin", NULL);
7883
7884         if (!decodebin) {
7885                 LOGE("fail to create decodebin\n");
7886                 goto ERROR;
7887         }
7888
7889         /* raw pad handling signal */
7890         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
7891                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
7892
7893         /* no-more-pad pad handling signal */
7894         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
7895                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
7896
7897         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
7898                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
7899
7900         /* This signal is emitted when a pad for which there is no further possible
7901            decoding is added to the decodebin.*/
7902         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
7903                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
7904
7905         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
7906            before looking for any elements that can handle that stream.*/
7907         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
7908                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
7909
7910         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
7911            before looking for any elements that can handle that stream.*/
7912         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
7913                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
7914
7915         /* This signal is emitted once decodebin has finished decoding all the data.*/
7916         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
7917                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
7918
7919         /* This signal is emitted when a element is added to the bin.*/
7920         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
7921                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
7922
7923 ERROR:
7924         return decodebin;
7925 }
7926
7927 static gboolean
7928 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
7929 {
7930         MMPlayerGstElement* mainbin = NULL;
7931         GstElement* decodebin = NULL;
7932         GstElement* queue2 = NULL;
7933         GstPad* sinkpad = NULL;
7934         GstPad* qsrcpad = NULL;
7935         gint64 dur_bytes = 0L;
7936
7937         guint max_buffer_size_bytes = 0;
7938         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
7939
7940         MMPLAYER_FENTER();
7941         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
7942
7943         mainbin = player->pipeline->mainbin;
7944
7945         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
7946                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
7947                 LOGD("creating http streaming buffering queue(queue2)\n");
7948
7949                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7950                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
7951                 } else {
7952                         queue2 = gst_element_factory_make("queue2", "queue2");
7953                         if (!queue2) {
7954                                 LOGE("failed to create buffering queue element\n");
7955                                 goto ERROR;
7956                         }
7957
7958                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
7959                                 LOGE("failed to add buffering queue\n");
7960                                 goto ERROR;
7961                         }
7962
7963                         sinkpad = gst_element_get_static_pad(queue2, "sink");
7964                         qsrcpad = gst_element_get_static_pad(queue2, "src");
7965
7966                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
7967                                 LOGE("failed to link buffering queue");
7968                                 goto ERROR;
7969                         }
7970
7971                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
7972                                 LOGE("fail to get duration");
7973
7974                         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
7975
7976                         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
7977
7978                         if (dur_bytes > 0) {
7979                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
7980                                         type = MUXED_BUFFER_TYPE_FILE;
7981                                 } else {
7982                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
7983                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
7984                                 }
7985                         } else {
7986                                 dur_bytes = 0;
7987                         }
7988
7989                         /* NOTE : in case of ts streaming, player cannot get the correct duration info *
7990                          *        skip the pull mode(file or ring buffering) setting. */
7991                         if (!g_strrstr(player->type, "video/mpegts")) {
7992                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
7993                                 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
7994
7995                                 __mm_player_streaming_set_queue2(player->streamer,
7996                                                                                                 queue2,
7997                                                                                                 FALSE,
7998                                                                                                 max_buffer_size_bytes,
7999                                                                                                 player->ini.http_buffering_time,
8000                                                                                                 1.0,                                /* no meaning */
8001                                                                                                 player->ini.http_buffering_limit,   /* no meaning */
8002                                                                                                 type,
8003                                                                                                 player->http_file_buffering_path,
8004                                                                                                 (guint64)dur_bytes);
8005                         }
8006
8007                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
8008                                 LOGE("failed to sync queue2 state with parent\n");
8009                                 goto ERROR;
8010                         }
8011
8012                         srcpad = qsrcpad;
8013
8014                         gst_object_unref(GST_OBJECT(sinkpad));
8015
8016                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
8017                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
8018                 }
8019         }
8020
8021         /* create decodebin */
8022         decodebin = __mmplayer_create_decodebin(player);
8023
8024         if (!decodebin) {
8025                 LOGE("can not create autoplug element\n");
8026                 goto ERROR;
8027         }
8028
8029         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
8030                 LOGE("failed to add decodebin\n");
8031                 goto ERROR;
8032         }
8033
8034         /* to force caps on the decodebin element and avoid reparsing stuff by
8035         * typefind. It also avoids a deadlock in the way typefind activates pads in
8036         * the state change */
8037         g_object_set(decodebin, "sink-caps", caps, NULL);
8038
8039         sinkpad = gst_element_get_static_pad(decodebin, "sink");
8040
8041         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
8042                 LOGE("failed to link decodebin\n");
8043                 goto ERROR;
8044         }
8045
8046         gst_object_unref(GST_OBJECT(sinkpad));
8047
8048         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
8049         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
8050
8051         /* set decodebin property about buffer in streaming playback. *
8052          * in case of HLS/DASH, it does not need to have big buffer   *
8053          * because it is kind of adaptive streaming.                  */
8054         if (!MMPLAYER_IS_HTTP_PD(player) &&
8055             (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
8056             gdouble high_percent = 0.0;
8057
8058                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
8059                 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
8060
8061                 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
8062                         GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
8063
8064                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
8065                                                                                         "high-percent", (gint)high_percent,
8066                                                                                         "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
8067                                                                                         "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
8068                                                                                         "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
8069                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
8070         }
8071
8072         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
8073                 LOGE("failed to sync decodebin state with parent\n");
8074                 goto ERROR;
8075         }
8076
8077         MMPLAYER_FLEAVE();
8078
8079         return TRUE;
8080
8081 ERROR:
8082
8083         if (sinkpad)
8084                 gst_object_unref(GST_OBJECT(sinkpad));
8085
8086         if (queue2) {
8087                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8088                  * You need to explicitly set elements to the NULL state before
8089                  * dropping the final reference, to allow them to clean up.
8090                  */
8091                 gst_element_set_state(queue2, GST_STATE_NULL);
8092
8093                 /* And, it still has a parent "player".
8094                  * You need to let the parent manage the object instead of unreffing the object directly.
8095                  */
8096                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
8097                 gst_object_unref(queue2);
8098                 queue2 = NULL;
8099         }
8100
8101         if (decodebin) {
8102                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8103                  * You need to explicitly set elements to the NULL state before
8104                  * dropping the final reference, to allow them to clean up.
8105                  */
8106                 gst_element_set_state(decodebin, GST_STATE_NULL);
8107
8108                 /* And, it still has a parent "player".
8109                  * You need to let the parent manage the object instead of unreffing the object directly.
8110                  */
8111
8112                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
8113                 gst_object_unref(decodebin);
8114                 decodebin = NULL;
8115         }
8116
8117         return FALSE;
8118 }
8119
8120 static int
8121 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
8122 {
8123         MMPLAYER_FENTER();
8124
8125         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8126         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
8127
8128         LOGD("class : %s, mime : %s \n", factory_class, mime);
8129
8130         /* add missing plugin */
8131         /* NOTE : msl should check missing plugin for image mime type.
8132          * Some motion jpeg clips can have playable audio track.
8133          * So, msl have to play audio after displaying popup written video format not supported.
8134          */
8135         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
8136                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
8137                         LOGD("not found demuxer\n");
8138                         player->not_found_demuxer = TRUE;
8139                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
8140
8141                         goto DONE;
8142                 }
8143         }
8144
8145         if (!g_strrstr(factory_class, "Demuxer")) {
8146                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
8147                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
8148                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
8149
8150                         /* check that clip have multi tracks or not */
8151                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
8152                                 LOGD("video plugin is already linked\n");
8153                         } else {
8154                                 LOGW("add VIDEO to missing plugin\n");
8155                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
8156                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
8157                         }
8158                 } else if (g_str_has_prefix(mime, "audio")) {
8159                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
8160                                 LOGD("audio plugin is already linked\n");
8161                         } else {
8162                                 LOGW("add AUDIO to missing plugin\n");
8163                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
8164                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
8165                         }
8166                 }
8167         }
8168
8169 DONE:
8170         MMPLAYER_FLEAVE();
8171
8172         return MM_ERROR_NONE;
8173 }
8174
8175
8176 static void
8177 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
8178 {
8179         mm_player_t* player = (mm_player_t*)data;
8180
8181         MMPLAYER_FENTER();
8182
8183         MMPLAYER_RETURN_IF_FAIL(player);
8184
8185         /* remove fakesink. */
8186         if (!__mmplayer_gst_remove_fakesink(player,
8187                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
8188                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
8189                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
8190                  * source element are not same. To overcome this situation, this function will called
8191                  * several places and several times. Therefore, this is not an error case.
8192                  */
8193                 return;
8194         }
8195
8196         LOGD("[handle: %p] pipeline has completely constructed", player);
8197
8198         if ((player->ini.async_start) &&
8199                 (player->msg_posted == FALSE) &&
8200                 (player->cmd >= MMPLAYER_COMMAND_START))
8201                 __mmplayer_handle_missed_plugin(player);
8202
8203         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
8204 }
8205
8206 static gboolean
8207 __mmplayer_verify_next_play_path(mm_player_t *player)
8208 {
8209         MMHandleType attrs = 0;
8210         MMPlayerParseProfile profile;
8211         gint uri_idx = 0, check_cnt = 0;
8212         char *uri = NULL;
8213         gint mode = MM_PLAYER_PD_MODE_NONE;
8214         gint video = 0;
8215         gint count = 0;
8216         gint gapless = 0;
8217         guint num_of_list = 0;
8218         static int profile_tv = -1;
8219
8220         MMPLAYER_FENTER();
8221
8222         LOGD("checking for gapless play");
8223
8224         if (player->pipeline->textbin) {
8225                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
8226                 goto ERROR;
8227         }
8228
8229         attrs = MMPLAYER_GET_ATTRS(player);
8230         if (!attrs) {
8231                 LOGE("fail to get attributes.\n");
8232                 goto ERROR;
8233         }
8234
8235         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
8236
8237         if (__builtin_expect(profile_tv == -1, 0)) {
8238                 char *profileName;
8239                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
8240                 switch (*profileName) {
8241                 case 't':
8242                 case 'T':
8243                         profile_tv = 1;
8244                         break;
8245                 default:
8246                         profile_tv = 0;
8247                 }
8248                 free(profileName);
8249         }
8250         /* gapless playback is not supported in case of video at TV profile. */
8251         if (profile_tv && video) {
8252                 LOGW("not support video gapless playback");
8253                 goto ERROR;
8254         }
8255
8256         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
8257                 if (mode == TRUE) {
8258                         LOGW("pd mode\n");
8259                         goto ERROR;
8260                 }
8261         }
8262
8263         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
8264                 LOGE("can not get play count\n");
8265
8266         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
8267                 LOGE("can not get gapless mode\n");
8268
8269         if (video && !gapless) {
8270                 LOGW("not enabled video gapless playback");
8271                 goto ERROR;
8272         }
8273
8274         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
8275                 gapless = 1;
8276
8277         if (!gapless) {
8278                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
8279                 goto ERROR;
8280         }
8281
8282         num_of_list = g_list_length(player->uri_info.uri_list);
8283
8284         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
8285
8286         if (num_of_list == 0) {
8287                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
8288                         LOGE("can not get profile_uri\n");
8289                         goto ERROR;
8290                 }
8291
8292                 if (!uri) {
8293                         LOGE("uri list is empty.\n");
8294                         goto ERROR;
8295                 }
8296
8297                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8298                 LOGD("add original path : %s ", uri);
8299
8300                 num_of_list = 1;
8301                 uri = NULL;
8302         }
8303
8304         uri_idx = player->uri_info.uri_idx;
8305
8306         while (TRUE) {
8307                 check_cnt++;
8308
8309                 if (check_cnt > num_of_list) {
8310                         LOGE("there is no valid uri.");
8311                         goto ERROR;
8312                 }
8313
8314                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
8315
8316                 if (uri_idx < num_of_list-1) {
8317                         uri_idx++;
8318                 } else {
8319                         if ((count <= 1) && (count != -1)) {
8320                                 LOGD("no repeat.");
8321                                 goto ERROR;
8322                         } else if (count > 1) {
8323                                 /* decrease play count */
8324                                 /* we succeeded to rewind. update play count and then wait for next EOS */
8325                                 count--;
8326
8327                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
8328
8329                                 /* commit attribute */
8330                                 if (mmf_attrs_commit(attrs))
8331                                         LOGE("failed to commit attribute\n");
8332                         }
8333
8334                         /* count < 0 : repeat continually */
8335                         uri_idx = 0;
8336                 }
8337
8338                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
8339                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
8340
8341                 if (uri == NULL) {
8342                         LOGW("next uri does not exist\n");
8343                         continue;
8344                 }
8345
8346                 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
8347                         LOGE("failed to parse profile\n");
8348                         continue;
8349                 }
8350
8351                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
8352                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
8353                         LOGW("uri type is not supported(%d).", profile.uri_type);
8354                         continue;
8355                 }
8356
8357                 break;
8358         }
8359
8360         player->uri_info.uri_idx = uri_idx;
8361         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
8362
8363         if (mmf_attrs_commit(player->attrs)) {
8364                 LOGE("failed to commit.\n");
8365                 goto ERROR;
8366         }
8367
8368         LOGD("next uri %s(%d)\n", uri, uri_idx);
8369
8370         return TRUE;
8371
8372 ERROR:
8373
8374         LOGE("unable to play next path. EOS will be posted soon.\n");
8375         return FALSE;
8376 }
8377
8378 static void
8379 __mmplayer_initialize_next_play(mm_player_t *player)
8380 {
8381         int i;
8382
8383         MMPLAYER_FENTER();
8384
8385         player->smooth_streaming = FALSE;
8386         player->videodec_linked = 0;
8387         player->audiodec_linked = 0;
8388         player->videosink_linked = 0;
8389         player->audiosink_linked = 0;
8390         player->textsink_linked = 0;
8391         player->is_external_subtitle_present = FALSE;
8392         player->is_external_subtitle_added_now = FALSE;
8393         player->not_supported_codec = MISSING_PLUGIN_NONE;
8394         player->can_support_codec = FOUND_PLUGIN_NONE;
8395         player->pending_seek.is_pending = FALSE;
8396         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
8397         player->pending_seek.pos = 0;
8398         player->msg_posted = FALSE;
8399         player->has_many_types = FALSE;
8400         player->no_more_pad = FALSE;
8401         player->not_found_demuxer = 0;
8402         player->seek_state = MMPLAYER_SEEK_NONE;
8403         player->max_audio_channels = 0;
8404         player->is_subtitle_force_drop = FALSE;
8405         player->play_subtitle = FALSE;
8406         player->adjust_subtitle_pos = 0;
8407
8408         player->total_bitrate = 0;
8409         player->total_maximum_bitrate = 0;
8410
8411         _mmplayer_track_initialize(player);
8412         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8413
8414         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
8415                 player->bitrate[i] = 0;
8416                 player->maximum_bitrate[i] = 0;
8417         }
8418
8419         if (player->v_stream_caps) {
8420                 gst_caps_unref(player->v_stream_caps);
8421                 player->v_stream_caps = NULL;
8422         }
8423
8424         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
8425
8426         /* clean found parsers */
8427         if (player->parsers) {
8428                 GList *parsers = player->parsers;
8429                 for (; parsers; parsers = g_list_next(parsers)) {
8430                         gchar *name = parsers->data;
8431                         MMPLAYER_FREEIF(name);
8432                 }
8433                 g_list_free(player->parsers);
8434                 player->parsers = NULL;
8435         }
8436
8437         /* clean found audio decoders */
8438         if (player->audio_decoders) {
8439                 GList *a_dec = player->audio_decoders;
8440                 for (; a_dec; a_dec = g_list_next(a_dec)) {
8441                         gchar *name = a_dec->data;
8442                         MMPLAYER_FREEIF(name);
8443                 }
8444                 g_list_free(player->audio_decoders);
8445                 player->audio_decoders = NULL;
8446         }
8447
8448         MMPLAYER_FLEAVE();
8449 }
8450
8451 static void
8452 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
8453 {
8454         MMPlayerGstElement *mainbin = NULL;
8455         MMMessageParamType msg_param = {0,};
8456         GstElement *element = NULL;
8457         MMHandleType attrs = 0;
8458         char *uri = NULL;
8459         enum MainElementID elemId = MMPLAYER_M_NUM;
8460
8461         MMPLAYER_FENTER();
8462
8463         if ((player == NULL) ||
8464                 (player->pipeline == NULL) ||
8465                 (player->pipeline->mainbin == NULL)) {
8466                 LOGE("player is null.\n");
8467                 goto ERROR;
8468         }
8469
8470         mainbin = player->pipeline->mainbin;
8471         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
8472
8473         attrs = MMPLAYER_GET_ATTRS(player);
8474         if (!attrs) {
8475                 LOGE("fail to get attributes.\n");
8476                 goto ERROR;
8477         }
8478
8479         /* Initialize Player values */
8480         __mmplayer_initialize_next_play(player);
8481
8482         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8483
8484         if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
8485                 LOGE("failed to parse profile\n");
8486                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8487                 goto ERROR;
8488         }
8489
8490         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
8491                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
8492                 LOGE("it's dash or hls. not support.");
8493                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8494                 goto ERROR;
8495         }
8496
8497         /* setup source */
8498         switch (player->profile.uri_type) {
8499         /* file source */
8500         case MM_PLAYER_URI_TYPE_FILE:
8501         {
8502                 LOGD("using filesrc for 'file://' handler.\n");
8503                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
8504                         LOGE("failed to get storage info");
8505                         break;
8506                 }
8507
8508                 element = gst_element_factory_make("filesrc", "source");
8509
8510                 if (!element) {
8511                         LOGE("failed to create filesrc\n");
8512                         break;
8513                 }
8514
8515                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
8516                 break;
8517         }
8518         case MM_PLAYER_URI_TYPE_URL_HTTP:
8519         {
8520                 gchar *user_agent, *cookies, **cookie_list;
8521                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
8522                 user_agent = cookies = NULL;
8523                 cookie_list = NULL;
8524
8525                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
8526                 if (!element) {
8527                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
8528                         break;
8529                 }
8530                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
8531
8532                 /* get attribute */
8533                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
8534                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
8535
8536                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
8537                         LOGD("get timeout from ini\n");
8538                         http_timeout = player->ini.http_timeout;
8539                 }
8540
8541                 /* get attribute */
8542                 SECURE_LOGD("location : %s\n", player->profile.uri);
8543                 SECURE_LOGD("cookies : %s\n", cookies);
8544                 SECURE_LOGD("user_agent :  %s\n", user_agent);
8545                 LOGD("timeout : %d\n", http_timeout);
8546
8547                 /* setting property to streaming source */
8548                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
8549                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
8550                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
8551
8552                 /* parsing cookies */
8553                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
8554                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
8555                 if (user_agent)
8556                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
8557                 break;
8558         }
8559         default:
8560                 LOGE("not support uri type %d\n", player->profile.uri_type);
8561                 break;
8562         }
8563
8564         if (!element) {
8565                 LOGE("no source element was created.\n");
8566                 goto ERROR;
8567         }
8568
8569         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
8570                 LOGE("failed to add source element to pipeline\n");
8571                 gst_object_unref(GST_OBJECT(element));
8572                 element = NULL;
8573                 goto ERROR;
8574         }
8575
8576         /* take source element */
8577         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
8578         mainbin[MMPLAYER_M_SRC].gst = element;
8579
8580         element = NULL;
8581
8582         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8583                 if (player->streamer == NULL) {
8584                         player->streamer = __mm_player_streaming_create();
8585                         __mm_player_streaming_initialize(player->streamer);
8586                 }
8587
8588                 elemId = MMPLAYER_M_TYPEFIND;
8589                 element = gst_element_factory_make("typefind", "typefinder");
8590                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
8591                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
8592         } else {
8593                 elemId = MMPLAYER_M_AUTOPLUG;
8594                 element = __mmplayer_create_decodebin(player);
8595         }
8596
8597         /* check autoplug element is OK */
8598         if (!element) {
8599                 LOGE("can not create element(%d)\n", elemId);
8600                 goto ERROR;
8601         }
8602
8603         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
8604                 LOGE("failed to add sinkbin to pipeline\n");
8605                 gst_object_unref(GST_OBJECT(element));
8606                 element = NULL;
8607                 goto ERROR;
8608         }
8609
8610         mainbin[elemId].id = elemId;
8611         mainbin[elemId].gst = element;
8612
8613         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
8614                 LOGE("Failed to link src - autoplug(or typefind)\n");
8615                 goto ERROR;
8616         }
8617
8618         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
8619                 LOGE("Failed to change state of src element\n");
8620                 goto ERROR;
8621         }
8622
8623         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
8624                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
8625                         LOGE("Failed to change state of decodebin\n");
8626                         goto ERROR;
8627                 }
8628         } else {
8629                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
8630                         LOGE("Failed to change state of src element\n");
8631                         goto ERROR;
8632                 }
8633         }
8634
8635         player->gapless.stream_changed = TRUE;
8636         player->gapless.running = TRUE;
8637         MMPLAYER_FLEAVE();
8638         return;
8639
8640 ERROR:
8641         if (player) {
8642                 MMPLAYER_PLAYBACK_UNLOCK(player);
8643
8644                 if (!player->msg_posted) {
8645                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8646                         player->msg_posted = TRUE;
8647                 }
8648         }
8649         return;
8650 }
8651
8652 static gboolean
8653 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
8654 {
8655         mm_player_selector_t *selector = &player->selector[type];
8656         MMPlayerGstElement *sinkbin = NULL;
8657         enum MainElementID selectorId = MMPLAYER_M_NUM;
8658         enum MainElementID sinkId = MMPLAYER_M_NUM;
8659         GstPad *srcpad = NULL;
8660         GstPad *sinkpad = NULL;
8661         gboolean send_notice = FALSE;
8662
8663         MMPLAYER_FENTER();
8664         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8665
8666         LOGD("type %d", type);
8667
8668         switch (type) {
8669         case MM_PLAYER_TRACK_TYPE_AUDIO:
8670                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
8671                 sinkId = MMPLAYER_A_BIN;
8672                 sinkbin = player->pipeline->audiobin;
8673                 break;
8674         case MM_PLAYER_TRACK_TYPE_VIDEO:
8675                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
8676                 sinkId = MMPLAYER_V_BIN;
8677                 sinkbin = player->pipeline->videobin;
8678                 send_notice = TRUE;
8679                 break;
8680         case MM_PLAYER_TRACK_TYPE_TEXT:
8681                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
8682                 sinkId = MMPLAYER_T_BIN;
8683                 sinkbin = player->pipeline->textbin;
8684                 break;
8685         default:
8686                 LOGE("requested type is not supportable");
8687                 return FALSE;
8688                 break;
8689         }
8690
8691         if (player->pipeline->mainbin[selectorId].gst) {
8692                 gint n;
8693
8694                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
8695
8696                 if (selector->event_probe_id != 0)
8697                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
8698                 selector->event_probe_id = 0;
8699
8700                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
8701                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
8702
8703                         if (srcpad && sinkpad) {
8704                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
8705                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
8706                                 gst_pad_unlink(srcpad, sinkpad);
8707
8708                                 /* send custom event to sink pad to handle it at video sink */
8709                                 if (send_notice) {
8710                                         LOGD("send custom event to sinkpad");
8711                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
8712                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
8713                                         gst_pad_send_event(sinkpad, event);
8714                                 }
8715                         }
8716
8717                         gst_object_unref(sinkpad);
8718                         sinkpad = NULL;
8719                 }
8720                 gst_object_unref(srcpad);
8721                 srcpad = NULL;
8722
8723                 LOGD("selector release");
8724
8725                 /* release and unref requests pad from the selector */
8726                 for (n = 0; n < selector->channels->len; n++) {
8727                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
8728                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
8729                 }
8730                 g_ptr_array_set_size(selector->channels, 0);
8731
8732                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
8733                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
8734
8735                 player->pipeline->mainbin[selectorId].gst = NULL;
8736                 selector = NULL;
8737         }
8738
8739         return TRUE;
8740 }
8741
8742 static void
8743 __mmplayer_deactivate_old_path(mm_player_t *player)
8744 {
8745         MMPLAYER_FENTER();
8746         MMPLAYER_RETURN_IF_FAIL(player);
8747
8748         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
8749                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
8750                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
8751                 LOGE("deactivate selector error");
8752                 goto ERROR;
8753         }
8754
8755         _mmplayer_track_destroy(player);
8756         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8757
8758         if (player->streamer) {
8759                 __mm_player_streaming_deinitialize(player->streamer);
8760                 __mm_player_streaming_destroy(player->streamer);
8761                 player->streamer = NULL;
8762         }
8763
8764         MMPLAYER_PLAYBACK_LOCK(player);
8765         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8766
8767         MMPLAYER_FLEAVE();
8768         return;
8769
8770 ERROR:
8771
8772         if (!player->msg_posted) {
8773                 MMMessageParamType msg = {0,};
8774
8775                 /*post error*/
8776                 msg.code = MM_ERROR_PLAYER_INTERNAL;
8777                 LOGE("next_uri_play> deactivate error");
8778
8779                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
8780                 player->msg_posted = TRUE;
8781         }
8782         return;
8783 }
8784
8785 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
8786 {
8787         int result = MM_ERROR_NONE;
8788         mm_player_t* player = (mm_player_t*) hplayer;
8789         MMPLAYER_FENTER();
8790
8791         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8792
8793         if (file_path) {
8794                 player->http_file_buffering_path = (gchar*)file_path;
8795                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
8796         }
8797         MMPLAYER_FLEAVE();
8798         return result;
8799 }
8800
8801 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
8802 {
8803         int result = MM_ERROR_NONE;
8804         mm_player_t* player = (mm_player_t*) hplayer;
8805         MMPLAYER_FENTER();
8806
8807         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8808
8809         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
8810         if (mmf_attrs_commit(player->attrs)) {
8811                 LOGE("failed to commit the original uri.\n");
8812                 result = MM_ERROR_PLAYER_INTERNAL;
8813         } else {
8814                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
8815                         LOGE("failed to add the original uri in the uri list.\n");
8816         }
8817
8818         MMPLAYER_FLEAVE();
8819         return result;
8820 }
8821
8822 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
8823 {
8824         mm_player_t* player = (mm_player_t*) hplayer;
8825         guint num_of_list = 0;
8826
8827         MMPLAYER_FENTER();
8828
8829         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8830         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
8831
8832         if (player->pipeline && player->pipeline->textbin) {
8833                 LOGE("subtitle path is enabled.\n");
8834                 return MM_ERROR_PLAYER_INVALID_STATE;
8835         }
8836
8837         num_of_list = g_list_length(player->uri_info.uri_list);
8838
8839         if (is_first_path == TRUE) {
8840                 if (num_of_list == 0) {
8841                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8842                         LOGD("add original path : %s", uri);
8843                 } else {
8844                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
8845                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
8846
8847                         LOGD("change original path : %s", uri);
8848                 }
8849         } else {
8850                 MMHandleType attrs = 0;
8851                 attrs = MMPLAYER_GET_ATTRS(player);
8852
8853                 if (num_of_list == 0) {
8854                         char *original_uri = NULL;
8855
8856                         if (attrs) {
8857                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
8858
8859                                 if (!original_uri) {
8860                                         LOGE("there is no original uri.");
8861                                         return MM_ERROR_PLAYER_INVALID_STATE;
8862                                 }
8863
8864                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
8865                                 player->uri_info.uri_idx = 0;
8866
8867                                 LOGD("add original path at first : %s(%d)", original_uri);
8868                         }
8869                 }
8870
8871                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8872                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
8873         }
8874
8875         MMPLAYER_FLEAVE();
8876         return MM_ERROR_NONE;
8877 }
8878
8879 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
8880 {
8881         mm_player_t* player = (mm_player_t*) hplayer;
8882         char *next_uri = NULL;
8883         guint num_of_list = 0;
8884
8885         MMPLAYER_FENTER();
8886         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8887
8888         num_of_list = g_list_length(player->uri_info.uri_list);
8889
8890         if (num_of_list > 0) {
8891                 gint uri_idx = player->uri_info.uri_idx;
8892
8893                 if (uri_idx < num_of_list-1)
8894                         uri_idx++;
8895                 else
8896                         uri_idx = 0;
8897
8898                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
8899                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
8900
8901                 *uri = g_strdup(next_uri);
8902         }
8903
8904         MMPLAYER_FLEAVE();
8905         return MM_ERROR_NONE;
8906 }
8907
8908 static void
8909 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
8910 GstCaps *caps, gpointer data)
8911 {
8912         mm_player_t* player = (mm_player_t*)data;
8913         const gchar* klass = NULL;
8914         const gchar* mime = NULL;
8915         gchar* caps_str = NULL;
8916
8917         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
8918         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8919         caps_str = gst_caps_to_string(caps);
8920
8921         LOGW("unknown type of caps : %s from %s",
8922                                         caps_str, GST_ELEMENT_NAME(elem));
8923
8924         MMPLAYER_FREEIF(caps_str);
8925
8926         /* There is no available codec. */
8927         __mmplayer_check_not_supported_codec(player, klass, mime);
8928 }
8929
8930 static gboolean
8931 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
8932 GstCaps * caps,  gpointer data)
8933 {
8934         mm_player_t* player = (mm_player_t*)data;
8935         const char* mime = NULL;
8936         gboolean ret = TRUE;
8937
8938         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8939         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8940
8941         if (g_str_has_prefix(mime, "audio")) {
8942                 GstStructure* caps_structure = NULL;
8943                 gint samplerate = 0;
8944                 gint channels = 0;
8945                 gchar *caps_str = NULL;
8946
8947                 caps_structure = gst_caps_get_structure(caps, 0);
8948                 gst_structure_get_int(caps_structure, "rate", &samplerate);
8949                 gst_structure_get_int(caps_structure, "channels", &channels);
8950
8951                 if ((channels > 0 && samplerate == 0)) {
8952                         LOGD("exclude audio...");
8953                         ret = FALSE;
8954                 }
8955
8956                 caps_str = gst_caps_to_string(caps);
8957                 /* set it directly because not sent by TAG */
8958                 if (g_strrstr(caps_str, "mobile-xmf"))
8959                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
8960                 MMPLAYER_FREEIF(caps_str);
8961         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
8962                 MMMessageParamType msg_param;
8963                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8964                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
8965                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8966                 LOGD("video file is not supported on this device");
8967                 ret = FALSE;
8968         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
8969                 LOGD("already video linked");
8970                 ret = FALSE;
8971         } else {
8972                 LOGD("found new stream");
8973         }
8974
8975         return ret;
8976 }
8977
8978 static int
8979 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
8980 {
8981         int ret = MM_ERROR_NONE;
8982         int idx = 0;
8983         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8984
8985         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
8986                 GstStructure* str = NULL;
8987                 gint channels = 0;
8988                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
8989
8990                 LOGD("audio codec type: %d", codec_type);
8991                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
8992                         /* sw codec will be skipped */
8993                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
8994                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
8995                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
8996                                         ret = MM_ERROR_PLAYER_INTERNAL;
8997                                         goto DONE;
8998                                 }
8999                         }
9000                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
9001                         /* hw codec will be skipped */
9002                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
9003                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
9004                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
9005                                 ret = MM_ERROR_PLAYER_INTERNAL;
9006                                 goto DONE;
9007                         }
9008                 }
9009
9010                 str = gst_caps_get_structure(caps, 0);
9011                 if (str) {
9012                         gst_structure_get_int(str, "channels", &channels);
9013
9014                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
9015                         if (player->max_audio_channels < channels)
9016                                 player->max_audio_channels = channels;
9017                 }
9018                 /* set stream information */
9019                 if (!player->audiodec_linked)
9020                         __mmplayer_set_audio_attrs(player, caps);
9021
9022                 /* update codec info */
9023                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
9024                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
9025                 player->audiodec_linked = 1;
9026
9027         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
9028
9029                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
9030
9031                 LOGD("video codec type: %d", codec_type);
9032                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
9033                         /* sw codec is skipped */
9034                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
9035                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
9036                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
9037                                         ret = MM_ERROR_PLAYER_INTERNAL;
9038                                         goto DONE;
9039                                 }
9040                         }
9041                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
9042                         /* hw codec is skipped */
9043                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
9044                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
9045                                 ret = MM_ERROR_PLAYER_INTERNAL;
9046                                 goto DONE;
9047                         }
9048                 }
9049
9050                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
9051                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
9052
9053                         /* mark video decoder for acquire */
9054                         if (player->video_decoder_resource == NULL) {
9055                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
9056                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
9057                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
9058                                                 &player->video_decoder_resource)
9059                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
9060                                         LOGE("could not mark video_decoder resource for acquire");
9061                                         ret = MM_ERROR_PLAYER_INTERNAL;
9062                                         goto DONE;
9063                                 }
9064                         } else {
9065                                 LOGW("video decoder resource is already acquired, skip it.");
9066                                 ret = MM_ERROR_PLAYER_INTERNAL;
9067                                 goto DONE;
9068                         }
9069
9070                         player->interrupted_by_resource = FALSE;
9071                         /* acquire resources for video playing */
9072                         if (mm_resource_manager_commit(player->resource_manager)
9073                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
9074                                 LOGE("could not acquire resources for video decoding\n");
9075                                 ret = MM_ERROR_PLAYER_INTERNAL;
9076                                 goto DONE;
9077                         }
9078                 }
9079
9080                 /* update codec info */
9081                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
9082                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
9083                 player->videodec_linked = 1;
9084         }
9085
9086 DONE:
9087         return ret;
9088 }
9089
9090 static gint
9091 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
9092 GstCaps* caps, GstElementFactory* factory, gpointer data)
9093 {
9094         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
9095          We are defining our own and will be removed when it actually exposed */
9096         typedef enum {
9097                 GST_AUTOPLUG_SELECT_TRY,
9098                 GST_AUTOPLUG_SELECT_EXPOSE,
9099                 GST_AUTOPLUG_SELECT_SKIP
9100         } GstAutoplugSelectResult;
9101
9102         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
9103         mm_player_t* player = (mm_player_t*)data;
9104
9105         gchar* factory_name = NULL;
9106         gchar* caps_str = NULL;
9107         const gchar* klass = NULL;
9108         gint idx = 0;
9109
9110         factory_name = GST_OBJECT_NAME(factory);
9111         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
9112         caps_str = gst_caps_to_string(caps);
9113
9114         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
9115
9116         /* store type string */
9117         if (player->type == NULL) {
9118                 player->type = gst_caps_to_string(caps);
9119                 __mmplayer_update_content_type_info(player);
9120         }
9121
9122         /* filtering exclude keyword */
9123         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
9124                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
9125                         LOGW("skipping [%s] by exculde keyword [%s]\n",
9126                                         factory_name, player->ini.exclude_element_keyword[idx]);
9127
9128                         result = GST_AUTOPLUG_SELECT_SKIP;
9129                         goto DONE;
9130                 }
9131         }
9132
9133         /* exclude webm format */
9134         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
9135          * because webm format is not supportable.
9136          * If webm is disabled in "autoplug-continue", there is no state change
9137          * failure or error because the decodebin will expose the pad directly.
9138          * It make MSL invoke _prepare_async_callback.
9139          * So, we need to disable webm format in "autoplug-select" */
9140         if (caps_str && strstr(caps_str, "webm")) {
9141                 LOGW("webm is not supported");
9142                 result = GST_AUTOPLUG_SELECT_SKIP;
9143                 goto DONE;
9144         }
9145
9146         /* check factory class for filtering */
9147         /* NOTE : msl don't need to use image plugins.
9148          * So, those plugins should be skipped for error handling.
9149          */
9150         if (g_strrstr(klass, "Codec/Decoder/Image")) {
9151                 LOGD("skipping [%s] by not required\n", factory_name);
9152                 result = GST_AUTOPLUG_SELECT_SKIP;
9153                 goto DONE;
9154         }
9155
9156         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
9157                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
9158                 // TO CHECK : subtitle if needed, add subparse exception.
9159                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
9160                 result = GST_AUTOPLUG_SELECT_SKIP;
9161                 goto DONE;
9162         }
9163
9164         if (g_strrstr(factory_name, "mpegpsdemux")) {
9165                 LOGD("skipping PS container - not support\n");
9166                 result = GST_AUTOPLUG_SELECT_SKIP;
9167                 goto DONE;
9168         }
9169
9170         if (g_strrstr(factory_name, "mssdemux"))
9171                 player->smooth_streaming = TRUE;
9172
9173         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
9174                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
9175                 gint stype = 0;
9176                 gint width = 0;
9177                 GstStructure *str = NULL;
9178                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
9179
9180                 /* don't make video because of not required */
9181                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
9182                         (player->set_mode.media_packet_video_stream == FALSE)) {
9183                         LOGD("no video because it's not required. -> return expose");
9184                         result = GST_AUTOPLUG_SELECT_EXPOSE;
9185                         goto DONE;
9186                 }
9187
9188                 /* get w/h for omx state-tune */
9189                 /* FIXME: deprecated? */
9190                 str = gst_caps_get_structure(caps, 0);
9191                 gst_structure_get_int(str, "width", &width);
9192
9193                 if (width != 0) {
9194                         if (player->v_stream_caps) {
9195                                 gst_caps_unref(player->v_stream_caps);
9196                                 player->v_stream_caps = NULL;
9197                         }
9198
9199                         player->v_stream_caps = gst_caps_copy(caps);
9200                         LOGD("take caps for video state tune");
9201                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
9202                 }
9203         }
9204
9205         if (g_strrstr(klass, "Codec/Decoder")) {
9206                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
9207                         LOGD("skipping %s codec", factory_name);
9208                         result = GST_AUTOPLUG_SELECT_SKIP;
9209                         goto DONE;
9210                 }
9211         }
9212
9213 DONE:
9214         MMPLAYER_FREEIF(caps_str);
9215
9216         return result;
9217 }
9218
9219 static void
9220 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
9221 gpointer data)
9222 {
9223         //mm_player_t* player = (mm_player_t*)data;
9224         GstCaps* caps = NULL;
9225
9226         LOGD("[Decodebin2] pad-removed signal\n");
9227
9228         caps = gst_pad_query_caps(new_pad, NULL);
9229         if (caps) {
9230                 gchar* caps_str = NULL;
9231                 caps_str = gst_caps_to_string(caps);
9232
9233                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
9234
9235                 MMPLAYER_FREEIF(caps_str);
9236                 gst_caps_unref(caps);
9237         }
9238 }
9239
9240 static void
9241 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
9242 {
9243         mm_player_t* player = (mm_player_t*)data;
9244         GstIterator *iter = NULL;
9245         GValue item = { 0, };
9246         GstPad *pad = NULL;
9247         gboolean done = FALSE;
9248         gboolean is_all_drained = TRUE;
9249
9250         MMPLAYER_FENTER();
9251         MMPLAYER_RETURN_IF_FAIL(player);
9252
9253         LOGD("__mmplayer_gst_decode_drained");
9254
9255         if (player->use_deinterleave == TRUE) {
9256                 LOGD("group playing mode.");
9257                 return;
9258         }
9259
9260         if (!MMPLAYER_CMD_TRYLOCK(player)) {
9261                 LOGW("Fail to get cmd lock");
9262                 return;
9263         }
9264
9265         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
9266                 !__mmplayer_verify_next_play_path(player)) {
9267                 LOGD("decoding is finished.");
9268                 __mmplayer_reset_gapless_state(player);
9269                 MMPLAYER_CMD_UNLOCK(player);
9270                 return;
9271         }
9272
9273         player->gapless.reconfigure = TRUE;
9274
9275         /* check decodebin src pads whether they received EOS or not */
9276         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
9277
9278         while (!done) {
9279                 switch (gst_iterator_next(iter, &item)) {
9280                 case GST_ITERATOR_OK:
9281                         pad = g_value_get_object(&item);
9282                         if (pad && !GST_PAD_IS_EOS(pad)) {
9283                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
9284                                 is_all_drained = FALSE;
9285                                 break;
9286                         }
9287                         g_value_reset(&item);
9288                         break;
9289                 case GST_ITERATOR_RESYNC:
9290                         gst_iterator_resync(iter);
9291                         break;
9292                 case GST_ITERATOR_ERROR:
9293                 case GST_ITERATOR_DONE:
9294                         done = TRUE;
9295                         break;
9296                 }
9297         }
9298         g_value_unset(&item);
9299         gst_iterator_free(iter);
9300
9301         if (!is_all_drained) {
9302                 LOGD("Wait util the all pads get EOS.");
9303                 MMPLAYER_CMD_UNLOCK(player);
9304                 MMPLAYER_FLEAVE();
9305                 return;
9306         }
9307
9308         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
9309         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
9310
9311         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
9312         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
9313         __mmplayer_deactivate_old_path(player);
9314         MMPLAYER_CMD_UNLOCK(player);
9315
9316         MMPLAYER_FLEAVE();
9317 }
9318
9319 static void
9320 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
9321 {
9322         mm_player_t* player = (mm_player_t*)data;
9323         const gchar* klass = NULL;
9324         gchar* factory_name = NULL;
9325
9326         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
9327         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
9328
9329         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
9330
9331         if (__mmplayer_add_dump_buffer_probe(player, element))
9332                 LOGD("add buffer probe");
9333
9334         //<-
9335         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
9336                 gchar* selected = NULL;
9337                 selected = g_strdup(GST_ELEMENT_NAME(element));
9338                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
9339         }
9340         //-> temp code
9341
9342         if (g_strrstr(klass, "Parser")) {
9343                 gchar* selected = NULL;
9344
9345                 selected = g_strdup(factory_name);
9346                 player->parsers = g_list_append(player->parsers, selected);
9347         }
9348
9349         if (g_strrstr(klass, "Demuxer/Adaptive")) {
9350                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
9351                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
9352
9353                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
9354                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
9355
9356                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9357                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
9358                                                 "max-video-width", player->adaptive_info.limit.width,
9359                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
9360
9361         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
9362                 /* FIXIT : first value will be overwritten if there's more
9363                  * than 1 demuxer/parser
9364                  */
9365
9366                 //LOGD("plugged element is demuxer. take it\n");
9367                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
9368                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
9369
9370                 /*Added for multi audio support */ // Q. del?
9371                 if (g_strrstr(klass, "Demux")) {
9372                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
9373                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
9374                 }
9375         }
9376
9377         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
9378                 int surface_type = 0;
9379
9380                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
9381         }
9382
9383         // to support trust-zone only
9384         if (g_strrstr(factory_name, "asfdemux")) {
9385                 LOGD("set file-location %s\n", player->profile.uri);
9386                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
9387
9388                 if (player->video_hub_download_mode == TRUE)
9389                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
9390         } else if (g_strrstr(factory_name, "legacyh264parse")) {
9391                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
9392                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
9393         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
9394                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
9395                         (__mmplayer_is_only_mp3_type(player->type))) {
9396                         LOGD("[mpegaudioparse] set streaming pull mode.");
9397                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
9398                 }
9399         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
9400                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
9401         }
9402
9403         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
9404                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
9405                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
9406
9407                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
9408                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
9409
9410                 if (!MMPLAYER_IS_HTTP_PD(player) &&
9411                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
9412                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
9413                         (MMPLAYER_IS_DASH_STREAMING(player)))) {
9414                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
9415                         __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
9416                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
9417                 }
9418
9419         }
9420
9421         return;
9422 }
9423
9424 gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
9425 {
9426         MMPLAYER_FENTER();
9427         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9428
9429         if (MMPLAYER_IS_STREAMING(player))
9430                 return FALSE;
9431
9432         /* This callback can be set to music player only. */
9433         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
9434                 LOGW("audio callback is not supported for video");
9435                 return FALSE;
9436         }
9437
9438         if (player->audio_stream_cb) {
9439                 GstPad *pad = NULL;
9440
9441                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
9442
9443                 if (!pad) {
9444                         LOGE("failed to get sink pad from audiosink to probe data\n");
9445                         return FALSE;
9446                 }
9447                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
9448                         __mmplayer_audio_stream_probe, player, NULL);
9449
9450                 gst_object_unref(pad);
9451
9452                 pad = NULL;
9453         } else {
9454                 LOGE("There is no audio callback to configure.\n");
9455                 return FALSE;
9456         }
9457
9458         MMPLAYER_FLEAVE();
9459
9460         return TRUE;
9461 }
9462
9463 static void
9464 __mmplayer_release_misc(mm_player_t* player)
9465 {
9466         int i;
9467         bool cur_mode = player->set_mode.rich_audio;
9468         MMPLAYER_FENTER();
9469
9470         MMPLAYER_RETURN_IF_FAIL(player);
9471
9472         player->video_stream_cb = NULL;
9473         player->video_stream_cb_user_param = NULL;
9474         player->video_stream_prerolled = FALSE;
9475
9476         player->audio_stream_cb = NULL;
9477         player->audio_stream_render_cb_ex = NULL;
9478         player->audio_stream_cb_user_param = NULL;
9479         player->audio_stream_sink_sync = false;
9480
9481         player->video_stream_changed_cb = NULL;
9482         player->video_stream_changed_cb_user_param = NULL;
9483
9484         player->audio_stream_changed_cb = NULL;
9485         player->audio_stream_changed_cb_user_param = NULL;
9486
9487         player->sent_bos = FALSE;
9488         player->playback_rate = DEFAULT_PLAYBACK_RATE;
9489
9490         player->seek_state = MMPLAYER_SEEK_NONE;
9491
9492         player->total_bitrate = 0;
9493         player->total_maximum_bitrate = 0;
9494
9495         player->not_found_demuxer = 0;
9496
9497         player->last_position = 0;
9498         player->duration = 0;
9499         player->http_content_size = 0;
9500         player->not_supported_codec = MISSING_PLUGIN_NONE;
9501         player->can_support_codec = FOUND_PLUGIN_NONE;
9502         player->pending_seek.is_pending = FALSE;
9503         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
9504         player->pending_seek.pos = 0;
9505         player->msg_posted = FALSE;
9506         player->has_many_types = FALSE;
9507         player->max_audio_channels = 0;
9508         player->video_share_api_delta = 0;
9509         player->video_share_clock_delta = 0;
9510         player->is_subtitle_force_drop = FALSE;
9511         player->play_subtitle = FALSE;
9512         player->adjust_subtitle_pos = 0;
9513         player->last_multiwin_status = FALSE;
9514         player->has_closed_caption = FALSE;
9515         player->set_mode.media_packet_video_stream = FALSE;
9516         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
9517         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
9518         /* recover mode */
9519         player->set_mode.rich_audio = cur_mode;
9520
9521         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
9522                 player->bitrate[i] = 0;
9523                 player->maximum_bitrate[i] = 0;
9524         }
9525
9526         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
9527
9528         /* remove media stream cb(appsrc cb) */
9529         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
9530                 player->media_stream_buffer_status_cb[i] = NULL;
9531                 player->media_stream_seek_data_cb[i] = NULL;
9532                 player->buffer_cb_user_param[i] = NULL;
9533                 player->seek_cb_user_param[i] = NULL;
9534         }
9535         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
9536
9537         /* free memory related to audio effect */
9538         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
9539
9540         if (player->adaptive_info.var_list) {
9541                 g_list_free_full(player->adaptive_info.var_list, g_free);
9542                 player->adaptive_info.var_list = NULL;
9543         }
9544
9545         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9546         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9547         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9548
9549         /* Reset video360 settings to their defaults in case if the pipeline is to be
9550          * re-created.
9551          * */
9552         player->video360_metadata.is_spherical = -1;
9553         player->is_openal_plugin_used = FALSE;
9554
9555         player->is_content_spherical = FALSE;
9556         player->is_video360_enabled = TRUE;
9557         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
9558         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
9559         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
9560         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
9561         player->video360_zoom = 1.0f;
9562         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
9563         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
9564
9565         player->sound.rg_enable = false;
9566
9567         MMPLAYER_FLEAVE();
9568 }
9569
9570 static void
9571 __mmplayer_release_misc_post(mm_player_t* player)
9572 {
9573         char *original_uri = NULL;
9574         MMPLAYER_FENTER();
9575
9576         /* player->pipeline is already released before. */
9577
9578         MMPLAYER_RETURN_IF_FAIL(player);
9579
9580         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
9581
9582         /* clean found parsers */
9583         if (player->parsers) {
9584                 GList *parsers = player->parsers;
9585                 for (; parsers; parsers = g_list_next(parsers)) {
9586                         gchar *name = parsers->data;
9587                         MMPLAYER_FREEIF(name);
9588                 }
9589                 g_list_free(player->parsers);
9590                 player->parsers = NULL;
9591         }
9592
9593         /* clean found audio decoders */
9594         if (player->audio_decoders) {
9595                 GList *a_dec = player->audio_decoders;
9596                 for (; a_dec; a_dec = g_list_next(a_dec)) {
9597                         gchar *name = a_dec->data;
9598                         MMPLAYER_FREEIF(name);
9599                 }
9600                 g_list_free(player->audio_decoders);
9601                 player->audio_decoders = NULL;
9602         }
9603
9604         /* clean the uri list except original uri */
9605         if (player->uri_info.uri_list) {
9606                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
9607
9608                 if (player->attrs) {
9609                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
9610                         LOGD("restore original uri = %s\n", original_uri);
9611
9612                         if (mmf_attrs_commit(player->attrs))
9613                                 LOGE("failed to commit the original uri.\n");
9614                 }
9615
9616                 GList *uri_list = player->uri_info.uri_list;
9617                 for (; uri_list; uri_list = g_list_next(uri_list)) {
9618                         gchar *uri = uri_list->data;
9619                         MMPLAYER_FREEIF(uri);
9620                 }
9621                 g_list_free(player->uri_info.uri_list);
9622                 player->uri_info.uri_list = NULL;
9623         }
9624
9625         /* clear the audio stream buffer list */
9626         __mmplayer_audio_stream_clear_buffer(player, FALSE);
9627
9628         /* clear the video stream bo list */
9629         __mmplayer_video_stream_destroy_bo_list(player);
9630         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
9631
9632         if (player->profile.input_mem.buf) {
9633                 free(player->profile.input_mem.buf);
9634                 player->profile.input_mem.buf = NULL;
9635         }
9636         player->profile.input_mem.len = 0;
9637         player->profile.input_mem.offset = 0;
9638
9639         player->uri_info.uri_idx = 0;
9640         MMPLAYER_FLEAVE();
9641 }
9642
9643 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
9644 {
9645         GstElement *element = NULL;
9646         GstPad *sinkpad;
9647
9648         LOGD("creating %s to plug\n", name);
9649
9650         element = gst_element_factory_make(name, NULL);
9651         if (!element) {
9652                 LOGE("failed to create queue\n");
9653                 return NULL;
9654         }
9655
9656         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
9657                 LOGE("failed to set state READY to %s\n", name);
9658                 gst_object_unref(element);
9659                 return NULL;
9660         }
9661
9662         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
9663                 LOGE("failed to add %s\n", name);
9664                 gst_object_unref(element);
9665                 return NULL;
9666         }
9667
9668         sinkpad = gst_element_get_static_pad(element, "sink");
9669
9670         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
9671                 LOGE("failed to link %s\n", name);
9672                 gst_object_unref(sinkpad);
9673                 gst_object_unref(element);
9674                 return NULL;
9675         }
9676
9677         LOGD("linked %s to pipeline successfully\n", name);
9678
9679         gst_object_unref(sinkpad);
9680
9681         return element;
9682 }
9683
9684 gboolean
9685 __mmplayer_check_subtitle(mm_player_t* player)
9686 {
9687         MMHandleType attrs = 0;
9688         char *subtitle_uri = NULL;
9689
9690         MMPLAYER_FENTER();
9691
9692         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9693
9694         /* get subtitle attribute */
9695         attrs = MMPLAYER_GET_ATTRS(player);
9696         if (!attrs)
9697                 return FALSE;
9698
9699         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
9700         if (!subtitle_uri || !strlen(subtitle_uri))
9701                 return FALSE;
9702
9703         SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
9704         player->is_external_subtitle_present = TRUE;
9705
9706         MMPLAYER_FLEAVE();
9707
9708         return TRUE;
9709 }
9710
9711 static gboolean
9712 __mmplayer_can_extract_pcm(mm_player_t* player)
9713 {
9714         MMHandleType attrs = 0;
9715         gboolean sound_extraction = FALSE;
9716
9717         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9718
9719         attrs = MMPLAYER_GET_ATTRS(player);
9720         if (!attrs) {
9721                 LOGE("fail to get attributes.");
9722                 return FALSE;
9723         }
9724
9725         /* get sound_extraction property */
9726         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
9727
9728         if (!sound_extraction) {
9729                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
9730                 return FALSE;
9731         }
9732
9733         return TRUE;
9734 }
9735
9736 void
9737 __mmplayer_cancel_eos_timer(mm_player_t* player)
9738 {
9739         MMPLAYER_RETURN_IF_FAIL(player);
9740
9741         if (player->eos_timer) {
9742                 LOGD("cancel eos timer");
9743                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
9744                 player->eos_timer = 0;
9745         }
9746
9747         return;
9748 }
9749
9750 static void
9751 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
9752 {
9753         MMPLAYER_FENTER();
9754
9755         MMPLAYER_RETURN_IF_FAIL(player);
9756         MMPLAYER_RETURN_IF_FAIL(sink);
9757
9758         player->sink_elements =
9759                 g_list_append(player->sink_elements, sink);
9760
9761         MMPLAYER_FLEAVE();
9762 }
9763
9764 static void
9765 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
9766 {
9767         MMPLAYER_FENTER();
9768
9769         MMPLAYER_RETURN_IF_FAIL(player);
9770         MMPLAYER_RETURN_IF_FAIL(sink);
9771
9772         player->sink_elements =
9773                         g_list_remove(player->sink_elements, sink);
9774
9775         MMPLAYER_FLEAVE();
9776 }
9777
9778 /* NOTE : be careful with calling this api. please refer to below glib comment
9779  * glib comment : Note that there is a bug in GObject that makes this function much
9780  * less useful than it might seem otherwise. Once gobject is disposed, the callback
9781  * will no longer be called, but, the signal handler is not currently disconnected.
9782  * If the instance is itself being freed at the same time than this doesn't matter,
9783  * since the signal will automatically be removed, but if instance persists,
9784  * then the signal handler will leak. You should not remove the signal yourself
9785  * because in a future versions of GObject, the handler will automatically be
9786  * disconnected.
9787  *
9788  * It's possible to work around this problem in a way that will continue to work
9789  * with future versions of GObject by checking that the signal handler is still
9790  * connected before disconnected it:
9791  *
9792  *  if (g_signal_handler_is_connected(instance, id))
9793  *    g_signal_handler_disconnect(instance, id);
9794  */
9795 static void
9796 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
9797 {
9798         GList* sig_list = NULL;
9799         MMPlayerSignalItem* item = NULL;
9800
9801         MMPLAYER_FENTER();
9802
9803         MMPLAYER_RETURN_IF_FAIL(player);
9804
9805         LOGD("release signals type : %d", type);
9806
9807         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
9808                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
9809                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
9810                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
9811                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
9812                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
9813                 return;
9814         }
9815
9816         sig_list = player->signals[type];
9817
9818         for (; sig_list; sig_list = sig_list->next) {
9819                 item = sig_list->data;
9820
9821                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
9822                         if (g_signal_handler_is_connected(item->obj, item->sig))
9823                                 g_signal_handler_disconnect(item->obj, item->sig);
9824                 }
9825
9826                 MMPLAYER_FREEIF(item);
9827         }
9828
9829         g_list_free(player->signals[type]);
9830         player->signals[type] = NULL;
9831
9832         MMPLAYER_FLEAVE();
9833
9834         return;
9835 }
9836
9837 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
9838 {
9839         mm_player_t* player = 0;
9840         int prev_display_surface_type = 0;
9841         void *prev_display_overlay = NULL;
9842         const gchar *klass = NULL;
9843         gchar *cur_videosink_name = NULL;
9844         int ret = 0;
9845         int i = 0;
9846         int num_of_dec = 2; /* DEC1, DEC2 */
9847
9848         MMPLAYER_FENTER();
9849
9850         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
9851         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
9852
9853         player = MM_PLAYER_CAST(handle);
9854
9855         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
9856                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
9857                 MMPLAYER_FLEAVE();
9858                 return MM_ERROR_INVALID_ARGUMENT;
9859         }
9860
9861         /* load previous attributes */
9862         if (player->attrs) {
9863                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
9864                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
9865                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
9866                 if (prev_display_surface_type == surface_type) {
9867                         LOGD("incoming display surface type is same as previous one, do nothing..");
9868                         MMPLAYER_FLEAVE();
9869                         return MM_ERROR_NONE;
9870                 }
9871         } else {
9872                 LOGE("failed to load attributes");
9873                 MMPLAYER_FLEAVE();
9874                 return MM_ERROR_PLAYER_INTERNAL;
9875         }
9876
9877         /* check videosink element is created */
9878         if (!player->pipeline || !player->pipeline->videobin ||
9879                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
9880                 LOGD("videosink element is not yet ready");
9881
9882                 /* videobin is not created yet, so we just set attributes related to display surface */
9883                 LOGD("store display attribute for given surface type(%d)", surface_type);
9884                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
9885                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
9886                 if (mmf_attrs_commit(player->attrs)) {
9887                         LOGE("failed to commit attribute");
9888                         MMPLAYER_FLEAVE();
9889                         return MM_ERROR_PLAYER_INTERNAL;
9890                 }
9891                 MMPLAYER_FLEAVE();
9892                 return MM_ERROR_NONE;
9893         } else {
9894                 /* get player command status */
9895                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
9896                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
9897                         MMPLAYER_FLEAVE();
9898                         return MM_ERROR_PLAYER_INVALID_STATE;
9899                 }
9900
9901                 /* surface change */
9902                 for (i = 0 ; i < num_of_dec ; i++) {
9903                         if (player->pipeline->mainbin &&
9904                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
9905                                 GstElementFactory *decfactory;
9906                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
9907
9908                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
9909                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
9910                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
9911                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
9912                                                 if (ret) {
9913                                                         goto ERROR_CASE;
9914                                                 } else {
9915                                                         LOGW("success to changing display surface(%d)", surface_type);
9916                                                         MMPLAYER_FLEAVE();
9917                                                         return MM_ERROR_NONE;
9918                                                 }
9919                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
9920                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
9921                                                 if (ret) {
9922                                                         goto ERROR_CASE;
9923                                                 } else {
9924                                                         LOGW("success to changing display surface(%d)", surface_type);
9925                                                         MMPLAYER_FLEAVE();
9926                                                         return MM_ERROR_NONE;
9927                                                 }
9928                                         } else {
9929                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
9930                                                 ret = MM_ERROR_PLAYER_INTERNAL;
9931                                                 goto ERROR_CASE;
9932                                         }
9933                                 }
9934                         }
9935                 }
9936         }
9937
9938 ERROR_CASE:
9939         /* rollback to previous attributes */
9940         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
9941         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
9942         if (mmf_attrs_commit(player->attrs)) {
9943                 LOGE("failed to commit attributes to rollback");
9944                 MMPLAYER_FLEAVE();
9945                 return MM_ERROR_PLAYER_INTERNAL;
9946         }
9947         MMPLAYER_FLEAVE();
9948         return ret;
9949 }
9950
9951 /* NOTE : It does not support some use cases, eg using colorspace converter */
9952 int
9953 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
9954 {
9955         GstPad *src_pad_dec = NULL;
9956         GstPad *sink_pad_videosink = NULL;
9957         GstPad *sink_pad_videobin = NULL;
9958         GstClock *clock = NULL;
9959         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
9960         int ret = MM_ERROR_NONE;
9961         gboolean is_audiobin_created = TRUE;
9962
9963         MMPLAYER_FENTER();
9964
9965         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
9966         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
9967         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
9968
9969         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
9970         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
9971
9972         /* get information whether if audiobin is created */
9973         if (!player->pipeline->audiobin ||
9974                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
9975                 LOGW("audiobin is null, this video content may not have audio data");
9976                 is_audiobin_created = FALSE;
9977         }
9978
9979         /* get current state of player */
9980         previous_state = MMPLAYER_CURRENT_STATE(player);
9981         LOGD("previous state(%d)", previous_state);
9982
9983
9984         /* get src pad of decoder and block it */
9985         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
9986         if (!src_pad_dec) {
9987                 LOGE("failed to get src pad from decode in mainbin");
9988                 return MM_ERROR_PLAYER_INTERNAL;
9989         }
9990
9991         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
9992                 LOGW("trying to block pad(video)");
9993 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
9994                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
9995                         NULL, NULL, NULL);
9996                 {
9997                         LOGE("failed to set block pad(video)");
9998                         return MM_ERROR_PLAYER_INTERNAL;
9999                 }
10000                 LOGW("pad is blocked(video)");
10001         } else {
10002                 /* no data flows, so no need to do pad_block */
10003                 if (player->seek_state != MMPLAYER_SEEK_NONE)
10004                         LOGW("not completed seek(%d), do nothing", player->seek_state);
10005
10006                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
10007         }
10008
10009         /* remove pad */
10010         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
10011                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
10012                 LOGE("failed to remove previous ghost_pad for videobin");
10013                 return MM_ERROR_PLAYER_INTERNAL;
10014         }
10015
10016         /* change state of videobin to NULL */
10017         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
10018         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
10019         if (ret != GST_STATE_CHANGE_SUCCESS) {
10020                 LOGE("failed to change state of videobin to NULL");
10021                 return MM_ERROR_PLAYER_INTERNAL;
10022         }
10023
10024         /* unlink between decoder and videobin and remove previous videosink from videobin */
10025         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
10026         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
10027                 LOGE("failed to remove former videosink from videobin");
10028                 return MM_ERROR_PLAYER_INTERNAL;
10029         }
10030
10031         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10032
10033         /* create a new videosink and add it to videobin */
10034         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
10035         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
10036                 LOGE("failed to create videosink element\n");
10037                 MMPLAYER_FLEAVE();
10038                 return MM_ERROR_PLAYER_INTERNAL;
10039         }
10040         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
10041         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10042         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
10043
10044         /* save attributes */
10045         if (player->attrs) {
10046                 /* set a new display surface type */
10047                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
10048                 /* set a new diplay overlay */
10049                 switch (surface_type) {
10050                 case MM_DISPLAY_SURFACE_OVERLAY:
10051                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
10052                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
10053                         break;
10054                 default:
10055                         LOGE("invalid type(%d) for changing display surface", surface_type);
10056                         MMPLAYER_FLEAVE();
10057                         return MM_ERROR_INVALID_ARGUMENT;
10058                 }
10059                 if (mmf_attrs_commit(player->attrs)) {
10060                         LOGE("failed to commit");
10061                         MMPLAYER_FLEAVE();
10062                         return MM_ERROR_PLAYER_INTERNAL;
10063                 }
10064         } else {
10065                 LOGE("player->attrs is null, failed to save attributes");
10066                 MMPLAYER_FLEAVE();
10067                 return MM_ERROR_PLAYER_INTERNAL;
10068         }
10069
10070         /* update video param */
10071         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
10072                 LOGE("failed to update video param");
10073                 return MM_ERROR_PLAYER_INTERNAL;
10074         }
10075
10076         /* change state of videobin to READY */
10077         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
10078         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
10079         if (ret != GST_STATE_CHANGE_SUCCESS) {
10080                 LOGE("failed to change state of videobin to READY");
10081                 return MM_ERROR_PLAYER_INTERNAL;
10082         }
10083
10084         /* change ghostpad */
10085         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
10086         if (!sink_pad_videosink) {
10087                 LOGE("failed to get sink pad from videosink element");
10088                 return MM_ERROR_PLAYER_INTERNAL;
10089         }
10090         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
10091         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
10092                 LOGE("failed to set active to ghost_pad");
10093                 return MM_ERROR_PLAYER_INTERNAL;
10094         }
10095         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
10096                 LOGE("failed to change ghostpad for videobin");
10097                 return MM_ERROR_PLAYER_INTERNAL;
10098         }
10099         gst_object_unref(sink_pad_videosink);
10100
10101         /* link decoder with videobin */
10102         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
10103         if (!sink_pad_videobin) {
10104                 LOGE("failed to get sink pad from videobin");
10105                 return MM_ERROR_PLAYER_INTERNAL;
10106         }
10107         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
10108                 LOGE("failed to link");
10109                 return MM_ERROR_PLAYER_INTERNAL;
10110         }
10111         gst_object_unref(sink_pad_videobin);
10112
10113         /* clock setting for a new videosink plugin */
10114         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
10115                         so we set it from audiosink plugin or pipeline(system clock) */
10116         if (!is_audiobin_created) {
10117                 LOGW("audiobin is not created, get clock from pipeline..");
10118                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
10119         } else {
10120                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10121         }
10122         if (clock) {
10123                 GstClockTime now;
10124                 GstClockTime base_time;
10125                 LOGD("set the clock to videosink");
10126                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
10127                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10128                 if (clock) {
10129                         LOGD("got clock of videosink");
10130                         now = gst_clock_get_time(clock);
10131                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
10132                         LOGD("at time %" GST_TIME_FORMAT ", base %"
10133                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
10134                 } else {
10135                         LOGE("failed to get clock of videosink after setting clock");
10136                         return MM_ERROR_PLAYER_INTERNAL;
10137                 }
10138         } else
10139                 LOGW("failed to get clock, maybe it is the time before first playing");
10140
10141         if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
10142                 /* change state of videobin to PAUSED */
10143                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
10144                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
10145                 if (ret != GST_STATE_CHANGE_FAILURE) {
10146                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
10147                 } else {
10148                         LOGE("failed to change state of videobin to PLAYING");
10149                         return MM_ERROR_PLAYER_INTERNAL;
10150                 }
10151
10152                 /* release blocked and unref src pad of video decoder */
10153                 #if 0
10154                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
10155                         LOGE("failed to set pad blocked FALSE(video)");
10156                         return MM_ERROR_PLAYER_INTERNAL;
10157                 }
10158                 #endif
10159                 LOGW("pad is unblocked(video)");
10160         } else {
10161                 if (player->seek_state != MMPLAYER_SEEK_NONE)
10162                         LOGW("not completed seek(%d)", player->seek_state);
10163                 /* change state of videobin to PAUSED */
10164                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
10165                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
10166                 if (ret != GST_STATE_CHANGE_FAILURE) {
10167                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
10168                 } else {
10169                         LOGE("failed to change state of videobin to PLAYING");
10170                         return MM_ERROR_PLAYER_INTERNAL;
10171                 }
10172
10173                 /* already skipped pad block */
10174                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
10175         }
10176
10177         /* do get/set position for new videosink plugin */
10178         {
10179                 gint64 position = 0;
10180
10181                 LOGD("do get/set position for new videosink plugin");
10182                 if (__mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
10183                         LOGE("failed to get position");
10184                         return MM_ERROR_PLAYER_INTERNAL;
10185                 }
10186 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
10187                 /* accurate seek */
10188                 if (__mmplayer_gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
10189                         LOGE("failed to set position");
10190                         return MM_ERROR_PLAYER_INTERNAL;
10191                 }
10192 #else
10193                 /* key unit seek */
10194                 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
10195                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
10196                                                         GST_SEEK_TYPE_SET, position,
10197                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
10198                 if (!ret) {
10199                         LOGE("failed to set position");
10200                         return MM_ERROR_PLAYER_INTERNAL;
10201                 }
10202 #endif
10203         }
10204
10205         if (src_pad_dec)
10206                 gst_object_unref(src_pad_dec);
10207         LOGD("success to change sink");
10208
10209         MMPLAYER_FLEAVE();
10210
10211         return MM_ERROR_NONE;
10212 }
10213
10214
10215 /* Note : if silent is true, then subtitle would not be displayed. :*/
10216 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
10217 {
10218         mm_player_t* player = (mm_player_t*) hplayer;
10219
10220         MMPLAYER_FENTER();
10221
10222         /* check player handle */
10223         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10224
10225         player->set_mode.subtitle_off = silent;
10226
10227         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
10228
10229         MMPLAYER_FLEAVE();
10230
10231         return MM_ERROR_NONE;
10232 }
10233
10234 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
10235 {
10236         MMPlayerGstElement* mainbin = NULL;
10237         MMPlayerGstElement* textbin = NULL;
10238         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
10239         GstState current_state = GST_STATE_VOID_PENDING;
10240         GstState element_state = GST_STATE_VOID_PENDING;
10241         GstState element_pending_state = GST_STATE_VOID_PENDING;
10242         gint64 time = 0;
10243         GstEvent *event = NULL;
10244         int result = MM_ERROR_NONE;
10245
10246         GstClock *curr_clock = NULL;
10247         GstClockTime base_time, start_time, curr_time;
10248
10249
10250         MMPLAYER_FENTER();
10251
10252         /* check player handle */
10253         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
10254                                                                 player->pipeline &&
10255                                                                 player->pipeline->mainbin &&
10256                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10257
10258         mainbin = player->pipeline->mainbin;
10259         textbin = player->pipeline->textbin;
10260
10261         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10262
10263         // sync clock with current pipeline
10264         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
10265         curr_time = gst_clock_get_time(curr_clock);
10266
10267         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
10268         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
10269
10270         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
10271                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
10272
10273         if (current_state > GST_STATE_READY) {
10274                 // sync state with current pipeline
10275                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
10276                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
10277                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
10278
10279                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
10280                 if (GST_STATE_CHANGE_FAILURE == ret) {
10281                         LOGE("fail to state change.\n");
10282                         result = MM_ERROR_PLAYER_INTERNAL;
10283                         goto ERROR;
10284                 }
10285         }
10286
10287         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
10288         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
10289
10290         if (curr_clock) {
10291                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
10292                 gst_object_unref(curr_clock);
10293         }
10294
10295         // seek to current position
10296         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
10297                 result = MM_ERROR_PLAYER_INVALID_STATE;
10298                 LOGE("gst_element_query_position failed, invalid state\n");
10299                 goto ERROR;
10300         }
10301
10302         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
10303         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
10304         if (event) {
10305                 __mmplayer_gst_send_event_to_sink(player, event);
10306         } else {
10307                 result = MM_ERROR_PLAYER_INTERNAL;
10308                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
10309                 goto ERROR;
10310         }
10311
10312         /* sync state with current pipeline */
10313         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
10314         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
10315         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
10316
10317         return MM_ERROR_NONE;
10318
10319 ERROR:
10320         /* release text pipeline resource */
10321         player->textsink_linked = 0;
10322
10323         /* release signal */
10324         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
10325
10326         /* release textbin with it's childs */
10327         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
10328         MMPLAYER_FREEIF(player->pipeline->textbin);
10329         player->pipeline->textbin = NULL;
10330
10331         /* release subtitle elem */
10332         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
10333         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
10334
10335         return result;
10336 }
10337
10338 static int
10339 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
10340 {
10341         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
10342         GstState current_state = GST_STATE_VOID_PENDING;
10343
10344         MMHandleType attrs = 0;
10345         MMPlayerGstElement* mainbin = NULL;
10346         MMPlayerGstElement* textbin = NULL;
10347
10348         gchar* subtitle_uri = NULL;
10349         int result = MM_ERROR_NONE;
10350         const gchar *charset = NULL;
10351
10352         MMPLAYER_FENTER();
10353
10354         /* check player handle */
10355         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
10356                                                                 player->pipeline &&
10357                                                                 player->pipeline->mainbin &&
10358                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10359         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
10360
10361         mainbin = player->pipeline->mainbin;
10362         textbin = player->pipeline->textbin;
10363
10364         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10365         if (current_state < GST_STATE_READY) {
10366                 result = MM_ERROR_PLAYER_INVALID_STATE;
10367                 LOGE("Pipeline is not in proper state\n");
10368                 goto EXIT;
10369         }
10370
10371         attrs = MMPLAYER_GET_ATTRS(player);
10372         if (!attrs) {
10373                 LOGE("cannot get content attribute\n");
10374                 result = MM_ERROR_PLAYER_INTERNAL;
10375                 goto EXIT;
10376         }
10377
10378         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
10379         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
10380                 LOGE("subtitle uri is not proper filepath\n");
10381                 result = MM_ERROR_PLAYER_INVALID_URI;
10382                 goto EXIT;
10383         }
10384
10385         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
10386                 LOGE("failed to get storage info of subtitle path");
10387                 result = MM_ERROR_PLAYER_INVALID_URI;
10388                 goto EXIT;
10389         }
10390
10391         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
10392         LOGD("new subtitle file path is [%s]\n", filepath);
10393
10394         if (!strcmp(filepath, subtitle_uri)) {
10395                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
10396                 goto EXIT;
10397         } else {
10398                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10399                 if (mmf_attrs_commit(player->attrs)) {
10400                         LOGE("failed to commit.\n");
10401                         goto EXIT;
10402                 }
10403         }
10404
10405         //gst_pad_set_blocked_async(src-srcpad, TRUE)
10406         MMPLAYER_SUBTITLE_INFO_LOCK(player);
10407         player->subtitle_language_list = NULL;
10408         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
10409
10410         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
10411         if (ret != GST_STATE_CHANGE_SUCCESS) {
10412                 LOGE("failed to change state of textbin to READY");
10413                 result = MM_ERROR_PLAYER_INTERNAL;
10414                 goto EXIT;
10415         }
10416
10417         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
10418         if (ret != GST_STATE_CHANGE_SUCCESS) {
10419                 LOGE("failed to change state of subparse to READY");
10420                 result = MM_ERROR_PLAYER_INTERNAL;
10421                 goto EXIT;
10422         }
10423
10424         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
10425         if (ret != GST_STATE_CHANGE_SUCCESS) {
10426                 LOGE("failed to change state of filesrc to READY");
10427                 result = MM_ERROR_PLAYER_INTERNAL;
10428                 goto EXIT;
10429         }
10430
10431         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
10432
10433         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
10434
10435         charset = util_get_charset(filepath);
10436         if (charset) {
10437                 LOGD("detected charset is %s\n", charset);
10438                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
10439         }
10440
10441         result = _mmplayer_sync_subtitle_pipeline(player);
10442
10443 EXIT:
10444         MMPLAYER_FLEAVE();
10445         return result;
10446 }
10447
10448 /* API to switch between external subtitles */
10449 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
10450 {
10451         int result = MM_ERROR_NONE;
10452         mm_player_t* player = (mm_player_t*)hplayer;
10453         char *path = NULL;
10454
10455         MMPLAYER_FENTER();
10456
10457         /* check player handle */
10458         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10459
10460         /* filepath can be null in idle state */
10461         if (filepath) {
10462                 /* check file path */
10463                 if ((path = strstr(filepath, "file://")))
10464                         result = util_exist_file_path(path + 7);
10465                 else
10466                         result = util_exist_file_path(filepath);
10467
10468                 if (result != MM_ERROR_NONE) {
10469                         LOGE("invalid subtitle path 0x%X", result);
10470                         return result; /* file not found or permission denied */
10471                 }
10472         }
10473
10474         if (!player->pipeline) {
10475                 /* IDLE state */
10476                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10477                 if (mmf_attrs_commit(player->attrs)) {
10478                         LOGE("failed to commit");       /* subtitle path will not be created */
10479                         return MM_ERROR_PLAYER_INTERNAL;
10480                 }
10481         } else {
10482                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
10483                 /* check filepath */
10484                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
10485
10486                 if (!__mmplayer_check_subtitle(player)) {
10487                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10488                         if (mmf_attrs_commit(player->attrs)) {
10489                                 LOGE("failed to commit");
10490                                 return MM_ERROR_PLAYER_INTERNAL;
10491                         }
10492
10493                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
10494                                 LOGE("fail to create text pipeline");
10495                                 return MM_ERROR_PLAYER_INTERNAL;
10496                         }
10497
10498                         result = _mmplayer_sync_subtitle_pipeline(player);
10499                 } else {
10500                         result = __mmplayer_change_external_subtitle_language(player, filepath);
10501                 }
10502
10503                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
10504                 player->is_external_subtitle_added_now = TRUE;
10505
10506                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
10507                 if (!player->subtitle_language_list) {
10508                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
10509                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
10510                                 LOGW("subtitle language list is not updated yet");
10511                 }
10512                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
10513         }
10514
10515         MMPLAYER_FLEAVE();
10516         return result;
10517 }
10518
10519 static int
10520 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
10521 {
10522         int result = MM_ERROR_NONE;
10523         gchar* change_pad_name = NULL;
10524         GstPad* sinkpad = NULL;
10525         MMPlayerGstElement* mainbin = NULL;
10526         enum MainElementID elemId = MMPLAYER_M_NUM;
10527         GstCaps* caps = NULL;
10528         gint total_track_num = 0;
10529
10530         MMPLAYER_FENTER();
10531
10532         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
10533                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
10534
10535         LOGD("Change Track(%d) to %d\n", type, index);
10536
10537         mainbin = player->pipeline->mainbin;
10538
10539         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
10540                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
10541         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
10542                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
10543         } else {
10544                 /* Changing Video Track is not supported. */
10545                 LOGE("Track Type Error\n");
10546                 goto EXIT;
10547         }
10548
10549         if (mainbin[elemId].gst == NULL) {
10550                 result = MM_ERROR_PLAYER_NO_OP;
10551                 LOGD("Req track doesn't exist\n");
10552                 goto EXIT;
10553         }
10554
10555         total_track_num = player->selector[type].total_track_num;
10556         if (total_track_num <= 0) {
10557                 result = MM_ERROR_PLAYER_NO_OP;
10558                 LOGD("Language list is not available \n");
10559                 goto EXIT;
10560         }
10561
10562         if ((index < 0) || (index >= total_track_num)) {
10563                 result = MM_ERROR_INVALID_ARGUMENT;
10564                 LOGD("Not a proper index : %d \n", index);
10565                 goto EXIT;
10566         }
10567
10568         /*To get the new pad from the selector*/
10569         change_pad_name = g_strdup_printf("sink_%u", index);
10570         if (change_pad_name == NULL) {
10571                 result = MM_ERROR_PLAYER_INTERNAL;
10572                 LOGD("Pad does not exists\n");
10573                 goto EXIT;
10574         }
10575
10576         LOGD("new active pad name: %s\n", change_pad_name);
10577
10578         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
10579         if (sinkpad == NULL) {
10580                 LOGD("sinkpad is NULL");
10581                 result = MM_ERROR_PLAYER_INTERNAL;
10582                 goto EXIT;
10583         }
10584
10585         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
10586         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
10587
10588         caps = gst_pad_get_current_caps(sinkpad);
10589         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10590
10591         if (sinkpad)
10592                 gst_object_unref(sinkpad);
10593
10594         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
10595                 __mmplayer_set_audio_attrs(player, caps);
10596
10597 EXIT:
10598
10599         MMPLAYER_FREEIF(change_pad_name);
10600         return result;
10601 }
10602
10603 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
10604 {
10605         int result = MM_ERROR_NONE;
10606         mm_player_t* player = NULL;
10607         MMPlayerGstElement* mainbin = NULL;
10608
10609         gint current_active_index = 0;
10610
10611         GstState current_state = GST_STATE_VOID_PENDING;
10612         GstEvent* event = NULL;
10613         gint64 time = 0;
10614
10615         MMPLAYER_FENTER();
10616
10617         player = (mm_player_t*)hplayer;
10618         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10619
10620         if (!player->pipeline) {
10621                 LOGE("Track %d pre setting -> %d\n", type, index);
10622
10623                 player->selector[type].active_pad_index = index;
10624                 goto EXIT;
10625         }
10626
10627         mainbin = player->pipeline->mainbin;
10628
10629         current_active_index = player->selector[type].active_pad_index;
10630
10631         /*If index is same as running index no need to change the pad*/
10632         if (current_active_index == index)
10633                 goto EXIT;
10634
10635         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
10636                 result = MM_ERROR_PLAYER_INVALID_STATE;
10637                 goto EXIT;
10638         }
10639
10640         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10641         if (current_state < GST_STATE_PAUSED) {
10642                 result = MM_ERROR_PLAYER_INVALID_STATE;
10643                 LOGW("Pipeline not in porper state\n");
10644                 goto EXIT;
10645         }
10646
10647         result = __mmplayer_change_selector_pad(player, type, index);
10648         if (result != MM_ERROR_NONE) {
10649                 LOGE("change selector pad error\n");
10650                 goto EXIT;
10651         }
10652
10653         player->selector[type].active_pad_index = index;
10654
10655         if (current_state == GST_STATE_PLAYING) {
10656                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
10657                 if (event) {
10658                         __mmplayer_gst_send_event_to_sink(player, event);
10659                 } else {
10660                         result = MM_ERROR_PLAYER_INTERNAL;
10661                         goto EXIT;
10662                 }
10663         }
10664
10665 EXIT:
10666         return result;
10667 }
10668
10669 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
10670 {
10671         mm_player_t* player = (mm_player_t*) hplayer;
10672
10673         MMPLAYER_FENTER();
10674
10675         /* check player handle */
10676         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10677
10678         *silent = player->set_mode.subtitle_off;
10679
10680         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
10681
10682         MMPLAYER_FLEAVE();
10683
10684         return MM_ERROR_NONE;
10685 }
10686
10687 int
10688 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
10689 {
10690         mm_player_t* player = (mm_player_t*) hplayer;
10691
10692         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10693
10694         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
10695                 MMPLAYER_PRINT_STATE(player);
10696                 LOGE("wrong-state : can't set the download mode to parse");
10697                 return MM_ERROR_PLAYER_INVALID_STATE;
10698         }
10699
10700         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
10701         player->video_hub_download_mode = mode;
10702
10703         return MM_ERROR_NONE;
10704 }
10705
10706 int
10707 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
10708 {
10709         mm_player_t* player = (mm_player_t*) hplayer;
10710
10711         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10712
10713         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
10714         player->sync_handler = enable;
10715
10716         return MM_ERROR_NONE;
10717 }
10718
10719 int
10720 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
10721                                                                                 gint64 video_time, gint64 media_clock, gint64 audio_time)
10722 {
10723         mm_player_t* player = (mm_player_t*) hplayer;
10724         MMPlayerGstElement* mainbin = NULL;
10725         GstClockTime start_time_audio = 0, start_time_video = 0;
10726         GstClockTimeDiff base_time = 0, new_base_time = 0;
10727         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10728         gint64 api_delta = 0;
10729         gint64 position = 0, position_delta = 0;
10730         gint64 adj_base_time = 0;
10731         GstClock *curr_clock = NULL;
10732         GstClockTime curr_time = 0;
10733         gboolean query_ret = TRUE;
10734         int result = MM_ERROR_NONE;
10735
10736         MMPLAYER_FENTER();
10737
10738         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10739         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10740         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
10741
10742         /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
10743                                                                         clock, clock_delta, video_time, media_clock, audio_time); */
10744
10745         if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
10746                 LOGD("skip setting master clock. %lld", video_time);
10747                 goto EXIT;
10748         }
10749
10750         mainbin = player->pipeline->mainbin;
10751
10752         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
10753         curr_time = gst_clock_get_time(curr_clock);
10754
10755         current_state = MMPLAYER_CURRENT_STATE(player);
10756
10757         if (current_state == MM_PLAYER_STATE_PLAYING)
10758                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
10759
10760         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
10761                 (!query_ret)) {
10762                 position = player->last_position;
10763                 LOGD("query fail. %"G_GINT64_FORMAT, position);
10764         }
10765
10766         clock *= GST_USECOND;
10767         clock_delta *= GST_USECOND;
10768
10769         api_delta = clock - curr_time;
10770         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
10771                 player->video_share_api_delta = api_delta;
10772         else
10773                 clock_delta += (api_delta - player->video_share_api_delta);
10774
10775         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
10776                 player->video_share_clock_delta = (gint64)clock_delta;
10777
10778                 position_delta = (position/GST_USECOND) - video_time;
10779                 position_delta *= GST_USECOND;
10780
10781                 adj_base_time = position_delta;
10782                 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
10783
10784         } else {
10785                 gint64 new_play_time = 0;
10786                 gint64 network_delay = 0;
10787
10788                 video_time *= GST_USECOND;
10789
10790                 network_delay = clock_delta - player->video_share_clock_delta;
10791                 new_play_time = video_time + network_delay;
10792
10793                 adj_base_time = position - new_play_time;
10794
10795                 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
10796                          "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
10797                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
10798         }
10799
10800         /* Adjust Current Stream Time with base_time of sink
10801          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
10802          * 2. Set new base time
10803          *    if adj_base_time is positive value, the stream time will be decreased.
10804          * 3. If seek event is occurred, the start time will be reset. */
10805         if ((player->pipeline->audiobin) &&
10806                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
10807                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10808
10809                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
10810                         LOGD("audio sink : gst_element_set_start_time -> NONE");
10811                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
10812                 }
10813
10814                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10815         }
10816
10817         if ((player->pipeline->videobin) &&
10818                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
10819                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10820
10821                 if (start_time_video != GST_CLOCK_TIME_NONE) {
10822                         LOGD("video sink : gst_element_set_start_time -> NONE");
10823                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
10824                 }
10825
10826                 // if videobin exist, get base_time from videobin.
10827                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10828         }
10829
10830         new_base_time = base_time + adj_base_time;
10831
10832         if ((player->pipeline->audiobin) &&
10833                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
10834                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
10835
10836         if ((player->pipeline->videobin) &&
10837                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
10838                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
10839
10840 EXIT:
10841         MMPLAYER_FLEAVE();
10842
10843         return result;
10844 }
10845
10846 int
10847 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
10848 {
10849         mm_player_t* player = (mm_player_t*) hplayer;
10850         MMPlayerGstElement* mainbin = NULL;
10851         GstClock *curr_clock = NULL;
10852         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10853         gint64 position = 0;
10854         gboolean query_ret = TRUE;
10855
10856         MMPLAYER_FENTER();
10857
10858         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10859         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10860         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
10861
10862         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
10863         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
10864         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
10865
10866         mainbin = player->pipeline->mainbin;
10867
10868         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
10869
10870         current_state = MMPLAYER_CURRENT_STATE(player);
10871
10872         if (current_state != MM_PLAYER_STATE_PAUSED)
10873                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
10874
10875         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
10876                 (!query_ret))
10877                 position = player->last_position;
10878
10879         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
10880
10881         LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
10882
10883         if (curr_clock)
10884                 gst_object_unref(curr_clock);
10885
10886         MMPLAYER_FLEAVE();
10887
10888         return MM_ERROR_NONE;
10889 }
10890
10891 static gboolean
10892 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
10893 {
10894         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10895         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
10896
10897         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
10898         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
10899
10900         int idx = 0;
10901
10902         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
10903                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
10904                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
10905                         mm_player_dump_t *dump_s;
10906                         dump_s = g_malloc(sizeof(mm_player_dump_t));
10907
10908                         if (dump_s == NULL) {
10909                                 LOGE("malloc fail");
10910                                 return FALSE;
10911                         }
10912
10913                         dump_s->dump_element_file = NULL;
10914                         dump_s->dump_pad = NULL;
10915                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
10916
10917                         if (dump_s->dump_pad) {
10918                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
10919                                 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]);
10920                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
10921                                 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);
10922                                 /* add list for removed buffer probe and close FILE */
10923                                 player->dump_list = g_list_append(player->dump_list, dump_s);
10924                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
10925                                 return TRUE;
10926                         } else {
10927                                 g_free(dump_s);
10928                                 dump_s = NULL;
10929                                 LOGE("failed to get %s sink pad added", factory_name);
10930                         }
10931
10932
10933                 }
10934         }
10935         return FALSE;
10936 }
10937
10938 static GstPadProbeReturn
10939 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
10940 {
10941         FILE *dump_data = (FILE *) u_data;
10942 //      int written = 0;
10943         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
10944         GstMapInfo probe_info = GST_MAP_INFO_INIT;
10945
10946         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
10947
10948         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
10949
10950 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
10951
10952         fwrite(probe_info.data, 1, probe_info.size , dump_data);
10953
10954         return GST_PAD_PROBE_OK;
10955 }
10956
10957 static void
10958 __mmplayer_release_dump_list(GList *dump_list)
10959 {
10960         if (dump_list) {
10961                 GList *d_list = dump_list;
10962                 for (; d_list; d_list = g_list_next(d_list)) {
10963                         mm_player_dump_t *dump_s = d_list->data;
10964                         if (dump_s->dump_pad) {
10965                                 if (dump_s->probe_handle_id)
10966                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
10967                         }
10968                         if (dump_s->dump_element_file) {
10969                                 fclose(dump_s->dump_element_file);
10970                                 dump_s->dump_element_file = NULL;
10971                         }
10972                         MMPLAYER_FREEIF(dump_s);
10973                 }
10974                 g_list_free(dump_list);
10975                 dump_list = NULL;
10976         }
10977 }
10978
10979 int
10980 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
10981 {
10982         mm_player_t* player = (mm_player_t*) hplayer;
10983
10984         MMPLAYER_FENTER();
10985
10986         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10987         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
10988
10989         *exist = player->has_closed_caption;
10990
10991         MMPLAYER_FLEAVE();
10992
10993         return MM_ERROR_NONE;
10994 }
10995
10996 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
10997 {
10998         MMPLAYER_FENTER();
10999         if (buffer) {
11000                 // LOGD("unref internal gst buffer %p", buffer);
11001                 gst_buffer_unref((GstBuffer *)buffer);
11002                 buffer = NULL;
11003         }
11004         MMPLAYER_FLEAVE();
11005 }
11006
11007 void
11008 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
11009 {
11010         mm_player_t *player  = (mm_player_t*)user_data;
11011         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11012         guint64 current_level_bytes = 0;
11013
11014         MMPLAYER_RETURN_IF_FAIL(player);
11015
11016         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
11017
11018         LOGI("app-src: feed audio(%llu)", current_level_bytes);
11019         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11020
11021         if (player->media_stream_buffer_status_cb[type])
11022                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11023         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11024
11025 }
11026
11027 void
11028 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
11029 {
11030         mm_player_t *player  = (mm_player_t*)user_data;
11031         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11032         guint64 current_level_bytes = 0;
11033
11034         MMPLAYER_RETURN_IF_FAIL(player);
11035
11036         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
11037
11038         LOGI("app-src: feed video(%llu)", current_level_bytes);
11039
11040         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11041         if (player->media_stream_buffer_status_cb[type])
11042                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11043         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11044 }
11045
11046 void
11047 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
11048 {
11049         mm_player_t *player  = (mm_player_t*)user_data;
11050         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
11051         guint64 current_level_bytes = 0;
11052
11053         MMPLAYER_RETURN_IF_FAIL(player);
11054
11055         LOGI("app-src: feed subtitle");
11056
11057         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
11058
11059         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11060         if (player->media_stream_buffer_status_cb[type])
11061                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11062
11063         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11064 }
11065
11066 void
11067 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
11068 {
11069         mm_player_t *player  = (mm_player_t*)user_data;
11070         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11071         guint64 current_level_bytes = 0;
11072
11073         MMPLAYER_RETURN_IF_FAIL(player);
11074
11075         LOGI("app-src: audio buffer is full");
11076
11077         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
11078
11079         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11080
11081         if (player->media_stream_buffer_status_cb[type])
11082                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
11083
11084         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11085 }
11086
11087 void
11088 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
11089 {
11090         mm_player_t *player  = (mm_player_t*)user_data;
11091         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11092         guint64 current_level_bytes = 0;
11093
11094         MMPLAYER_RETURN_IF_FAIL(player);
11095
11096         LOGI("app-src: video buffer is full");
11097
11098         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
11099
11100         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11101         if (player->media_stream_buffer_status_cb[type])
11102                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
11103
11104         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11105 }
11106
11107 gboolean
11108 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
11109 {
11110         mm_player_t *player  = (mm_player_t*)user_data;
11111         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11112
11113         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11114
11115         LOGD("app-src: seek audio data %llu", position);
11116         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11117
11118         if (player->media_stream_seek_data_cb[type])
11119                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11120         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11121
11122         return TRUE;
11123 }
11124
11125 gboolean
11126 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
11127 {
11128         mm_player_t *player  = (mm_player_t*)user_data;
11129         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11130
11131         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11132
11133         LOGD("app-src: seek video data %llu", position);
11134         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11135         if (player->media_stream_seek_data_cb[type])
11136                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11137         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11138
11139         return TRUE;
11140 }
11141
11142 gboolean
11143 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
11144 {
11145         mm_player_t *player  = (mm_player_t*)user_data;
11146         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
11147
11148         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11149
11150         LOGD("app-src: seek subtitle data");
11151         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11152
11153         if (player->media_stream_seek_data_cb[type])
11154                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11155         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11156
11157         return TRUE;
11158 }
11159
11160 int
11161 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
11162 {
11163         mm_player_t* player = (mm_player_t*) hplayer;
11164
11165         MMPLAYER_FENTER();
11166
11167         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11168
11169         player->pcm_samplerate = samplerate;
11170         player->pcm_channel = channel;
11171
11172         MMPLAYER_FLEAVE();
11173         return MM_ERROR_NONE;
11174 }
11175
11176 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
11177 {
11178         mm_player_t* player = (mm_player_t*) hplayer;
11179
11180         MMPLAYER_FENTER();
11181
11182         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11183         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
11184
11185         if (MMPLAYER_IS_HTTP_PD(player))
11186                 *timeout = player->ini.live_state_change_timeout*2;
11187         else if (MMPLAYER_IS_STREAMING(player))
11188                 *timeout = player->ini.live_state_change_timeout;
11189         else
11190                 *timeout = player->ini.localplayback_state_change_timeout;
11191
11192         LOGD("timeout = %d\n", *timeout);
11193
11194         MMPLAYER_FLEAVE();
11195         return MM_ERROR_NONE;
11196 }
11197
11198 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
11199 {
11200         mm_player_t* player = (mm_player_t*) hplayer;
11201
11202         MMPLAYER_FENTER();
11203
11204         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11205         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
11206
11207         *num = player->video_num_buffers;
11208         *extra_num = player->video_extra_num_buffers;
11209
11210         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
11211
11212         MMPLAYER_FLEAVE();
11213         return MM_ERROR_NONE;
11214 }
11215
11216 static void
11217 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
11218 {
11219         int i = 0;
11220         MMPLAYER_FENTER();
11221         MMPLAYER_RETURN_IF_FAIL(player);
11222
11223         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
11224
11225                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
11226                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
11227                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
11228                         player->storage_info[i].id = -1;
11229                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
11230
11231                         if (path_type != MMPLAYER_PATH_MAX)
11232                                 break;
11233                 }
11234         }
11235
11236         MMPLAYER_FLEAVE();
11237 }
11238
11239 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
11240 {
11241         int ret = MM_ERROR_NONE;
11242         mm_player_t* player = (mm_player_t*)hplayer;
11243         MMMessageParamType msg_param = {0, };
11244
11245         MMPLAYER_FENTER();
11246         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11247
11248         LOGW("state changed storage %d:%d", id, state);
11249
11250         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
11251                 return MM_ERROR_NONE;
11252
11253         /* FIXME: text path should be handled seperately. */
11254         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
11255                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
11256                 LOGW("external storage is removed");
11257
11258                 if (player->msg_posted == FALSE) {
11259                         memset(&msg_param, 0, sizeof(MMMessageParamType));
11260                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11261                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11262                         player->msg_posted = TRUE;
11263                 }
11264
11265                 /* unrealize the player */
11266                 ret = _mmplayer_unrealize(hplayer);
11267                 if (ret != MM_ERROR_NONE)
11268                         LOGE("failed to unrealize");
11269         }
11270
11271         MMPLAYER_FLEAVE();
11272         return ret;
11273 }
11274
11275 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
11276 {
11277         int ret = MM_ERROR_NONE;
11278         mm_player_t* player = (mm_player_t*) hplayer;
11279         int idx = 0, total = 0;
11280         gchar *result = NULL, *tmp = NULL;
11281
11282         MMPLAYER_FENTER();
11283         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11284         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
11285
11286         total = *num = g_list_length(player->adaptive_info.var_list);
11287         if (total <= 0) {
11288                 LOGW("There is no stream variant info.");
11289                 return ret;
11290         }
11291
11292         result = g_strdup("");
11293         for (idx = 0 ; idx < total ; idx++) {
11294                 VariantData *v_data = NULL;
11295                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
11296
11297                 if (v_data) {
11298                         gchar data[64] = {0};
11299                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
11300
11301                         tmp = g_strconcat(result, data, NULL);
11302                         g_free(result);
11303                         result = tmp;
11304                 } else {
11305                         LOGW("There is no variant data in %d", idx);
11306                         (*num)--;
11307                 }
11308         }
11309
11310         *var_info = (char *)result;
11311
11312         LOGD("variant info %d:%s", *num, *var_info);
11313         MMPLAYER_FLEAVE();
11314         return ret;
11315 }
11316
11317 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
11318 {
11319         int ret = MM_ERROR_NONE;
11320         mm_player_t* player = (mm_player_t*) hplayer;
11321
11322         MMPLAYER_FENTER();
11323         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11324
11325         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
11326
11327         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11328         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11329         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11330
11331         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
11332                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
11333                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11334                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
11335
11336                 /* FIXME: seek to current position for applying new variant limitation */
11337         }
11338
11339         MMPLAYER_FLEAVE();
11340         return ret;
11341
11342 }
11343
11344 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
11345 {
11346         int ret = MM_ERROR_NONE;
11347         mm_player_t* player = (mm_player_t*) hplayer;
11348
11349         MMPLAYER_FENTER();
11350         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11351         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
11352
11353         *bandwidth = player->adaptive_info.limit.bandwidth;
11354         *width = player->adaptive_info.limit.width;
11355         *height = player->adaptive_info.limit.height;
11356
11357         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
11358
11359         MMPLAYER_FLEAVE();
11360         return ret;
11361 }
11362
11363 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
11364 {
11365         int ret = MM_ERROR_NONE;
11366         mm_player_t* player = (mm_player_t*) hplayer;
11367
11368         MMPLAYER_FENTER();
11369         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11370
11371         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
11372                 LOGW("buffer_ms will not be applied.");
11373
11374
11375         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
11376
11377         if (player->streamer == NULL) {
11378                 player->streamer = __mm_player_streaming_create();
11379                 __mm_player_streaming_initialize(player->streamer);
11380         }
11381
11382         if (buffer_ms >= 0)
11383                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
11384
11385         if (rebuffer_ms >= 0)
11386                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
11387
11388         MMPLAYER_FLEAVE();
11389         return ret;
11390
11391 }
11392
11393 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
11394 {
11395         int ret = MM_ERROR_NONE;
11396         mm_player_t* player = (mm_player_t*) hplayer;
11397
11398         MMPLAYER_FENTER();
11399         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11400         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
11401
11402         if (player->streamer == NULL) {
11403                 player->streamer = __mm_player_streaming_create();
11404                 __mm_player_streaming_initialize(player->streamer);
11405         }
11406
11407         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
11408         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
11409
11410         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
11411
11412         MMPLAYER_FLEAVE();
11413         return ret;
11414 }
11415
11416 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
11417 {
11418 #define IDX_FIRST_SW_CODEC 0
11419         mm_player_t* player = (mm_player_t*) hplayer;
11420         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
11421         MMHandleType attrs = 0;
11422
11423         MMPLAYER_FENTER();
11424         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11425
11426         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
11427                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
11428                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
11429
11430         switch (stream_type) {
11431         case MM_PLAYER_STREAM_TYPE_AUDIO:
11432                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
11433                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
11434                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
11435                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
11436                         LOGE("There is no a codec for codec_type %d", codec_type);
11437                         return MM_ERROR_PLAYER_NO_OP;
11438                 }
11439         break;
11440         case MM_PLAYER_STREAM_TYPE_VIDEO:
11441                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
11442                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
11443                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
11444                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
11445                         LOGE("There is no v codec for codec_type %d", codec_type);
11446                         return MM_ERROR_PLAYER_NO_OP;
11447                 }
11448
11449         break;
11450         default:
11451                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
11452                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
11453         break;
11454         }
11455
11456         LOGD("update %s codec_type to %d", attr_name, codec_type);
11457
11458         attrs = MMPLAYER_GET_ATTRS(player);
11459         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
11460
11461         if (mmf_attrs_commit(player->attrs)) {
11462                 LOGE("failed to commit codec_type attributes");
11463                 return MM_ERROR_PLAYER_INTERNAL;
11464         }
11465
11466         MMPLAYER_FLEAVE();
11467         return MM_ERROR_NONE;
11468 }
11469
11470 int
11471 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
11472 {
11473         mm_player_t* player = (mm_player_t*) hplayer;
11474         GstElement* rg_vol_element = NULL;
11475
11476         MMPLAYER_FENTER();
11477
11478         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11479
11480         player->sound.rg_enable = enabled;
11481
11482         /* just hold rgvolume enable value if pipeline is not ready */
11483         if (!player->pipeline || !player->pipeline->audiobin) {
11484                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
11485                 return MM_ERROR_NONE;
11486         }
11487
11488         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
11489
11490         if (!rg_vol_element) {
11491                 LOGD("rgvolume element is not created");
11492                 return MM_ERROR_PLAYER_INTERNAL;
11493         }
11494
11495         if (enabled)
11496                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
11497         else
11498                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
11499
11500         MMPLAYER_FLEAVE();
11501
11502         return MM_ERROR_NONE;
11503 }
11504
11505 int
11506 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
11507 {
11508         mm_player_t* player = (mm_player_t*) hplayer;
11509         GstElement* rg_vol_element = NULL;
11510         gboolean enable = FALSE;
11511
11512         MMPLAYER_FENTER();
11513
11514         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11515         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
11516
11517         /* just hold enable_rg value if pipeline is not ready */
11518         if (!player->pipeline || !player->pipeline->audiobin) {
11519                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
11520                 *enabled = player->sound.rg_enable;
11521                 return MM_ERROR_NONE;
11522         }
11523
11524         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
11525
11526         if (!rg_vol_element) {
11527                 LOGD("rgvolume element is not created");
11528                 return MM_ERROR_PLAYER_INTERNAL;
11529         }
11530
11531         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
11532         *enabled = enable;
11533
11534         MMPLAYER_FLEAVE();
11535
11536         return MM_ERROR_NONE;
11537 }