[0.6.108] Change the way to check the track type of tag message
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
58 |                                                                                                                                                                                       |
59 ========================================================================================== */
60
61 /*---------------------------------------------------------------------------
62 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
63 ---------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------
66 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
67 ---------------------------------------------------------------------------*/
68
69 /*---------------------------------------------------------------------------
70 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
71 ---------------------------------------------------------------------------*/
72
73 /*---------------------------------------------------------------------------
74 |    LOCAL #defines:                                                                                                            |
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
78
79 #define MM_VOLUME_FACTOR_DEFAULT                1.0
80 #define MM_VOLUME_FACTOR_MIN                    0
81 #define MM_VOLUME_FACTOR_MAX                    1.0
82
83 /* Don't need to sleep for sound fadeout
84  * fadeout related fucntion will be deleted(Deprecated)
85  */
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
87
88 #define DEFAULT_PLAYBACK_RATE                   1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
90
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93         (player->ini.http_use_file_buffer) && \
94         (player->http_file_buffering_path) && \
95         (strlen(player->http_file_buffering_path) > 0))
96
97 #define PLAYER_DISPLAY_MODE_DST_ROI             5
98
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
100
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 100
103
104 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
105
106 /*---------------------------------------------------------------------------
107 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
108 ---------------------------------------------------------------------------*/
109
110 /*---------------------------------------------------------------------------
111 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
112 ---------------------------------------------------------------------------*/
113
114 /*---------------------------------------------------------------------------
115 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
116 ---------------------------------------------------------------------------*/
117
118 /*---------------------------------------------------------------------------
119 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
120 ---------------------------------------------------------------------------*/
121 static sound_stream_info_h stream_info;
122
123 /*---------------------------------------------------------------------------
124 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
125 ---------------------------------------------------------------------------*/
126 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
127 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
128 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
129 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
130 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
131 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
132 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
133
134 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
135 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
136 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
137 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
138 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
139 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
140 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
141 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
142 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
143 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
144 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
145 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
146 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
147 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
151
152 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
153 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
154 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
155 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void             __mmplayer_release_misc(mm_player_t* player);
157 static void             __mmplayer_release_misc_post(mm_player_t* player);
158 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
159 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
160 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
161 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
162 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
163 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
164 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
166 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
167 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
168 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
169
170 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
171 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
172 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
173 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
174 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
175 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
176 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
177 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
178 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
179 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
180 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
181 static gpointer __mmplayer_next_play_thread(gpointer data);
182 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
183
184 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
185 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
186 static void __mmplayer_release_dump_list(GList *dump_list);
187
188 static int              __gst_realize(mm_player_t* player);
189 static int              __gst_unrealize(mm_player_t* player);
190 static int              __gst_start(mm_player_t* player);
191 static int              __gst_stop(mm_player_t* player);
192 static int              __gst_pause(mm_player_t* player, gboolean async);
193 static int              __gst_resume(mm_player_t* player, gboolean async);
194 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
195                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
196                                         gint64 cur, GstSeekType stop_type, gint64 stop);
197 static int __gst_pending_seek(mm_player_t* player);
198
199 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
200 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
201 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
202 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
203 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
204
205 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
206
207 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
208 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
209
210 /* util */
211 static gboolean __is_ms_buff_src(mm_player_t* player);
212 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
213
214 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
215 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
216 static int __mmplayer_start_streaming_ext(mm_player_t *player);
217 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
218 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
219
220 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
221 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
222 static void __mmplayer_check_pipeline(mm_player_t* player);
223 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
224 static void __mmplayer_deactivate_old_path(mm_player_t *player);
225
226 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
227 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
228
229 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
230 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
231 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
232 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
233 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
234 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
235 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
236 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
237 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
238 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
239 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
240 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
241 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
242 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
243 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
244 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
245
246 /*===========================================================================================
247 |                                                                                                                                                                                       |
248 |  FUNCTION DEFINITIONS                                                                                                                                         |
249 |                                                                                                                                                                                       |
250 ========================================================================================== */
251
252 #if 0 //debug
253 static void
254 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
255 {
256         gint i, count;
257
258         count = gst_tag_list_get_tag_size(list, tag);
259
260         LOGD("count = %d", count);
261
262         for (i = 0; i < count; i++) {
263                 gchar *str;
264
265                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
266                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
267                                 g_assert_not_reached();
268                 } else
269                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
270
271                 if (i == 0)
272                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
273                 else
274                         g_print("                 : %s\n", str);
275
276                 g_free(str);
277         }
278 }
279 #endif
280
281 /* This function should be called after the pipeline goes PAUSED or higher
282 state. */
283 gboolean
284 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
285 {
286         static gboolean has_duration = FALSE;
287         static gboolean has_video_attrs = FALSE;
288         static gboolean has_audio_attrs = FALSE;
289         static gboolean has_bitrate = FALSE;
290         gboolean missing_only = FALSE;
291         gboolean all = FALSE;
292         gint64 dur_nsec = 0;
293         GstStructure* p = NULL;
294         MMHandleType attrs = 0;
295         gchar *path = NULL;
296         struct stat sb;
297
298         MMPLAYER_FENTER();
299
300         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
301
302         /* check player state here */
303         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
304                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
305                 /* give warning now only */
306                 LOGW("be careful. content attributes may not available in this state ");
307         }
308
309         /* get content attribute first */
310         attrs = MMPLAYER_GET_ATTRS(player);
311         if (!attrs) {
312                 LOGE("cannot get content attribute");
313                 return FALSE;
314         }
315
316         /* get update flag */
317
318         if (flag & ATTR_MISSING_ONLY) {
319                 missing_only = TRUE;
320                 LOGD("updating missed attr only");
321         }
322
323         if (flag & ATTR_ALL) {
324                 all = TRUE;
325                 has_duration = FALSE;
326                 has_video_attrs = FALSE;
327                 has_audio_attrs = FALSE;
328                 has_bitrate = FALSE;
329
330                 LOGD("updating all attrs");
331         }
332
333         if (missing_only && all) {
334                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
335                 missing_only = FALSE;
336         }
337
338         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
339                 LOGD("try to update duration");
340                 has_duration = FALSE;
341
342                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
343                         player->duration = dur_nsec;
344                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
345                 }
346
347                 if (player->duration < 0) {
348                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
349                         player->duration = 0;
350                 }
351
352                 /* update streaming service type */
353                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
354
355                 /* check duration is OK */
356                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
357                         /* FIXIT : find another way to get duration here. */
358                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
359                 } else {
360                         /*update duration */
361                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
362                         has_duration = TRUE;
363                 }
364         }
365
366         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
367                 /* update audio params
368                 NOTE : We need original audio params and it can be only obtained from src pad of audio
369                 decoder. Below code only valid when we are not using 'resampler' just before
370                 'audioconverter'. */
371
372                 LOGD("try to update audio attrs");
373                 has_audio_attrs = FALSE;
374
375                 if (player->pipeline->audiobin &&
376                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
377                         GstCaps *caps_a = NULL;
378                         GstPad* pad = NULL;
379                         gint samplerate = 0, channels = 0;
380
381                         pad = gst_element_get_static_pad(
382                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
383
384                         if (pad) {
385                                 caps_a = gst_pad_get_current_caps(pad);
386
387                                 if (caps_a) {
388                                         p = gst_caps_get_structure(caps_a, 0);
389
390                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
391
392                                         gst_structure_get_int(p, "rate", &samplerate);
393                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
394
395                                         gst_structure_get_int(p, "channels", &channels);
396                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
397
398                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
399
400                                         gst_caps_unref(caps_a);
401                                         caps_a = NULL;
402
403                                         has_audio_attrs = TRUE;
404                                 } else
405                                         LOGW("not ready to get audio caps");
406
407                                 gst_object_unref(pad);
408                         } else
409                                 LOGW("failed to get pad from audiosink");
410                 }
411         }
412
413         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
414                 LOGD("try to update video attrs");
415                 has_video_attrs = FALSE;
416
417                 if (player->pipeline->videobin &&
418                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
419                         GstCaps *caps_v = NULL;
420                         GstPad* pad = NULL;
421                         gint tmpNu, tmpDe;
422                         gint width, height;
423
424                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
425                         if (pad) {
426                                 caps_v = gst_pad_get_current_caps(pad);
427
428                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
429                                 if (!caps_v && player->v_stream_caps) {
430                                         caps_v = player->v_stream_caps;
431                                         gst_caps_ref(caps_v);
432                                 }
433
434                                 if (caps_v) {
435                                         p = gst_caps_get_structure(caps_v, 0);
436                                         gst_structure_get_int(p, "width", &width);
437                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
438
439                                         gst_structure_get_int(p, "height", &height);
440                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
441
442                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
443
444                                         SECURE_LOGD("width : %d     height : %d", width, height);
445
446                                         gst_caps_unref(caps_v);
447                                         caps_v = NULL;
448
449                                         if (tmpDe > 0) {
450                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
451                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
452                                         }
453
454                                         has_video_attrs = TRUE;
455                                 } else
456                                         LOGD("no negitiated caps from videosink");
457                                 gst_object_unref(pad);
458                                 pad = NULL;
459                         } else
460                                 LOGD("no videosink sink pad");
461                 }
462         }
463
464
465         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
466                 has_bitrate = FALSE;
467
468                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
469                 if (player->duration) {
470                         guint64 data_size = 0;
471
472                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
473                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
474
475                                 if (stat(path, &sb) == 0)
476                                         data_size = (guint64)sb.st_size;
477                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
478                                 data_size = player->http_content_size;
479                         }
480                         LOGD("try to update bitrate : data_size = %lld", data_size);
481
482                         if (data_size) {
483                                 guint64 bitrate = 0;
484                                 guint64 msec_dur = 0;
485
486                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
487                                 if (msec_dur > 0) {
488                                         bitrate = data_size * 8 * 1000 / msec_dur;
489                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
490                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
491
492                                         has_bitrate = TRUE;
493                                 } else {
494                                         LOGD("player duration is less than 0");
495                                 }
496                         }
497
498                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
499                                 if (player->total_bitrate) {
500                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
501                                         has_bitrate = TRUE;
502                                 }
503                         }
504                 }
505         }
506
507         /* validate all */
508         if (mmf_attrs_commit(attrs)) {
509                 LOGE("failed to update attributes\n");
510                 return FALSE;
511         }
512
513         MMPLAYER_FLEAVE();
514
515         return TRUE;
516 }
517
518 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
519 {
520         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
521
522         MMPLAYER_FENTER();
523
524         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
525                         player->pipeline &&
526                         player->pipeline->mainbin &&
527                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
528                         STREAMING_SERVICE_NONE);
529
530         /* streaming service type if streaming */
531         if (!MMPLAYER_IS_STREAMING(player))
532                 return STREAMING_SERVICE_NONE;
533
534         if (MMPLAYER_IS_HTTP_STREAMING(player))
535                 streaming_type = (player->duration == 0) ?
536                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
537
538         switch (streaming_type) {
539         case STREAMING_SERVICE_LIVE:
540                 LOGD("it's live streaming");
541                 break;
542         case STREAMING_SERVICE_VOD:
543                 LOGD("it's vod streaming");
544                 break;
545         default:
546                 LOGE("should not get here");
547                 break;
548         }
549
550         MMPLAYER_FLEAVE();
551
552         return streaming_type;
553 }
554
555
556 /* this function sets the player state and also report
557  * it to applicaton by calling callback function
558  */
559 int
560 __mmplayer_set_state(mm_player_t* player, int state)
561 {
562         MMMessageParamType msg = {0, };
563         gboolean post_bos = FALSE;
564
565         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
566
567         if (MMPLAYER_CURRENT_STATE(player) == state) {
568                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
569                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
570                 return MM_ERROR_NONE;
571         }
572
573         /* update player states */
574         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
575         MMPLAYER_CURRENT_STATE(player) = state;
576
577         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
578                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
579
580         /* print state */
581         MMPLAYER_PRINT_STATE(player);
582
583         switch (MMPLAYER_CURRENT_STATE(player)) {
584         case MM_PLAYER_STATE_NULL:
585         case MM_PLAYER_STATE_READY:
586                 break;
587
588         case MM_PLAYER_STATE_PAUSED:
589                 {
590                         if (!player->sent_bos) {
591                                 /* rtsp case, get content attrs by GstMessage */
592                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
593                                         /* it's first time to update all content attrs. */
594                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
595                                 }
596                         }
597
598                         /* add audio callback probe if condition is satisfied */
599                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
600                                 __mmplayer_configure_audio_callback(player);
601
602                         /* FIXIT : handle return value */
603                 }
604                 break;
605
606         case MM_PLAYER_STATE_PLAYING:
607                 {
608                         /* try to get content metadata */
609                         if (!player->sent_bos) {
610                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
611                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
612                                  * legacy mmfw-player api */
613                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
614                         }
615
616                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
617                                 if (!player->sent_bos)
618                                         __mmplayer_handle_missed_plugin(player);
619                         }
620
621                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
622                                 /* initialize because auto resume is done well. */
623                                 player->resumed_by_rewind = FALSE;
624                                 player->playback_rate = 1.0;
625                         }
626
627                         if (!player->sent_bos) {
628                                 /* check audio codec field is set or not
629                                  * we can get it from typefinder or codec's caps.
630                                  */
631                                 gchar *audio_codec = NULL;
632                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
633
634                                 /* The codec format can't be sent for audio only case like amr, mid etc.
635                                  * Because, parser don't make related TAG.
636                                  * So, if it's not set yet, fill it with found data.
637                                  */
638                                 if (!audio_codec) {
639                                         if (g_strrstr(player->type, "audio/midi"))
640                                                 audio_codec = g_strdup("MIDI");
641                                         else if (g_strrstr(player->type, "audio/x-amr"))
642                                                 audio_codec = g_strdup("AMR");
643                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
644                                                 audio_codec = g_strdup("AAC");
645                                         else
646                                                 audio_codec = g_strdup("unknown");
647                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
648
649                                         MMPLAYER_FREEIF(audio_codec);
650                                         if (mmf_attrs_commit(player->attrs))
651                                                 LOGE("failed to update attributes\n");
652
653                                         LOGD("set audio codec type with caps\n");
654                                 }
655
656                                 post_bos = TRUE;
657                         }
658                 }
659                 break;
660
661         case MM_PLAYER_STATE_NONE:
662         default:
663                 LOGW("invalid target state, there is nothing to do.\n");
664                 break;
665         }
666
667
668         /* post message to application */
669         if (MMPLAYER_TARGET_STATE(player) == state) {
670                 /* fill the message with state of player */
671                 msg.union_type = MM_MSG_UNION_STATE;
672                 msg.state.previous = MMPLAYER_PREV_STATE(player);
673                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
674
675                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
676
677                 /* state changed by resource callback */
678                 if (player->interrupted_by_resource) {
679                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
680                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
681                 } else { /* state changed by usecase */
682                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
683                 }
684         } else {
685                 LOGD("intermediate state, do nothing.\n");
686                 MMPLAYER_PRINT_STATE(player);
687                 return MM_ERROR_NONE;
688         }
689
690         if (post_bos) {
691                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
692                 player->sent_bos = TRUE;
693         }
694
695         return MM_ERROR_NONE;
696 }
697
698 static gpointer __mmplayer_next_play_thread(gpointer data)
699 {
700         mm_player_t* player = (mm_player_t*) data;
701         MMPlayerGstElement *mainbin = NULL;
702
703         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
704
705         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
706         while (!player->next_play_thread_exit) {
707                 LOGD("next play thread started. waiting for signal.\n");
708                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
709
710                 LOGD("reconfigure pipeline for gapless play.\n");
711
712                 if (player->next_play_thread_exit) {
713                         if (player->gapless.reconfigure) {
714                                 player->gapless.reconfigure = false;
715                                 MMPLAYER_PLAYBACK_UNLOCK(player);
716                         }
717                         LOGD("exiting gapless play thread\n");
718                         break;
719                 }
720
721                 mainbin = player->pipeline->mainbin;
722
723                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
724                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
725                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
726                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
728
729                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
730         }
731         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
732
733         return NULL;
734 }
735
736 static void
737 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
738 {
739         MMHandleType attrs = 0;
740         guint64 data_size = 0;
741         gchar* path = NULL;
742         unsigned long pos_msec = 0;
743         struct stat sb;
744
745         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
746
747         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
748
749         attrs = MMPLAYER_GET_ATTRS(player);
750         if (!attrs) {
751                 LOGE("fail to get attributes.\n");
752                 return;
753         }
754
755         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
756                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
757
758                 if (stat(path, &sb) == 0)
759                         data_size = (guint64)sb.st_size;
760         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
761                 data_size = player->http_content_size;
762
763         __mm_player_streaming_buffering(player->streamer,
764                                                                                 buffering_msg,
765                                                                                 data_size,
766                                                                                 player->last_position,
767                                                                                 player->duration);
768
769         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
770
771         return;
772 }
773
774 static int
775 __mmplayer_handle_buffering_message(mm_player_t* player)
776 {
777         int ret = MM_ERROR_NONE;
778         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
779         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
780         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
781         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
782
783         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
784                 LOGW("do nothing for buffering msg\n");
785                 ret = MM_ERROR_PLAYER_INVALID_STATE;
786                 goto exit;
787         }
788
789         prev_state = MMPLAYER_PREV_STATE(player);
790         current_state = MMPLAYER_CURRENT_STATE(player);
791         target_state = MMPLAYER_TARGET_STATE(player);
792         pending_state = MMPLAYER_PENDING_STATE(player);
793
794         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
795                 MMPLAYER_STATE_GET_NAME(prev_state),
796                 MMPLAYER_STATE_GET_NAME(current_state),
797                 MMPLAYER_STATE_GET_NAME(pending_state),
798                 MMPLAYER_STATE_GET_NAME(target_state),
799                 player->streamer->is_buffering);
800
801         if (!player->streamer->is_buffering) {
802                 /* NOTE : if buffering has done, player has to go to target state. */
803                 switch (target_state) {
804                 case MM_PLAYER_STATE_PAUSED:
805                         {
806                                 switch (pending_state) {
807                                 case MM_PLAYER_STATE_PLAYING:
808                                         __gst_pause(player, TRUE);
809                                         break;
810
811                                 case MM_PLAYER_STATE_PAUSED:
812                                         LOGD("player is already going to paused state, there is nothing to do.\n");
813                                         break;
814
815                                 case MM_PLAYER_STATE_NONE:
816                                 case MM_PLAYER_STATE_NULL:
817                                 case MM_PLAYER_STATE_READY:
818                                 default:
819                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
820                                         break;
821                                 }
822                         }
823                         break;
824
825                 case MM_PLAYER_STATE_PLAYING:
826                         {
827                                 switch (pending_state) {
828                                 case MM_PLAYER_STATE_NONE:
829                                         {
830                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
831                                                         __gst_resume(player, TRUE);
832                                         }
833                                         break;
834
835                                 case MM_PLAYER_STATE_PAUSED:
836                                         /* NOTE: It should be worked as asynchronously.
837                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
838                                          */
839                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
840                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
841                                                  * The current state should be changed to paused purposely to prevent state conflict.
842                                                  */
843                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
844                                         }
845                                         __gst_resume(player, TRUE);
846                                         break;
847
848                                 case MM_PLAYER_STATE_PLAYING:
849                                         LOGD("player is already going to playing state, there is nothing to do.\n");
850                                         break;
851
852                                 case MM_PLAYER_STATE_NULL:
853                                 case MM_PLAYER_STATE_READY:
854                                 default:
855                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
856                                         break;
857                                 }
858                         }
859                         break;
860
861                 case MM_PLAYER_STATE_NULL:
862                 case MM_PLAYER_STATE_READY:
863                 case MM_PLAYER_STATE_NONE:
864                 default:
865                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
866                         break;
867                 }
868         } else {
869                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
870                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
871                  */
872                 switch (pending_state) {
873                 case MM_PLAYER_STATE_NONE:
874                         {
875                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
876                                         /* rtsp streaming pause makes rtsp server stop sending data. */
877                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
878                                                 LOGD("set pause state during buffering\n");
879                                                 __gst_pause(player, TRUE);
880                                         }
881                                 }
882                         }
883                         break;
884
885                 case MM_PLAYER_STATE_PLAYING:
886                         /* rtsp streaming pause makes rtsp server stop sending data. */
887                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
888                                 __gst_pause(player, TRUE);
889                         break;
890
891                 case MM_PLAYER_STATE_PAUSED:
892                         break;
893
894                 case MM_PLAYER_STATE_NULL:
895                 case MM_PLAYER_STATE_READY:
896                 default:
897                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
898                         break;
899                 }
900         }
901
902 exit:
903         return ret;
904 }
905
906 static void
907 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
908 {
909         MMPlayerGstElement *textbin;
910         MMPLAYER_FENTER();
911
912         MMPLAYER_RETURN_IF_FAIL(player &&
913                                         player->pipeline &&
914                                         player->pipeline->textbin);
915
916         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
917
918         textbin = player->pipeline->textbin;
919
920         if (is_drop) {
921                 LOGD("Drop subtitle text after getting EOS\n");
922
923                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
924                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
925
926                 player->is_subtitle_force_drop = TRUE;
927         } else {
928                 if (player->is_subtitle_force_drop == TRUE) {
929                         LOGD("Enable subtitle data path without drop\n");
930
931                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
932                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
933
934                         LOGD("non-connected with external display");
935
936                         player->is_subtitle_force_drop = FALSE;
937                 }
938         }
939 }
940
941 static VariantData *
942 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
943 {
944         VariantData *var_info = NULL;
945         g_return_val_if_fail(self != NULL, NULL);
946
947         var_info = g_new0(VariantData, 1);
948         if (!var_info) return NULL;
949         var_info->bandwidth = self->bandwidth;
950         var_info->width = self->width;
951         var_info->height = self->height;
952         return var_info;
953 }
954
955 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
956 {
957         mm_player_t* player = (mm_player_t*)hplayer;
958
959         MMPLAYER_FENTER();
960         MMPLAYER_RETURN_IF_FAIL(player);
961
962         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
963
964         /* destroy the gst bus msg thread */
965         if (player->bus_msg_thread) {
966                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
967                 player->bus_msg_thread_exit = TRUE;
968                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
969                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
970
971                 LOGD("gst bus msg thread exit.");
972                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
973                 player->bus_msg_thread = NULL;
974
975                 g_mutex_clear(&player->bus_msg_thread_mutex);
976                 g_cond_clear(&player->bus_msg_thread_cond);
977         }
978
979         MMPLAYER_FLEAVE();
980 }
981
982 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
983 {
984         mm_player_t *player = (mm_player_t*)(data);
985         GstMessage *msg = NULL;
986         GstBus *bus = NULL;
987
988         MMPLAYER_FENTER();
989         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
990                                                 player->pipeline &&
991                                                 player->pipeline->mainbin &&
992                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
993                                                 NULL);
994
995         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
996         if (!bus) {
997                 LOGE("cannot get BUS from the pipeline");
998                 return NULL;
999         }
1000
1001         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1002
1003         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1004         while (!player->bus_msg_thread_exit) {
1005                 msg = gst_bus_pop(bus);
1006                 if (msg == NULL) {
1007                         int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1008                         MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1009                         continue;
1010                 }
1011
1012                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1013                 /* handle the gst msg */
1014                 __mmplayer_gst_callback(msg, player);
1015                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016                 gst_message_unref(msg);
1017         }
1018
1019         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1020         gst_object_unref(GST_OBJECT(bus));
1021
1022         MMPLAYER_FLEAVE();
1023         return NULL;
1024 }
1025
1026 static void
1027 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1028 {
1029         mm_player_t* player = (mm_player_t*)(data);
1030         static gboolean async_done = FALSE;
1031
1032         MMPLAYER_RETURN_IF_FAIL(player);
1033         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1034
1035         switch (GST_MESSAGE_TYPE(msg)) {
1036         case GST_MESSAGE_UNKNOWN:
1037                 LOGD("unknown message received\n");
1038                 break;
1039
1040         case GST_MESSAGE_EOS:
1041                 {
1042                         MMHandleType attrs = 0;
1043                         gint count = 0;
1044
1045                         LOGD("GST_MESSAGE_EOS received\n");
1046
1047                         /* NOTE : EOS event is comming multiple time. watch out it */
1048                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1049                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1050                                 LOGD("EOS received on non-playing state. ignoring it\n");
1051                                 break;
1052                         }
1053
1054                         if (player->pipeline) {
1055                                 if (player->pipeline->textbin)
1056                                         __mmplayer_drop_subtitle(player, TRUE);
1057
1058                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1059                                         GstPad *pad = NULL;
1060
1061                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1062
1063                                         LOGD("release audio callback\n");
1064
1065                                         /* release audio callback */
1066                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1067                                         player->audio_cb_probe_id = 0;
1068                                         /* audio callback should be free because it can be called even though probe remove.*/
1069                                         player->audio_stream_cb = NULL;
1070                                         player->audio_stream_cb_user_param = NULL;
1071
1072                                 }
1073                         }
1074                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1075                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1076
1077                         /* rewind if repeat count is greater then zero */
1078                         /* get play count */
1079                         attrs = MMPLAYER_GET_ATTRS(player);
1080
1081                         if (attrs) {
1082                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1083
1084                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1085
1086                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1087                                         if (player->playback_rate < 0.0) {
1088                                                 player->resumed_by_rewind = TRUE;
1089                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1090                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1091                                         }
1092
1093                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1094
1095                                         /* initialize */
1096                                         player->sent_bos = FALSE;
1097
1098                                         /* not posting eos when repeating */
1099                                         break;
1100                                 }
1101                         }
1102
1103                         if (player->pipeline)
1104                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1105
1106                         /* post eos message to application */
1107                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1108
1109                         /* reset last position */
1110                         player->last_position = 0;
1111                 }
1112                 break;
1113
1114         case GST_MESSAGE_ERROR:
1115                 {
1116                         GError *error = NULL;
1117                         gchar* debug = NULL;
1118
1119                         /* generating debug info before returning error */
1120                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1121
1122                         /* get error code */
1123                         gst_message_parse_error(msg, &error, &debug);
1124
1125                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1126                                 /* Note : the streaming error from the streaming source is handled
1127                                  *   using __mmplayer_handle_streaming_error.
1128                                  */
1129                                 __mmplayer_handle_streaming_error(player, msg);
1130
1131                                 /* dump state of all element */
1132                                 __mmplayer_dump_pipeline_state(player);
1133                         } else {
1134                                 /* traslate gst error code to msl error code. then post it
1135                                  * to application if needed
1136                                  */
1137                                 __mmplayer_handle_gst_error(player, msg, error);
1138
1139                                 if (debug)
1140                                         LOGE("error debug : %s", debug);
1141                         }
1142
1143                         if (MMPLAYER_IS_HTTP_PD(player))
1144                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1145
1146                         MMPLAYER_FREEIF(debug);
1147                         g_error_free(error);
1148                 }
1149                 break;
1150
1151         case GST_MESSAGE_WARNING:
1152                 {
1153                         char* debug = NULL;
1154                         GError* error = NULL;
1155
1156                         gst_message_parse_warning(msg, &error, &debug);
1157
1158                         LOGD("warning : %s\n", error->message);
1159                         LOGD("debug : %s\n", debug);
1160
1161                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1162
1163                         MMPLAYER_FREEIF(debug);
1164                         g_error_free(error);
1165                 }
1166                 break;
1167
1168         case GST_MESSAGE_TAG:
1169                 {
1170                         LOGD("GST_MESSAGE_TAG\n");
1171                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1172                                 LOGW("failed to extract tags from gstmessage\n");
1173                 }
1174                 break;
1175
1176         case GST_MESSAGE_BUFFERING:
1177                 {
1178                         MMMessageParamType msg_param = {0, };
1179                         int bRet = MM_ERROR_NONE;
1180
1181                         if (!(player->pipeline && player->pipeline->mainbin)) {
1182                                 LOGE("player pipeline handle is null");
1183                                 break;
1184                         }
1185
1186                         if (!MMPLAYER_IS_STREAMING(player))
1187                                 break;
1188
1189                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1190                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1191                                         /* skip the playback control by buffering msg while user request is handled. */
1192                                         gint per = 0;
1193
1194                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1195
1196                                         gst_message_parse_buffering(msg, &per);
1197                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1198
1199                                         msg_param.connection.buffering = per;
1200                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1201                                         break;
1202                                 }
1203                         } else {
1204                                 MMPLAYER_CMD_LOCK(player);
1205                         }
1206
1207                         /* ignore the prev buffering message */
1208                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1209                                 && (player->streamer->is_buffering_done == TRUE)) {
1210                                 gint buffer_percent = 0;
1211
1212                                 gst_message_parse_buffering(msg, &buffer_percent);
1213
1214                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1215                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1216                                         player->streamer->is_buffering_done = FALSE;
1217                                 }
1218                                 MMPLAYER_CMD_UNLOCK(player);
1219                                 break;
1220                         }
1221
1222                         __mmplayer_update_buffer_setting(player, msg);
1223
1224                         bRet = __mmplayer_handle_buffering_message(player);
1225
1226                         if (bRet == MM_ERROR_NONE) {
1227                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1228                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1229
1230                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1231                                         player->pending_resume &&
1232                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1233
1234                                         player->is_external_subtitle_added_now = FALSE;
1235                                         player->pending_resume = FALSE;
1236                                         _mmplayer_resume((MMHandleType)player);
1237                                 }
1238
1239                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1240                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1241
1242                                         if (player->doing_seek) {
1243                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1244                                                         player->doing_seek = FALSE;
1245                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1246                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1247                                                         async_done = TRUE;
1248                                                 }
1249                                         }
1250                                 }
1251                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1252                                 if (!player->streamer) {
1253                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1254                                         MMPLAYER_CMD_UNLOCK(player);
1255                                         break;
1256                                 }
1257
1258                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1259
1260                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1261                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1262
1263                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1264                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1265                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1266                                         } else {
1267                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1268                                         }
1269                                 } else {
1270                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1271                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1272                                 }
1273                         }
1274                         MMPLAYER_CMD_UNLOCK(player);
1275                 }
1276                 break;
1277
1278         case GST_MESSAGE_STATE_CHANGED:
1279                 {
1280                         MMPlayerGstElement *mainbin;
1281                         const GValue *voldstate, *vnewstate, *vpending;
1282                         GstState oldstate = GST_STATE_NULL;
1283                         GstState newstate = GST_STATE_NULL;
1284                         GstState pending = GST_STATE_NULL;
1285
1286                         if (!(player->pipeline && player->pipeline->mainbin)) {
1287                                 LOGE("player pipeline handle is null");
1288                                 break;
1289                         }
1290
1291                         mainbin = player->pipeline->mainbin;
1292
1293                         /* we only handle messages from pipeline */
1294                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1295                                 break;
1296
1297                         /* get state info from msg */
1298                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1299                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1300                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1301
1302                         if (!voldstate || !vnewstate) {
1303                                 LOGE("received msg has wrong format.");
1304                                 break;
1305                         }
1306
1307                         oldstate = (GstState)voldstate->data[0].v_int;
1308                         newstate = (GstState)vnewstate->data[0].v_int;
1309                         if (vpending)
1310                                 pending = (GstState)vpending->data[0].v_int;
1311
1312                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1313                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1314                                 gst_element_state_get_name((GstState)oldstate),
1315                                 gst_element_state_get_name((GstState)newstate),
1316                                 gst_element_state_get_name((GstState)pending));
1317
1318                         if (newstate == GST_STATE_PLAYING) {
1319                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1320
1321                                         int retVal = MM_ERROR_NONE;
1322                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1323
1324                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1325
1326                                         if (MM_ERROR_NONE != retVal)
1327                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1328
1329                                         player->pending_seek.is_pending = FALSE;
1330                                 }
1331                         }
1332
1333                         if (oldstate == newstate) {
1334                                 LOGD("pipeline reports state transition to old state");
1335                                 break;
1336                         }
1337
1338                         switch (newstate) {
1339                         case GST_STATE_VOID_PENDING:
1340                                 break;
1341
1342                         case GST_STATE_NULL:
1343                                 break;
1344
1345                         case GST_STATE_READY:
1346                                 break;
1347
1348                         case GST_STATE_PAUSED:
1349                                 {
1350                                         gboolean prepare_async = FALSE;
1351                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1352
1353                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1354                                                 __mmplayer_configure_audio_callback(player);
1355
1356                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1357                                                 // managed prepare async case
1358                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1359                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1360                                         }
1361
1362                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1363                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1364
1365                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1366                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1367                                                                 player->total_maximum_bitrate, player->total_bitrate);
1368
1369                                                 if (player->pending_seek.is_pending) {
1370                                                         LOGW("trying to do pending seek");
1371                                                         MMPLAYER_CMD_LOCK(player);
1372                                                         __gst_pending_seek(player);
1373                                                         MMPLAYER_CMD_UNLOCK(player);
1374                                                 }
1375                                         }
1376                                 }
1377                                 break;
1378
1379                         case GST_STATE_PLAYING:
1380                                 {
1381                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1382
1383                                         if (MMPLAYER_IS_STREAMING(player)) {
1384                                                 // managed prepare async case when buffering is completed
1385                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1386                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1387                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1388                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1389
1390                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1391
1392                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1393                                                         if (player->streamer->buffering_percent < 100) {
1394
1395                                                                 MMMessageParamType msg_param = {0, };
1396                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1397
1398                                                                 msg_param.connection.buffering = 100;
1399                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1400                                                         }
1401                                                 }
1402                                         }
1403
1404                                         if (player->gapless.stream_changed) {
1405                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1406                                                 player->gapless.stream_changed = FALSE;
1407                                         }
1408
1409                                         if (player->doing_seek && async_done) {
1410                                                 player->doing_seek = FALSE;
1411                                                 async_done = FALSE;
1412                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1413                                         }
1414                                 }
1415                                 break;
1416
1417                         default:
1418                                 break;
1419                         }
1420                 }
1421                 break;
1422
1423         case GST_MESSAGE_CLOCK_LOST:
1424                         {
1425                                 GstClock *clock = NULL;
1426                                 gboolean need_new_clock = FALSE;
1427
1428                                 gst_message_parse_clock_lost(msg, &clock);
1429                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1430
1431                                 if (!player->videodec_linked)
1432                                         need_new_clock = TRUE;
1433                                 else if (!player->ini.use_system_clock)
1434                                         need_new_clock = TRUE;
1435
1436                                 if (need_new_clock) {
1437                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1438                                         __gst_pause(player, FALSE);
1439                                         __gst_resume(player, FALSE);
1440                                 }
1441                         }
1442                         break;
1443
1444         case GST_MESSAGE_NEW_CLOCK:
1445                         {
1446                                 GstClock *clock = NULL;
1447                                 gst_message_parse_new_clock(msg, &clock);
1448                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1449                         }
1450                         break;
1451
1452         case GST_MESSAGE_ELEMENT:
1453                         {
1454                                 const gchar *structure_name;
1455                                 gint count = 0, idx = 0;
1456                                 MMHandleType attrs = 0;
1457
1458                                 attrs = MMPLAYER_GET_ATTRS(player);
1459                                 if (!attrs) {
1460                                         LOGE("cannot get content attribute");
1461                                         break;
1462                                 }
1463
1464                                 if (gst_message_get_structure(msg) == NULL)
1465                                         break;
1466
1467                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1468                                 if (!structure_name)
1469                                         break;
1470
1471                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1472
1473                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1474                                         const GValue *var_info = NULL;
1475
1476                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1477                                         if (var_info != NULL) {
1478                                                 if (player->adaptive_info.var_list)
1479                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1480
1481                                                 /* share addr or copy the list */
1482                                                 player->adaptive_info.var_list =
1483                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1484
1485                                                 count = g_list_length(player->adaptive_info.var_list);
1486                                                 if (count > 0) {
1487                                                         VariantData *temp = NULL;
1488
1489                                                         /* print out for debug */
1490                                                         LOGD("num of variant_info %d", count);
1491                                                         for (idx = 0; idx < count; idx++) {
1492                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1493                                                                 if (temp)
1494                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1495                                                         }
1496                                                 }
1497                                         }
1498                                 }
1499
1500                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1501                                         gint num_buffers = 0;
1502                                         gint extra_num_buffers = 0;
1503
1504                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1505                                                 player->video_num_buffers = num_buffers;
1506                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1507                                         }
1508
1509                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1510                                                 player->video_extra_num_buffers = extra_num_buffers;
1511                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1512                                         }
1513                                         break;
1514                                 }
1515
1516                                 if (!strcmp(structure_name, "Language_list")) {
1517                                         const GValue *lang_list = NULL;
1518                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1519                                         if (lang_list != NULL) {
1520                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1521                                                 if (count > 1)
1522                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1523                                         }
1524                                 }
1525
1526                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1527                                         const GValue *lang_list = NULL;
1528                                         MMPlayerLangStruct *temp = NULL;
1529
1530                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1531                                         if (lang_list != NULL) {
1532                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1533                                                 if (count) {
1534                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1535                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1536                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1537                                                         if (mmf_attrs_commit(attrs))
1538                                                                 LOGE("failed to commit.\n");
1539                                                         LOGD("Total subtitle tracks = %d \n", count);
1540
1541                                                         while (count) {
1542                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1543                                                                 if (temp)
1544                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1545                                                                                                 temp->language_key, temp->language_code);
1546                                                                 count--;
1547                                                         }
1548                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1549                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1550                                                 }
1551                                         }
1552                                 }
1553
1554                                 /* custom message */
1555                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1556                                         MMMessageParamType msg_param = {0,};
1557                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1558                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1559                                 }
1560
1561                                 /* custom message for RTSP attribute :
1562                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1563                                     sdp which has contents info is received when rtsp connection is opened.
1564                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1565                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1566
1567                                         gchar *audio_codec = NULL;
1568                                         gchar *video_codec = NULL;
1569                                         gchar *video_frame_size = NULL;
1570
1571                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1572                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1573                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1574                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1575
1576                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1577                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1578                                         if (audio_codec)
1579                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1580
1581                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1582                                         LOGD("rtsp_video_codec : %s", video_codec);
1583                                         if (video_codec)
1584                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1585
1586                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1587                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1588                                         if (video_frame_size) {
1589
1590                                                 char *seperator = strchr(video_frame_size, '-');
1591                                                 if (seperator) {
1592
1593                                                         char video_width[10] = {0,};
1594                                                         int frame_size_len = strlen(video_frame_size);
1595                                                         int separtor_len = strlen(seperator);
1596
1597                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1598                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1599
1600                                                         seperator++;
1601                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1602                                                 }
1603                                         }
1604
1605                                         if (mmf_attrs_commit(attrs))
1606                                                 LOGE("failed to commit.\n");
1607                                 }
1608                         }
1609                         break;
1610
1611         case GST_MESSAGE_DURATION_CHANGED:
1612                 {
1613                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1614                         if (!__mmplayer_gst_handle_duration(player, msg))
1615                                 LOGW("failed to update duration");
1616                 }
1617
1618                 break;
1619
1620         case GST_MESSAGE_ASYNC_START:
1621                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1622                 break;
1623
1624         case GST_MESSAGE_ASYNC_DONE:
1625                 {
1626                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1627
1628                         /* we only handle messages from pipeline */
1629                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1630                                 break;
1631
1632                         if (player->doing_seek) {
1633                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1634                                         player->doing_seek = FALSE;
1635                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1636                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1637                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1638                                                 (player->streamer) &&
1639                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1640                                                 (player->streamer->is_buffering == FALSE)) {
1641                                                 GstQuery *query = NULL;
1642                                                 gboolean busy = FALSE;
1643                                                 gint percent = 0;
1644
1645                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1646                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1647                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1648                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1649                                                         gst_query_unref(query);
1650
1651                                                         LOGD("buffered percent(%s): %d\n",
1652                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1653                                                 }
1654
1655                                                 if (percent >= 100) {
1656                                                         player->streamer->is_buffering = FALSE;
1657                                                         __mmplayer_handle_buffering_message(player);
1658                                                 }
1659                                         }
1660
1661                                         async_done = TRUE;
1662                                 }
1663                         }
1664                 }
1665                 break;
1666
1667         #if 0 /* delete unnecessary logs */
1668         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1669         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1670         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1671         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1672         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1673         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1674         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1675         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1676         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1677         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1678         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1679         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1680         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1681         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1682         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1683         #endif
1684
1685         default:
1686                 break;
1687         }
1688
1689         /* should not call 'gst_message_unref(msg)' */
1690         return;
1691 }
1692
1693 static gboolean
1694 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1695 {
1696         gint64 bytes = 0;
1697
1698         MMPLAYER_FENTER();
1699
1700         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1701         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1702
1703         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1704                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1705                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1706
1707                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1708                         LOGD("data total size of http content: %lld", bytes);
1709                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1710                 }
1711         } else
1712                 /* handling audio clip which has vbr. means duration is keep changing */
1713                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1714
1715         MMPLAYER_FLEAVE();
1716
1717         return TRUE;
1718 }
1719
1720 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1721                 mm_player_spherical_metadata_t *metadata) {
1722         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1723         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1724         gst_tag_list_get_string(tags, "stitching_software",
1725                         &metadata->stitching_software);
1726         gst_tag_list_get_string(tags, "projection_type",
1727                         &metadata->projection_type_string);
1728         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1729         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1730         gst_tag_list_get_int(tags, "init_view_heading",
1731                         &metadata->init_view_heading);
1732         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1733         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1734         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1735         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1736                         &metadata->full_pano_width_pixels);
1737         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1738                         &metadata->full_pano_height_pixels);
1739         gst_tag_list_get_int(tags, "cropped_area_image_width",
1740                         &metadata->cropped_area_image_width);
1741         gst_tag_list_get_int(tags, "cropped_area_image_height",
1742                         &metadata->cropped_area_image_height);
1743         gst_tag_list_get_int(tags, "cropped_area_left",
1744                         &metadata->cropped_area_left);
1745         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1746         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1747         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1748         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1749 }
1750
1751 static gboolean
1752 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1753 {
1754
1755 /* macro for better code readability */
1756 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1757 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1758         if (string != NULL) { \
1759                 SECURE_LOGD("update tag string : %s\n", string); \
1760                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1761                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1762                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1763                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1764                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1765                         g_free(new_string); \
1766                         new_string = NULL; \
1767                 } else { \
1768                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1769                 } \
1770                 g_free(string); \
1771                 string = NULL; \
1772         } \
1773 }
1774
1775 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1776 do {    \
1777         GstSample *sample = NULL;\
1778         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1779                 GstMapInfo info = GST_MAP_INFO_INIT;\
1780                 buffer = gst_sample_get_buffer(sample);\
1781                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1782                         LOGD("failed to get image data from tag");\
1783                         gst_sample_unref(sample);\
1784                         return FALSE;\
1785                 } \
1786                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1787                 MMPLAYER_FREEIF(player->album_art);\
1788                 player->album_art = (gchar *)g_malloc(info.size);\
1789                 if (player->album_art) {\
1790                         memcpy(player->album_art, info.data, info.size);\
1791                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1792                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1793                                 msg_param.data = (void *)player->album_art;\
1794                                 msg_param.size = info.size;\
1795                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1796                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1797                         } \
1798                 } \
1799                 gst_buffer_unmap(buffer, &info);\
1800                 gst_sample_unref(sample);\
1801         }       \
1802 } while (0)
1803
1804 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1805 do {    \
1806         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1807                 if (v_uint) { \
1808                         int i = 0; \
1809                         gchar *tag_list_str = NULL; \
1810                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1811                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1812                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1813                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1814                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1815                         else \
1816                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1817                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1818                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1819                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1820                                 player->bitrate[track_type] = v_uint; \
1821                                 player->total_bitrate = 0; \
1822                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1823                                         player->total_bitrate += player->bitrate[i]; \
1824                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1825                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1826                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1827                                 player->maximum_bitrate[track_type] = v_uint; \
1828                                 player->total_maximum_bitrate = 0; \
1829                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1830                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1831                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1832                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1833                         } else { \
1834                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1835                         } \
1836                         v_uint = 0;\
1837                         g_free(tag_list_str); \
1838                 } \
1839         } \
1840 } while (0)
1841
1842 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1843 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1844         if (date != NULL) {\
1845                 string = g_strdup_printf("%d", g_date_get_year(date));\
1846                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1847                 SECURE_LOGD("metainfo year : %s\n", string);\
1848                 MMPLAYER_FREEIF(string);\
1849                 g_date_free(date);\
1850         } \
1851 }
1852
1853 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1854 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1855         if (datetime != NULL) {\
1856                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1857                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1858                 SECURE_LOGD("metainfo year : %s\n", string);\
1859                 MMPLAYER_FREEIF(string);\
1860                 gst_date_time_unref(datetime);\
1861         } \
1862 }
1863
1864 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1865 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1866         if (v_uint64) {\
1867                 /* FIXIT : don't know how to store date */\
1868                 g_assert(1);\
1869                 v_uint64 = 0;\
1870         } \
1871 }
1872
1873 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1874 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1875         if (v_double) {\
1876                 /* FIXIT : don't know how to store date */\
1877                 g_assert(1);\
1878                 v_double = 0;\
1879         } \
1880 }
1881
1882         /* function start */
1883         GstTagList* tag_list = NULL;
1884
1885         MMHandleType attrs = 0;
1886
1887         char *string = NULL;
1888         guint v_uint = 0;
1889         GDate *date = NULL;
1890         GstDateTime *datetime = NULL;
1891         /* album cover */
1892         GstBuffer *buffer = NULL;
1893         gint index = 0;
1894         MMMessageParamType msg_param = {0, };
1895
1896         /* currently not used. but those are needed for above macro */
1897         //guint64 v_uint64 = 0;
1898         //gdouble v_double = 0;
1899
1900         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1901
1902         attrs = MMPLAYER_GET_ATTRS(player);
1903
1904         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1905
1906         /* get tag list from gst message */
1907         gst_message_parse_tag(msg, &tag_list);
1908
1909         /* store tags to player attributes */
1910         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1911         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1912         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1913         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1914         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1915         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1916         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1917         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1918         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1919         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1920         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1922         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1923         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1924         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1925         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1926         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1927         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1928         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1929         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1930         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1931         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1932         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1933         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1934         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1937         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1938         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1939         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1940         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1941         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1942         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1943         MMPLAYER_UPDATE_TAG_LOCK(player);
1944         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1945         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1946         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1947         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1948         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1949         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1950         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1951         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1952         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1953         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1954         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1955         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1956         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1957         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1958         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1959
1960         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1961                 if (player->video360_metadata.is_spherical == -1) {
1962                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1963                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1964                                         player->video360_metadata.is_spherical);
1965                         if (player->video360_metadata.is_spherical == 1) {
1966                                 LOGD("This is spherical content for 360 playback.");
1967                                 player->is_content_spherical = TRUE;
1968                         } else {
1969                                 LOGD("This is not spherical content");
1970                                 player->is_content_spherical = FALSE;
1971                         }
1972
1973                         if (player->video360_metadata.projection_type_string) {
1974                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1975                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1976                                 } else {
1977                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1978                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1979                                 }
1980                         }
1981
1982                         if (player->video360_metadata.stereo_mode_string) {
1983                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1984                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1985                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1986                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1987                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1988                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1989                                 } else {
1990                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1991                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
1992                                 }
1993                         }
1994                 }
1995         }
1996
1997         if (mmf_attrs_commit(attrs))
1998                 LOGE("failed to commit.\n");
1999
2000         gst_tag_list_free(tag_list);
2001
2002         return TRUE;
2003 }
2004
2005 static void
2006 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2007 {
2008         mm_player_t* player = (mm_player_t*) data;
2009
2010         MMPLAYER_FENTER();
2011
2012         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2013           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2014           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2015           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2016
2017           * [1] audio and video will be dumped with filesink.
2018           * [2] autoplugging is done by just using pad caps.
2019           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2020           * and the video will be dumped via filesink.
2021           */
2022         if (player->num_dynamic_pad == 0) {
2023                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2024
2025                 if (!__mmplayer_gst_remove_fakesink(player,
2026                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2027                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2028                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2029                          * source element are not same. To overcome this situation, this function will called
2030                          * several places and several times. Therefore, this is not an error case.
2031                          */
2032                         return;
2033         }
2034
2035         /* create dot before error-return. for debugging */
2036         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2037
2038         player->no_more_pad = TRUE;
2039
2040         MMPLAYER_FLEAVE();
2041 }
2042
2043 static gboolean
2044 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2045 {
2046         GstElement* parent = NULL;
2047
2048         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2049
2050         /* if we have no fakesink. this meas we are using decodebin which doesn'
2051         t need to add extra fakesink */
2052         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2053
2054         /* lock */
2055         MMPLAYER_FSINK_LOCK(player);
2056
2057         if (!fakesink->gst)
2058                 goto ERROR;
2059
2060         /* get parent of fakesink */
2061         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2062         if (!parent) {
2063                 LOGD("fakesink already removed\n");
2064                 goto ERROR;
2065         }
2066
2067         gst_element_set_locked_state(fakesink->gst, TRUE);
2068
2069         /* setting the state to NULL never returns async
2070          * so no need to wait for completion of state transiton
2071          */
2072         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2073                 LOGE("fakesink state change failure!\n");
2074                 /* FIXIT : should I return here? or try to proceed to next? */
2075                 /* return FALSE; */
2076
2077         /* remove fakesink from it's parent */
2078         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2079                 LOGE("failed to remove fakesink\n");
2080
2081                 gst_object_unref(parent);
2082
2083                 goto ERROR;
2084         }
2085
2086         gst_object_unref(parent);
2087
2088         LOGD("state-holder removed\n");
2089
2090         gst_element_set_locked_state(fakesink->gst, FALSE);
2091
2092         MMPLAYER_FSINK_UNLOCK(player);
2093         return TRUE;
2094
2095 ERROR:
2096         if (fakesink->gst)
2097                 gst_element_set_locked_state(fakesink->gst, FALSE);
2098
2099         MMPLAYER_FSINK_UNLOCK(player);
2100         return FALSE;
2101 }
2102
2103
2104 static void
2105 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2106 {
2107         GstPad *sinkpad = NULL;
2108         GstCaps* caps = NULL;
2109         GstElement* new_element = NULL;
2110         GstStructure* str = NULL;
2111         const gchar* name = NULL;
2112
2113         mm_player_t* player = (mm_player_t*) data;
2114
2115         MMPLAYER_FENTER();
2116
2117         MMPLAYER_RETURN_IF_FAIL(element && pad);
2118         MMPLAYER_RETURN_IF_FAIL(player &&
2119                                         player->pipeline &&
2120                                         player->pipeline->mainbin);
2121
2122
2123         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2124          * num_dynamic_pad will decreased after creating a sinkbin.
2125          */
2126         player->num_dynamic_pad++;
2127         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2128
2129         caps = gst_pad_query_caps(pad, NULL);
2130
2131         MMPLAYER_CHECK_NULL(caps);
2132
2133         /* clear  previous result*/
2134         player->have_dynamic_pad = FALSE;
2135
2136         str = gst_caps_get_structure(caps, 0);
2137
2138         if (!str) {
2139                 LOGE("cannot get structure from caps.\n");
2140                 goto ERROR;
2141         }
2142
2143         name = gst_structure_get_name(str);
2144         if (!name) {
2145                 LOGE("cannot get mimetype from structure.\n");
2146                 goto ERROR;
2147         }
2148
2149         if (strstr(name, "video")) {
2150                 gint stype = 0;
2151                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2152
2153                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2154                         if (player->v_stream_caps) {
2155                                 gst_caps_unref(player->v_stream_caps);
2156                                 player->v_stream_caps = NULL;
2157                         }
2158
2159                         new_element = gst_element_factory_make("fakesink", NULL);
2160                         player->num_dynamic_pad--;
2161                         goto NEW_ELEMENT;
2162                 }
2163         }
2164
2165         /* clear  previous result*/
2166         player->have_dynamic_pad = FALSE;
2167
2168         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2169                 LOGE("failed to autoplug for caps");
2170                 goto ERROR;
2171         }
2172
2173         /* check if there's dynamic pad*/
2174         if (player->have_dynamic_pad) {
2175                 LOGE("using pad caps assums there's no dynamic pad !\n");
2176                 goto ERROR;
2177         }
2178
2179         gst_caps_unref(caps);
2180         caps = NULL;
2181
2182 NEW_ELEMENT:
2183
2184         /* excute new_element if created*/
2185         if (new_element) {
2186                 LOGD("adding new element to pipeline\n");
2187
2188                 /* set state to READY before add to bin */
2189                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2190
2191                 /* add new element to the pipeline */
2192                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2193                         LOGE("failed to add autoplug element to bin\n");
2194                         goto ERROR;
2195                 }
2196
2197                 /* get pad from element */
2198                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2199                 if (!sinkpad) {
2200                         LOGE("failed to get sinkpad from autoplug element\n");
2201                         goto ERROR;
2202                 }
2203
2204                 /* link it */
2205                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2206                         LOGE("failed to link autoplug element\n");
2207                         goto ERROR;
2208                 }
2209
2210                 gst_object_unref(sinkpad);
2211                 sinkpad = NULL;
2212
2213                 /* run. setting PLAYING here since streamming source is live source */
2214                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2215         }
2216
2217         if (caps)
2218                 gst_caps_unref(caps);
2219
2220         MMPLAYER_FLEAVE();
2221
2222         return;
2223
2224 STATE_CHANGE_FAILED:
2225 ERROR:
2226         /* FIXIT : take care if new_element has already added to pipeline */
2227         if (new_element)
2228                 gst_object_unref(GST_OBJECT(new_element));
2229
2230         if (sinkpad)
2231                 gst_object_unref(GST_OBJECT(sinkpad));
2232
2233         if (caps)
2234                 gst_caps_unref(caps);
2235
2236         /* FIXIT : how to inform this error to MSL ????? */
2237         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2238          * then post an error to application
2239          */
2240 }
2241
2242 static GstPadProbeReturn
2243 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2244 {
2245         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2246         return GST_PAD_PROBE_OK;
2247 }
2248
2249 static GstPadProbeReturn
2250 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2251 {
2252         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2253         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2254         mm_player_t* player = (mm_player_t*)data;
2255         GstCaps* caps = NULL;
2256         GstStructure* str = NULL;
2257         const gchar* name = NULL;
2258         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2259
2260
2261         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2262                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2263                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2264                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2265                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2266                         return ret;
2267         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2268                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2269                         return ret;
2270         }
2271
2272         caps = gst_pad_query_caps(pad, NULL);
2273         if (!caps) {
2274                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2275                 return ret;
2276         }
2277
2278         str = gst_caps_get_structure(caps, 0);
2279         if (!str) {
2280                 LOGE("failed to get structure from caps");
2281                 goto ERROR;
2282         }
2283
2284         name = gst_structure_get_name(str);
2285         if (!name) {
2286                 LOGE("failed to get name from str");
2287                 goto ERROR;
2288         }
2289
2290         if (strstr(name, "audio")) {
2291                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2292         } else if (strstr(name, "video")) {
2293                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2294         } else {
2295                 /* text track is not supportable */
2296                 LOGE("invalid name %s", name);
2297                 goto ERROR;
2298         }
2299
2300         switch (GST_EVENT_TYPE(event)) {
2301         case GST_EVENT_EOS:
2302                 {
2303                         /* in case of gapless, drop eos event not to send it to sink */
2304                         if (player->gapless.reconfigure && !player->msg_posted) {
2305                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2306                                 ret = GST_PAD_PROBE_DROP;
2307                         }
2308                         break;
2309                 }
2310         case GST_EVENT_STREAM_START:
2311                 {
2312                         gint64 stop_running_time = 0;
2313                         gint64 position_running_time = 0;
2314                         gint64 position = 0;
2315                         gint idx = 0;
2316
2317                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2318                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2319                                         !(player->selector[idx].event_probe_id)) {
2320                                         /* LOGW("[%d] skip", idx); */
2321                                         continue;
2322                                 }
2323
2324                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2325                                         stop_running_time =
2326                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2327                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2328                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2329                                         stop_running_time =
2330                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2331                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2332                                 } else {
2333                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2334                                         stop_running_time =
2335                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2336                                                                 GST_FORMAT_TIME, player->duration);
2337                                 }
2338
2339                                 position_running_time =
2340                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2341                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2342
2343                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2344                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2345                                         idx,
2346                                         GST_TIME_ARGS(stop_running_time),
2347                                         GST_TIME_ARGS(position_running_time),
2348                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2349                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2350
2351                                 position_running_time = MAX(position_running_time, stop_running_time);
2352                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2353                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2354                                 position_running_time = MAX(0, position_running_time);
2355                                 position = MAX(position, position_running_time);
2356                         }
2357
2358                         if (position != 0) {
2359                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2360                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2361                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2362
2363                                 player->gapless.start_time[stream_type] += position;
2364                         }
2365                         break;
2366                 }
2367         case GST_EVENT_FLUSH_STOP:
2368                 {
2369                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2370                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2371                         player->gapless.start_time[stream_type] = 0;
2372                         break;
2373                 }
2374         case GST_EVENT_SEGMENT:
2375                 {
2376                         GstSegment segment;
2377                         GstEvent *tmpev;
2378
2379                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2380                         gst_event_copy_segment(event, &segment);
2381
2382                         if (segment.format == GST_FORMAT_TIME) {
2383                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2384                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2385                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2386                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2387                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2388                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2389
2390                                 /* keep the all the segment ev to cover the seeking */
2391                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2392                                 player->gapless.update_segment[stream_type] = TRUE;
2393
2394                                 if (!player->gapless.running)
2395                                         break;
2396
2397                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2398
2399                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2400
2401                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2402                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2403                                 gst_event_unref(event);
2404                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2405                         }
2406                         break;
2407                 }
2408         case GST_EVENT_QOS:
2409                 {
2410                         gdouble proportion = 0.0;
2411                         GstClockTimeDiff diff = 0;
2412                         GstClockTime timestamp = 0;
2413                         gint64 running_time_diff = -1;
2414                         GstQOSType type = 0;
2415                         GstEvent *tmpev = NULL;
2416
2417                         running_time_diff = player->gapless.segment[stream_type].base;
2418
2419                         if (running_time_diff <= 0) /* don't need to adjust */
2420                                 break;
2421
2422                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2423                         gst_event_unref(event);
2424
2425                         if (timestamp < running_time_diff) {
2426                                 LOGW("QOS event from previous group");
2427                                 ret = GST_PAD_PROBE_DROP;
2428                                 break;
2429                         }
2430
2431                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2432                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2433                                                 stream_type, GST_TIME_ARGS(timestamp),
2434                                                 GST_TIME_ARGS(running_time_diff),
2435                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2436
2437                         timestamp -= running_time_diff;
2438
2439                         /* That case is invalid for QoS events */
2440                         if (diff < 0 && -diff > timestamp) {
2441                                 LOGW("QOS event from previous group");
2442                                 ret = GST_PAD_PROBE_DROP;
2443                                 break;
2444                         }
2445
2446                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2447                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2448
2449                         break;
2450                 }
2451         default:
2452                 break;
2453         }
2454
2455 ERROR:
2456         if (caps)
2457                 gst_caps_unref(caps);
2458         return ret;
2459 }
2460
2461 static void
2462 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2463 {
2464         mm_player_t* player = NULL;
2465         GstElement* pipeline = NULL;
2466         GstElement* selector = NULL;
2467         GstElement* fakesink = NULL;
2468         GstCaps* caps = NULL;
2469         GstStructure* str = NULL;
2470         const gchar* name = NULL;
2471         GstPad* sinkpad = NULL;
2472         GstPad* srcpad = NULL;
2473         gboolean first_track = FALSE;
2474
2475         enum MainElementID elemId = MMPLAYER_M_NUM;
2476         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2477
2478         /* check handles */
2479         player = (mm_player_t*)data;
2480
2481         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2482         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2483
2484         //LOGD("pad-added signal handling\n");
2485
2486         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2487
2488         /* get mimetype from caps */
2489         caps = gst_pad_query_caps(pad, NULL);
2490         if (!caps) {
2491                 LOGE("cannot get caps from pad.\n");
2492                 goto ERROR;
2493         }
2494
2495         str = gst_caps_get_structure(caps, 0);
2496         if (!str) {
2497                 LOGE("cannot get structure from caps.\n");
2498                 goto ERROR;
2499         }
2500
2501         name = gst_structure_get_name(str);
2502         if (!name) {
2503                 LOGE("cannot get mimetype from structure.\n");
2504                 goto ERROR;
2505         }
2506
2507         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2508         //LOGD("detected mimetype : %s\n", name);
2509
2510         if (strstr(name, "video")) {
2511                 gint stype = 0;
2512
2513                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2514                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2515
2516                 /* don't make video because of not required, and not support multiple track */
2517                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2518                         LOGD("no video sink by null surface");
2519
2520                         gchar *caps_str = gst_caps_to_string(caps);
2521                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2522                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2523                                 player->set_mode.video_zc = TRUE;
2524
2525                         MMPLAYER_FREEIF(caps_str);
2526
2527                         if (player->v_stream_caps) {
2528                                 gst_caps_unref(player->v_stream_caps);
2529                                 player->v_stream_caps = NULL;
2530                         }
2531
2532                         LOGD("create fakesink instead of videobin");
2533
2534                         /* fake sink */
2535                         fakesink = gst_element_factory_make("fakesink", NULL);
2536                         if (fakesink == NULL) {
2537                                 LOGE("ERROR : fakesink create error\n");
2538                                 goto ERROR;
2539                         }
2540
2541                         if (player->ini.set_dump_element_flag)
2542                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2543
2544                         player->video_fakesink = fakesink;
2545
2546                         /* store it as it's sink element */
2547                         __mmplayer_add_sink(player, player->video_fakesink);
2548
2549                         gst_bin_add(GST_BIN(pipeline), fakesink);
2550
2551                         // link
2552                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2553
2554                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2555                                 LOGW("failed to link fakesink\n");
2556                                 gst_object_unref(GST_OBJECT(fakesink));
2557                                 goto ERROR;
2558                         }
2559
2560                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2561                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2562                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2563                         }
2564
2565                         if (player->set_mode.media_packet_video_stream) {
2566                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2567
2568                                 MMPLAYER_SIGNAL_CONNECT(player,
2569                                                                                 G_OBJECT(fakesink),
2570                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2571                                                                                 "handoff",
2572                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2573                                                                                 (gpointer)player);
2574
2575                                 MMPLAYER_SIGNAL_CONNECT(player,
2576                                                                                 G_OBJECT(fakesink),
2577                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2578                                                                                 "preroll-handoff",
2579                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2580                                                                                 (gpointer)player);
2581                         }
2582
2583                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2584                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2585                         goto DONE;
2586                 }
2587
2588                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2589                         __mmplayer_gst_decode_callback(elem, pad, player);
2590                         goto DONE;
2591                 }
2592
2593                 LOGD("video selector \n");
2594                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2595                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2596         } else {
2597                 if (strstr(name, "audio")) {
2598                         gint samplerate = 0;
2599                         gint channels = 0;
2600
2601                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2602                                 __mmplayer_gst_decode_callback(elem, pad, player);
2603                                 goto DONE;
2604                         }
2605
2606                         LOGD("audio selector \n");
2607                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2608                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2609
2610                         gst_structure_get_int(str, "rate", &samplerate);
2611                         gst_structure_get_int(str, "channels", &channels);
2612
2613                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2614                                 /* fake sink */
2615                                 fakesink = gst_element_factory_make("fakesink", NULL);
2616                                 if (fakesink == NULL) {
2617                                         LOGE("ERROR : fakesink create error\n");
2618                                         goto ERROR;
2619                                 }
2620
2621                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2622
2623                                 /* link */
2624                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2625
2626                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2627                                         LOGW("failed to link fakesink\n");
2628                                         gst_object_unref(GST_OBJECT(fakesink));
2629                                         goto ERROR;
2630                                 }
2631
2632                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2633                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2634                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2635
2636                                 goto DONE;
2637                         }
2638                 } else if (strstr(name, "text")) {
2639                         LOGD("text selector \n");
2640                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2641                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2642                 } else {
2643                         LOGE("wrong elem id \n");
2644                         goto ERROR;
2645                 }
2646         }
2647
2648         selector = player->pipeline->mainbin[elemId].gst;
2649         if (selector == NULL) {
2650                 selector = gst_element_factory_make("input-selector", NULL);
2651                 LOGD("Creating input-selector\n");
2652                 if (selector == NULL) {
2653                         LOGE("ERROR : input-selector create error\n");
2654                         goto ERROR;
2655                 }
2656                 g_object_set(selector, "sync-streams", TRUE, NULL);
2657
2658                 player->pipeline->mainbin[elemId].id = elemId;
2659                 player->pipeline->mainbin[elemId].gst = selector;
2660
2661                 first_track = TRUE;
2662                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2663
2664                 srcpad = gst_element_get_static_pad(selector, "src");
2665
2666                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2667                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2668                         __mmplayer_gst_selector_blocked, NULL, NULL);
2669                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2670                         __mmplayer_gst_selector_event_probe, player, NULL);
2671
2672                 gst_element_set_state(selector, GST_STATE_PAUSED);
2673                 gst_bin_add(GST_BIN(pipeline), selector);
2674         } else
2675                 LOGD("input-selector is already created.\n");
2676
2677         // link
2678         LOGD("Calling request pad with selector %p \n", selector);
2679         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2680
2681         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2682
2683         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2684                 LOGW("failed to link selector\n");
2685                 gst_object_unref(GST_OBJECT(selector));
2686                 goto ERROR;
2687         }
2688
2689         if (first_track) {
2690                 LOGD("this is first track --> active track \n");
2691                 g_object_set(selector, "active-pad", sinkpad, NULL);
2692         }
2693
2694         _mmplayer_track_update_info(player, stream_type, sinkpad);
2695
2696
2697 DONE:
2698 ERROR:
2699
2700         if (caps)
2701                 gst_caps_unref(caps);
2702
2703         if (sinkpad) {
2704                 gst_object_unref(GST_OBJECT(sinkpad));
2705                 sinkpad = NULL;
2706         }
2707
2708         if (srcpad) {
2709                 gst_object_unref(GST_OBJECT(srcpad));
2710                 srcpad = NULL;
2711         }
2712
2713         return;
2714 }
2715
2716 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2717 {
2718         GstPad* srcpad = NULL;
2719         MMHandleType attrs = 0;
2720         gint active_index = 0;
2721
2722         // [link] input-selector :: textbin
2723         srcpad = gst_element_get_static_pad(text_selector, "src");
2724         if (!srcpad) {
2725                 LOGE("failed to get srcpad from selector\n");
2726                 return;
2727         }
2728
2729         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2730
2731         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2732         if ((active_index != DEFAULT_TRACK) &&
2733                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2734                 LOGW("failed to change text track\n");
2735                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2736         }
2737
2738         player->no_more_pad = TRUE;
2739         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2740
2741         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2742         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2743                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2744                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2745         }
2746
2747         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2748
2749         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2750                 player->has_closed_caption = TRUE;
2751
2752         attrs = MMPLAYER_GET_ATTRS(player);
2753         if (attrs) {
2754                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2755                 if (mmf_attrs_commit(attrs))
2756                         LOGE("failed to commit.\n");
2757         } else
2758                 LOGE("cannot get content attribute");
2759
2760         if (srcpad) {
2761                 gst_object_unref(GST_OBJECT(srcpad));
2762                 srcpad = NULL;
2763         }
2764 }
2765
2766 static void
2767 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2768 {
2769         mm_player_t* player = (mm_player_t*)data;
2770         GstElement* selector = NULL;
2771         GstElement* queue = NULL;
2772
2773         GstPad* srcpad = NULL;
2774         GstPad* sinkpad = NULL;
2775         GstCaps* caps = NULL;
2776         gchar* caps_str = NULL;
2777
2778         MMPLAYER_FENTER();
2779         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2780
2781         caps = gst_pad_get_current_caps(pad);
2782         caps_str = gst_caps_to_string(caps);
2783         LOGD("deinterleave new caps : %s\n", caps_str);
2784         MMPLAYER_FREEIF(caps_str);
2785         gst_caps_unref(caps);
2786
2787         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2788                 LOGE("ERROR : queue create error\n");
2789                 goto ERROR;
2790         }
2791
2792         g_object_set(G_OBJECT(queue),
2793                                 "max-size-buffers", 10,
2794                                 "max-size-bytes", 0,
2795                                 "max-size-time", (guint64)0,
2796                                 NULL);
2797
2798         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2799
2800         if (!selector) {
2801                 LOGE("there is no audio channel selector.\n");
2802                 goto ERROR;
2803         }
2804
2805         srcpad = gst_element_get_static_pad(queue, "src");
2806         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2807
2808         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2809
2810         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2811                 LOGW("failed to link deinterleave - selector\n");
2812                 goto ERROR;
2813         }
2814
2815         gst_element_set_state(queue, GST_STATE_PAUSED);
2816         player->audio_mode.total_track_num++;
2817
2818 ERROR:
2819
2820         if (srcpad) {
2821                 gst_object_unref(GST_OBJECT(srcpad));
2822                 srcpad = NULL;
2823         }
2824
2825         if (sinkpad) {
2826                 gst_object_unref(GST_OBJECT(sinkpad));
2827                 sinkpad = NULL;
2828         }
2829
2830         MMPLAYER_FLEAVE();
2831         return;
2832 }
2833
2834 static void
2835 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2836 {
2837         mm_player_t* player = NULL;
2838         GstElement* selector = NULL;
2839         GstPad* sinkpad = NULL;
2840         gint active_index = 0;
2841         gchar* change_pad_name = NULL;
2842         GstCaps* caps = NULL;   // no need to unref
2843         gint default_audio_ch = 0;
2844
2845         MMPLAYER_FENTER();
2846         player = (mm_player_t*) data;
2847
2848         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2849
2850         if (!selector) {
2851                 LOGE("there is no audio channel selector.\n");
2852                 goto ERROR;
2853         }
2854
2855         active_index = player->audio_mode.active_pad_index;
2856
2857         if (active_index != default_audio_ch) {
2858                 gint audio_ch = default_audio_ch;
2859
2860                 /*To get the new pad from the selector*/
2861                 change_pad_name = g_strdup_printf("sink%d", active_index);
2862                 if (change_pad_name != NULL) {
2863                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2864                         if (sinkpad != NULL) {
2865                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2866                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2867
2868                                 audio_ch = active_index;
2869
2870                                 caps = gst_pad_get_current_caps(sinkpad);
2871                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2872
2873                                 __mmplayer_set_audio_attrs(player, caps);
2874                                 gst_caps_unref(caps);
2875                         }
2876                         MMPLAYER_FREEIF(change_pad_name);
2877                 }
2878
2879                 player->audio_mode.active_pad_index = audio_ch;
2880                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2881         }
2882
2883 ERROR:
2884
2885         if (sinkpad)
2886                 gst_object_unref(sinkpad);
2887
2888         MMPLAYER_FLEAVE();
2889         return;
2890 }
2891
2892 static void
2893 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2894 {
2895         mm_player_t* player = NULL;
2896         MMPlayerGstElement *mainbin = NULL;
2897
2898         GstElement* tee = NULL;
2899         GstElement* stereo_queue = NULL;
2900         GstElement* mono_queue = NULL;
2901         GstElement* conv = NULL;
2902         GstElement* filter = NULL;
2903         GstElement* deinterleave = NULL;
2904         GstElement* selector = NULL;
2905
2906         GstPad* srcpad = NULL;
2907         GstPad* selector_srcpad = NULL;
2908         GstPad* sinkpad = NULL;
2909         GstCaps* caps = NULL;
2910         gulong block_id = 0;
2911
2912         MMPLAYER_FENTER();
2913
2914         /* check handles */
2915         player = (mm_player_t*) data;
2916
2917         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2918         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2919
2920         mainbin = player->pipeline->mainbin;
2921
2922         /* tee */
2923         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2924                 LOGE("ERROR : tee create error\n");
2925                 goto ERROR;
2926         }
2927
2928         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2929         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2930
2931         gst_element_set_state(tee, GST_STATE_PAUSED);
2932
2933         /* queue */
2934         srcpad = gst_element_get_request_pad(tee, "src_%u");
2935         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2936                 LOGE("ERROR : stereo queue create error\n");
2937                 goto ERROR;
2938         }
2939
2940         g_object_set(G_OBJECT(stereo_queue),
2941                                 "max-size-buffers", 10,
2942                                 "max-size-bytes", 0,
2943                                 "max-size-time", (guint64)0,
2944                                 NULL);
2945
2946         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2947         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2948
2949         if (srcpad) {
2950                 gst_object_unref(GST_OBJECT(srcpad));
2951                 srcpad = NULL;
2952         }
2953
2954         srcpad = gst_element_get_request_pad(tee, "src_%u");
2955
2956         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2957                 LOGE("ERROR : mono queue create error\n");
2958                 goto ERROR;
2959         }
2960
2961         g_object_set(G_OBJECT(mono_queue),
2962                                 "max-size-buffers", 10,
2963                                 "max-size-bytes", 0,
2964                                 "max-size-time", (guint64)0,
2965                                 NULL);
2966
2967         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2968         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2969
2970         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2971         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2972
2973         /* audioconvert */
2974         srcpad = gst_element_get_static_pad(mono_queue, "src");
2975         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2976                 LOGE("ERROR : audioconvert create error\n");
2977                 goto ERROR;
2978         }
2979
2980         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2981         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2982
2983         /* caps filter */
2984         if (srcpad) {
2985                 gst_object_unref(GST_OBJECT(srcpad));
2986                 srcpad = NULL;
2987         }
2988         srcpad = gst_element_get_static_pad(conv, "src");
2989
2990         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2991                 LOGE("ERROR : capsfilter create error\n");
2992                 goto ERROR;
2993         }
2994
2995         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2996         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2997
2998         caps = gst_caps_from_string("audio/x-raw-int, "
2999                                 "width = (int) 16, "
3000                                 "depth = (int) 16, "
3001                                 "channels = (int) 2");
3002
3003         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3004         gst_caps_unref(caps);
3005
3006         gst_element_set_state(conv, GST_STATE_PAUSED);
3007         gst_element_set_state(filter, GST_STATE_PAUSED);
3008
3009         /* deinterleave */
3010         if (srcpad) {
3011                 gst_object_unref(GST_OBJECT(srcpad));
3012                 srcpad = NULL;
3013         }
3014         srcpad = gst_element_get_static_pad(filter, "src");
3015
3016         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3017                 LOGE("ERROR : deinterleave create error\n");
3018                 goto ERROR;
3019         }
3020
3021         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3022
3023         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3024                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3025
3026         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3027                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3028
3029         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3030         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3031
3032         /* selector */
3033         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3034         if (selector == NULL) {
3035                 LOGE("ERROR : audio-selector create error\n");
3036                 goto ERROR;
3037         }
3038
3039         g_object_set(selector, "sync-streams", TRUE, NULL);
3040         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3041
3042         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3043         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3044
3045         selector_srcpad = gst_element_get_static_pad(selector, "src");
3046
3047         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3048         block_id =
3049                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3050                         __mmplayer_gst_selector_blocked, NULL, NULL);
3051
3052         if (srcpad) {
3053                 gst_object_unref(GST_OBJECT(srcpad));
3054                 srcpad = NULL;
3055         }
3056
3057         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3058         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3059
3060         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3061                 LOGW("failed to link queue_stereo - selector\n");
3062                 goto ERROR;
3063         }
3064
3065         player->audio_mode.total_track_num++;
3066
3067         g_object_set(selector, "active-pad", sinkpad, NULL);
3068         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3069         gst_element_set_state(selector, GST_STATE_PAUSED);
3070
3071         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3072
3073 ERROR:
3074
3075         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3076         if (block_id != 0) {
3077                 gst_pad_remove_probe(selector_srcpad, block_id);
3078                 block_id = 0;
3079         }
3080
3081         if (sinkpad) {
3082                 gst_object_unref(GST_OBJECT(sinkpad));
3083                 sinkpad = NULL;
3084         }
3085
3086         if (srcpad) {
3087                 gst_object_unref(GST_OBJECT(srcpad));
3088                 srcpad = NULL;
3089         }
3090
3091         if (selector_srcpad) {
3092                 gst_object_unref(GST_OBJECT(selector_srcpad));
3093                 selector_srcpad = NULL;
3094         }
3095
3096         MMPLAYER_FLEAVE();
3097         return;
3098 }
3099
3100 static void
3101 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3102 {
3103         mm_player_t* player = NULL;
3104         GstPad* srcpad = NULL;
3105         GstElement* video_selector = NULL;
3106         GstElement* audio_selector = NULL;
3107         GstElement* text_selector = NULL;
3108         MMHandleType attrs = 0;
3109         gint active_index = 0;
3110         gint64 dur_bytes = 0L;
3111
3112         player = (mm_player_t*) data;
3113
3114         LOGD("no-more-pad signal handling\n");
3115
3116         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3117                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3118                 LOGW("no need to go more");
3119
3120                 if (player->gapless.reconfigure) {
3121                         player->gapless.reconfigure = FALSE;
3122                         MMPLAYER_PLAYBACK_UNLOCK(player);
3123                 }
3124
3125                 return;
3126         }
3127
3128         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3129                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3130                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3131                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3132                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3133
3134                 if (NULL == player->streamer) {
3135                         LOGW("invalid state for buffering");
3136                         goto ERROR;
3137                 }
3138
3139                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3140                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3141
3142                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3143                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3144
3145                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3146
3147                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3148                         LOGE("fail to get duration.\n");
3149
3150                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3151                 // use file information was already set on Q2 when it was created.
3152                 __mm_player_streaming_set_queue2(player->streamer,
3153                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3154                                                 TRUE,                                                           // use_buffering
3155                                                 buffer_bytes,
3156                                                 init_buffering_time,
3157                                                 1.0,                                                            // low percent
3158                                                 player->ini.http_buffering_limit,       // high percent
3159                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3160                                                 NULL,
3161                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3162         }
3163
3164         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3165         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3166         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3167         if (video_selector) {
3168                 // [link] input-selector :: videobin
3169                 srcpad = gst_element_get_static_pad(video_selector, "src");
3170                 if (!srcpad) {
3171                         LOGE("failed to get srcpad from video selector\n");
3172                         goto ERROR;
3173                 }
3174
3175                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3176                 if (!text_selector && !audio_selector)
3177                         player->no_more_pad = TRUE;
3178
3179                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3180
3181                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3182                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3183                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3184                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3185                 }
3186         }
3187
3188         if (audio_selector) {
3189                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3190                 if ((active_index != DEFAULT_TRACK) &&
3191                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3192                         LOGW("failed to change audio track\n");
3193                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3194                 }
3195
3196                 // [link] input-selector :: audiobin
3197                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3198                 if (!srcpad) {
3199                         LOGE("failed to get srcpad from selector\n");
3200                         goto ERROR;
3201                 }
3202
3203                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3204                 if (!text_selector)
3205                         player->no_more_pad = TRUE;
3206
3207                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3208                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3209                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3210                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3211                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3212                         }
3213
3214                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3215                 } else {
3216                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3217
3218                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3219                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3220                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3221                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3222                         }
3223                 }
3224
3225                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3226
3227                 attrs = MMPLAYER_GET_ATTRS(player);
3228                 if (attrs) {
3229                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3230                         if (mmf_attrs_commit(attrs))
3231                                 LOGE("failed to commit.\n");
3232                 } else
3233                         LOGE("cannot get content attribute");
3234         } else {
3235                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3236                         LOGD("There is no audio track : remove audiobin");
3237
3238                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3239                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3240
3241                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3242                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3243                 }
3244
3245                 if (player->num_dynamic_pad == 0)
3246                         __mmplayer_pipeline_complete(NULL, player);
3247         }
3248
3249         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3250                 if (text_selector)
3251                         __mmplayer_handle_text_decode_path(player, text_selector);
3252         }
3253
3254         MMPLAYER_FLEAVE();
3255
3256 ERROR:
3257         if (srcpad) {
3258                 gst_object_unref(GST_OBJECT(srcpad));
3259                 srcpad = NULL;
3260         }
3261
3262         if (player->gapless.reconfigure) {
3263                 player->gapless.reconfigure = FALSE;
3264                 MMPLAYER_PLAYBACK_UNLOCK(player);
3265         }
3266 }
3267
3268 static void
3269 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3270 {
3271         mm_player_t* player = NULL;
3272         MMHandleType attrs = 0;
3273         GstElement* pipeline = NULL;
3274         GstCaps* caps = NULL;
3275         gchar* caps_str = NULL;
3276         GstStructure* str = NULL;
3277         const gchar* name = NULL;
3278         GstPad* sinkpad = NULL;
3279         GstElement* sinkbin = NULL;
3280         gboolean reusing = FALSE;
3281         GstElement *text_selector = NULL;
3282
3283         /* check handles */
3284         player = (mm_player_t*) data;
3285
3286         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3287         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3288
3289         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3290
3291         attrs = MMPLAYER_GET_ATTRS(player);
3292         if (!attrs) {
3293                 LOGE("cannot get content attribute\n");
3294                 goto ERROR;
3295         }
3296
3297         /* get mimetype from caps */
3298         caps = gst_pad_query_caps(pad, NULL);
3299         if (!caps) {
3300                 LOGE("cannot get caps from pad.\n");
3301                 goto ERROR;
3302         }
3303         caps_str = gst_caps_to_string(caps);
3304
3305         str = gst_caps_get_structure(caps, 0);
3306         if (!str) {
3307                 LOGE("cannot get structure from caps.\n");
3308                 goto ERROR;
3309         }
3310
3311         name = gst_structure_get_name(str);
3312         if (!name) {
3313                 LOGE("cannot get mimetype from structure.\n");
3314                 goto ERROR;
3315         }
3316
3317         //LOGD("detected mimetype : %s\n", name);
3318
3319         if (strstr(name, "audio")) {
3320                 if (player->pipeline->audiobin == NULL) {
3321                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3322                                 LOGE("failed to create audiobin. continuing without audio\n");
3323                                 goto ERROR;
3324                         }
3325
3326                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3327                         LOGD("creating audiosink bin success\n");
3328                 } else {
3329                         reusing = TRUE;
3330                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3331                         LOGD("reusing audiobin\n");
3332                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3333                 }
3334
3335                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3336                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3337
3338                 player->audiosink_linked  = 1;
3339
3340                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3341                 if (!sinkpad) {
3342                         LOGE("failed to get pad from sinkbin\n");
3343                         goto ERROR;
3344                 }
3345         } else if (strstr(name, "video")) {
3346                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3347                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3348                         player->set_mode.video_zc = TRUE;
3349
3350                 if (player->pipeline->videobin == NULL) {
3351                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3352                         /* get video surface type */
3353                         int surface_type = 0;
3354                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3355                         LOGD("display_surface_type(%d)\n", surface_type);
3356
3357                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3358                                 LOGD("not make videobin because it dose not want\n");
3359                                 goto ERROR;
3360                         }
3361
3362                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3363                                 /* mark video overlay for acquire */
3364                                 if (player->video_overlay_resource == NULL) {
3365                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3366                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3367                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3368                                                         &player->video_overlay_resource)
3369                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3370                                                 LOGE("could not mark video_overlay resource for acquire\n");
3371                                                 goto ERROR;
3372                                         }
3373                                 }
3374                         }
3375
3376                         player->interrupted_by_resource = FALSE;
3377                         /* acquire resources for video overlay */
3378                         if (mm_resource_manager_commit(player->resource_manager) !=
3379                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3380                                 LOGE("could not acquire resources for video playing\n");
3381                                 goto ERROR;
3382                         }
3383
3384                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3385                                 LOGE("failed to create videobin. continuing without video\n");
3386                                 goto ERROR;
3387                         }
3388
3389                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3390                         LOGD("creating videosink bin success\n");
3391                 } else {
3392                         reusing = TRUE;
3393                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3394                         LOGD("re-using videobin\n");
3395                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3396                 }
3397
3398                 player->videosink_linked  = 1;
3399
3400                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3401                 if (!sinkpad) {
3402                         LOGE("failed to get pad from sinkbin\n");
3403                         goto ERROR;
3404                 }
3405         } else if (strstr(name, "text")) {
3406                 if (player->pipeline->textbin == NULL) {
3407                         MMPlayerGstElement* mainbin = NULL;
3408
3409                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3410                                 LOGE("failed to create text sink bin. continuing without text\n");
3411                                 goto ERROR;
3412                         }
3413
3414                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3415                         LOGD("creating textsink bin success\n");
3416
3417                         /* FIXIT : track number shouldn't be hardcoded */
3418                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3419
3420                         player->textsink_linked  = 1;
3421                         LOGI("player->textsink_linked set to 1\n");
3422
3423                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3424                         if (!sinkpad) {
3425                                 LOGE("failed to get pad from sinkbin\n");
3426                                 goto ERROR;
3427                         }
3428
3429                         mainbin = player->pipeline->mainbin;
3430
3431                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3432                                 /* input selector */
3433                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3434                                 if (!text_selector) {
3435                                         LOGE("failed to create subtitle input selector element\n");
3436                                         goto ERROR;
3437                                 }
3438                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3439
3440                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3441                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3442
3443                                 /* warm up */
3444                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3445                                         LOGE("failed to set state(READY) to sinkbin\n");
3446                                         goto ERROR;
3447                                 }
3448
3449                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3450                                         LOGW("failed to add subtitle input selector\n");
3451                                         goto ERROR;
3452                                 }
3453
3454                                 LOGD("created element input-selector");
3455
3456                         } else {
3457                                 LOGD("already having subtitle input selector");
3458                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3459                         }
3460                 } else {
3461                         if (!player->textsink_linked) {
3462                                 LOGD("re-using textbin\n");
3463
3464                                 reusing = TRUE;
3465                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3466
3467                                 player->textsink_linked  = 1;
3468                                 LOGI("player->textsink_linked set to 1\n");
3469                         } else
3470                                 LOGD("ignoring internal subtutle since external subtitle is available");
3471                 }
3472         } else {
3473                 LOGW("unknown type of elementary stream!ignoring it...\n");
3474                 goto ERROR;
3475         }
3476
3477         if (sinkbin) {
3478                 if (!reusing) {
3479                         /* warm up */
3480                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3481                                 LOGE("failed to set state(READY) to sinkbin\n");
3482                                 goto ERROR;
3483                         }
3484
3485                         /* Added for multi audio support to avoid adding audio bin again*/
3486                         /* add */
3487                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3488                                 LOGE("failed to add sinkbin to pipeline\n");
3489                                 goto ERROR;
3490                         }
3491                 }
3492
3493                 /* link */
3494                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3495                         LOGE("failed to get pad from sinkbin\n");
3496                         goto ERROR;
3497                 }
3498
3499                 if (!reusing) {
3500                         /* run */
3501                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3502                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3503                                 goto ERROR;
3504                         }
3505
3506                         if (text_selector) {
3507                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3508                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3509                                         goto ERROR;
3510                                 }
3511                         }
3512                 }
3513
3514                 gst_object_unref(sinkpad);
3515                 sinkpad = NULL;
3516         }
3517
3518         LOGD("[handle: %p] linking sink bin success", player);
3519
3520         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3521          * streaming task. if the task blocked, then buffer will not flow to the next element
3522          *(autoplugging element). so this is special hack for streaming. please try to remove it
3523          */
3524         /* dec stream count. we can remove fakesink if it's zero */
3525         if (player->num_dynamic_pad)
3526                 player->num_dynamic_pad--;
3527
3528         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3529
3530         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3531                 __mmplayer_pipeline_complete(NULL, player);
3532
3533 ERROR:
3534
3535         MMPLAYER_FREEIF(caps_str);
3536
3537         if (caps)
3538                 gst_caps_unref(caps);
3539
3540         if (sinkpad)
3541                 gst_object_unref(GST_OBJECT(sinkpad));
3542
3543         /* flusing out new attributes */
3544         if (mmf_attrs_commit(attrs))
3545                 LOGE("failed to comit attributes\n");
3546
3547         return;
3548 }
3549
3550 static gboolean
3551 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3552 {
3553         int pro_value = 0; // in the case of expection, default will be returned.
3554         int dest_angle = rotation_angle;
3555         int rotation_type = -1;
3556
3557         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3558         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3559         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3560
3561         if (rotation_angle >= 360)
3562                 dest_angle = rotation_angle - 360;
3563
3564         /* chech if supported or not */
3565         if (dest_angle % 90) {
3566                 LOGD("not supported rotation angle = %d", rotation_angle);
3567                 return FALSE;
3568         }
3569
3570         /*
3571           * tizenwlsink (A)
3572           * custom_convert - none (B)
3573           * videoflip - none (C)
3574           */
3575         if (player->set_mode.video_zc) {
3576                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3577                         rotation_type = ROTATION_USING_CUSTOM;
3578                 else // A
3579                         rotation_type = ROTATION_USING_SINK;
3580         } else {
3581                 int surface_type = 0;
3582                 rotation_type = ROTATION_USING_FLIP;
3583
3584                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3585                 LOGD("check display surface type attribute: %d", surface_type);
3586
3587                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3588                         rotation_type = ROTATION_USING_SINK;
3589                 else
3590                         rotation_type = ROTATION_USING_FLIP; //C
3591
3592                 LOGD("using %d type for rotation", rotation_type);
3593         }
3594
3595         /* get property value for setting */
3596         switch (rotation_type) {
3597         case ROTATION_USING_SINK: // tizenwlsink
3598                 {
3599                         switch (dest_angle) {
3600                         case 0:
3601                                 break;
3602                         case 90:
3603                                 pro_value = 3; // clockwise 90
3604                                 break;
3605                         case 180:
3606                                 pro_value = 2;
3607                                 break;
3608                         case 270:
3609                                 pro_value = 1; // counter-clockwise 90
3610                                 break;
3611                         }
3612                 }
3613                 break;
3614         case ROTATION_USING_CUSTOM:
3615                 {
3616                         gchar *ename = NULL;
3617                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3618
3619                         if (g_strrstr(ename, "fimcconvert")) {
3620                                 switch (dest_angle) {
3621                                 case 0:
3622                                         break;
3623                                 case 90:
3624                                         pro_value = 90; // clockwise 90
3625                                         break;
3626                                 case 180:
3627                                         pro_value = 180;
3628                                         break;
3629                                 case 270:
3630                                         pro_value = 270; // counter-clockwise 90
3631                                         break;
3632                                 }
3633                         }
3634                 }
3635                 break;
3636         case ROTATION_USING_FLIP: // videoflip
3637                 {
3638                                 switch (dest_angle) {
3639                                 case 0:
3640                                         break;
3641                                 case 90:
3642                                         pro_value = 1; // clockwise 90
3643                                         break;
3644                                 case 180:
3645                                         pro_value = 2;
3646                                         break;
3647                                 case 270:
3648                                         pro_value = 3; // counter-clockwise 90
3649                                         break;
3650                                 }
3651                 }
3652                 break;
3653         }
3654
3655         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3656
3657         *value = pro_value;
3658
3659         return TRUE;
3660 }
3661
3662 int
3663 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3664 {
3665         /* check video sinkbin is created */
3666         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3667                 player->pipeline &&
3668                 player->pipeline->videobin &&
3669                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3670                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3671                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3672
3673         return MM_ERROR_NONE;
3674 }
3675
3676 void
3677 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3678 {
3679         int rotation_value = 0;
3680         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3681         int user_angle = 0;
3682         MMPLAYER_FENTER();
3683
3684         /* check video sinkbin is created */
3685         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3686                 return;
3687
3688         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3689
3690         /* get rotation value to set */
3691         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3692         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3693         LOGD("set video param : rotate %d", rotation_value);
3694 }
3695
3696 void
3697 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3698 {
3699         MMHandleType attrs = 0;
3700         int visible = 0;
3701         MMPLAYER_FENTER();
3702
3703         /* check video sinkbin is created */
3704         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3705                 return;
3706
3707         attrs = MMPLAYER_GET_ATTRS(player);
3708         MMPLAYER_RETURN_IF_FAIL(attrs);
3709
3710         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3711         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3712         LOGD("set video param : visible %d", visible);
3713 }
3714
3715 void
3716 __mmplayer_video_param_set_display_method(mm_player_t* player)
3717 {
3718         MMHandleType attrs = 0;
3719         int display_method = 0;
3720         MMPLAYER_FENTER();
3721
3722         /* check video sinkbin is created */
3723         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3724                 return;
3725
3726         attrs = MMPLAYER_GET_ATTRS(player);
3727         MMPLAYER_RETURN_IF_FAIL(attrs);
3728
3729         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3730         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3731         LOGD("set video param : method %d", display_method);
3732 }
3733
3734 void
3735 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3736 {
3737         MMHandleType attrs = 0;
3738         void *handle = NULL;
3739         /*set wl_display*/
3740         int wl_window_x = 0;
3741         int wl_window_y = 0;
3742         int wl_window_width = 0;
3743         int wl_window_height = 0;
3744         MMPLAYER_FENTER();
3745
3746         /* check video sinkbin is created */
3747         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3748                 return;
3749
3750         attrs = MMPLAYER_GET_ATTRS(player);
3751         MMPLAYER_RETURN_IF_FAIL(attrs);
3752
3753         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3754
3755         if (handle) {
3756                 /*It should be set after setting window*/
3757                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3758                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3759                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3760                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3761
3762                 /* After setting window handle, set render      rectangle */
3763                 gst_video_overlay_set_render_rectangle(
3764                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3765                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3766                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3767                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3768
3769         }
3770 }
3771 void
3772 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3773 {
3774         MMHandleType attrs = 0;
3775         void *handle = NULL;
3776
3777         /* check video sinkbin is created */
3778         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3779                 return;
3780
3781         attrs = MMPLAYER_GET_ATTRS(player);
3782         MMPLAYER_RETURN_IF_FAIL(attrs);
3783
3784         /* common case if using overlay surface */
3785         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3786
3787         if (handle) {
3788                 /* default is using wl_surface_id */
3789                 unsigned int wl_surface_id      = 0;
3790                 wl_surface_id = *(int*)handle;
3791                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3792                 gst_video_overlay_set_wl_window_wl_surface_id(
3793                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3794                                 *(int*)handle);
3795         } else
3796                 /* FIXIT : is it error case? */
3797                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3798 }
3799
3800
3801 int
3802 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3803 {
3804         bool update_all_param = FALSE;
3805         MMPLAYER_FENTER();
3806
3807         /* check video sinkbin is created */
3808         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3809                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3810
3811         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3812                 LOGE("can not find tizenwlsink");
3813                 return MM_ERROR_PLAYER_INTERNAL;
3814         }
3815
3816         LOGD("param_name : %s", param_name);
3817         if (!g_strcmp0(param_name, "update_all_param"))
3818                 update_all_param = TRUE;
3819
3820         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3821                 __mmplayer_video_param_set_display_overlay(player);
3822         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3823                 __mmplayer_video_param_set_display_method(player);
3824         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3825                 __mmplayer_video_param_set_render_rectangle(player);
3826         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3827                 __mmplayer_video_param_set_display_visible(player);
3828         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3829                 __mmplayer_video_param_set_display_rotation(player);
3830
3831         return MM_ERROR_NONE;
3832 }
3833
3834 int
3835 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3836 {
3837         MMHandleType attrs = 0;
3838         int surface_type = 0;
3839         int ret = MM_ERROR_NONE;
3840
3841         MMPLAYER_FENTER();
3842
3843         /* check video sinkbin is created */
3844         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3845                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3846
3847         attrs = MMPLAYER_GET_ATTRS(player);
3848         if (!attrs) {
3849                 LOGE("cannot get content attribute");
3850                 return MM_ERROR_PLAYER_INTERNAL;
3851         }
3852         LOGD("param_name : %s", param_name);
3853
3854         /* update display surface */
3855         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3856         LOGD("check display surface type attribute: %d", surface_type);
3857
3858         /* configuring display */
3859         switch (surface_type) {
3860         case MM_DISPLAY_SURFACE_OVERLAY:
3861                 {
3862                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3863                         if (ret != MM_ERROR_NONE)
3864                                 return ret;
3865                 }
3866                 break;
3867         }
3868
3869         MMPLAYER_FLEAVE();
3870
3871         return MM_ERROR_NONE;
3872 }
3873
3874 int
3875 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3876 {
3877         gboolean disable_overlay = FALSE;
3878         mm_player_t* player = (mm_player_t*) hplayer;
3879         int ret = MM_ERROR_NONE;
3880
3881         MMPLAYER_FENTER();
3882         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3883         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3884                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3885                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3886
3887         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3888                 LOGW("Display control is not supported");
3889                 return MM_ERROR_PLAYER_INTERNAL;
3890         }
3891
3892         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3893
3894         if (audio_only == (bool)disable_overlay) {
3895                 LOGE("It's the same with current setting: (%d)", audio_only);
3896                 return MM_ERROR_NONE;
3897         }
3898
3899         if (audio_only) {
3900                 LOGE("disable overlay");
3901                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3902
3903                 /* release overlay resource */
3904                 if (player->video_overlay_resource != NULL) {
3905                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3906                                         player->video_overlay_resource);
3907                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3908                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3909                                 goto ERROR;
3910                         }
3911                         player->video_overlay_resource = NULL;
3912                 }
3913
3914                 ret = mm_resource_manager_commit(player->resource_manager);
3915                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3916                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3917                         goto ERROR;
3918                 }
3919         } else {
3920                 /* mark video overlay for acquire */
3921                 if (player->video_overlay_resource == NULL) {
3922                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3923                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3924                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3925                                         &player->video_overlay_resource);
3926                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3927                                 LOGE("could not prepare for video_overlay resource\n");
3928                                 goto ERROR;
3929                         }
3930                 }
3931
3932                 player->interrupted_by_resource = FALSE;
3933                 /* acquire resources for video overlay */
3934                 ret = mm_resource_manager_commit(player->resource_manager);
3935                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3936                         LOGE("could not acquire resources for video playing\n");
3937                         goto ERROR;
3938                 }
3939
3940                 LOGD("enable overlay");
3941                 __mmplayer_video_param_set_display_overlay(player);
3942                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3943         }
3944
3945 ERROR:
3946         MMPLAYER_FLEAVE();
3947         return MM_ERROR_NONE;
3948 }
3949
3950 int
3951 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3952 {
3953         mm_player_t* player = (mm_player_t*) hplayer;
3954         gboolean disable_overlay = FALSE;
3955
3956         MMPLAYER_FENTER();
3957
3958         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3959         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3960         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3961                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3962                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3963
3964         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3965                 LOGW("Display control is not supported");
3966                 return MM_ERROR_PLAYER_INTERNAL;
3967         }
3968
3969         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3970
3971         *paudio_only = (bool)(disable_overlay);
3972
3973         LOGD("audio_only : %d", *paudio_only);
3974
3975         MMPLAYER_FLEAVE();
3976
3977         return MM_ERROR_NONE;
3978 }
3979
3980 static int
3981 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3982 {
3983         GList* bucket = element_bucket;
3984         MMPlayerGstElement* element = NULL;
3985         MMPlayerGstElement* prv_element = NULL;
3986         gint successful_link_count = 0;
3987
3988         MMPLAYER_FENTER();
3989
3990         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3991
3992         prv_element = (MMPlayerGstElement*)bucket->data;
3993         bucket = bucket->next;
3994
3995         for (; bucket; bucket = bucket->next) {
3996                 element = (MMPlayerGstElement*)bucket->data;
3997
3998                 if (element && element->gst) {
3999                         /* If next element is audio appsrc then make a separate audio pipeline */
4000                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4001                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4002                                 prv_element = element;
4003                                 continue;
4004                         }
4005
4006                         if (prv_element && prv_element->gst) {
4007                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4008                                         LOGD("linking [%s] to [%s] success\n",
4009                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4010                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4011                                         successful_link_count++;
4012                                 } else {
4013                                         LOGD("linking [%s] to [%s] failed\n",
4014                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4015                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4016                                         return -1;
4017                                 }
4018                         }
4019                 }
4020
4021                 prv_element = element;
4022         }
4023
4024         MMPLAYER_FLEAVE();
4025
4026         return successful_link_count;
4027 }
4028
4029 static int
4030 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4031 {
4032         GList* bucket = element_bucket;
4033         MMPlayerGstElement* element = NULL;
4034         int successful_add_count = 0;
4035
4036         MMPLAYER_FENTER();
4037
4038         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4039         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4040
4041         for (; bucket; bucket = bucket->next) {
4042                 element = (MMPlayerGstElement*)bucket->data;
4043
4044                 if (element && element->gst) {
4045                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4046                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4047                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4048                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4049                                 return 0;
4050                         }
4051                         successful_add_count++;
4052                 }
4053         }
4054
4055         MMPLAYER_FLEAVE();
4056
4057         return successful_add_count;
4058 }
4059
4060 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4061 {
4062         mm_player_t* player = (mm_player_t*) data;
4063         GstCaps *caps = NULL;
4064         GstStructure *str = NULL;
4065         const char *name;
4066
4067         MMPLAYER_FENTER();
4068
4069         MMPLAYER_RETURN_IF_FAIL(pad)
4070         MMPLAYER_RETURN_IF_FAIL(unused)
4071         MMPLAYER_RETURN_IF_FAIL(data)
4072
4073         caps = gst_pad_get_current_caps(pad);
4074         if (!caps)
4075                 return;
4076
4077         str = gst_caps_get_structure(caps, 0);
4078         if (!str)
4079                 goto ERROR;
4080
4081         name = gst_structure_get_name(str);
4082         if (!name)
4083                 goto ERROR;
4084
4085         LOGD("name = %s\n", name);
4086
4087         if (strstr(name, "audio")) {
4088                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4089
4090                 if (player->audio_stream_changed_cb) {
4091                         LOGE("call the audio stream changed cb\n");
4092                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4093                 }
4094         } else if (strstr(name, "video")) {
4095                 if ((name = gst_structure_get_string(str, "format")))
4096                         player->set_mode.video_zc = name[0] == 'S';
4097
4098                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4099
4100                 if (player->video_stream_changed_cb) {
4101                         LOGE("call the video stream changed cb\n");
4102                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4103                 }
4104         } else
4105                 goto ERROR;
4106
4107 ERROR:
4108
4109         gst_caps_unref(caps);
4110
4111         MMPLAYER_FLEAVE();
4112
4113         return;
4114 }
4115
4116
4117
4118 /**
4119  * This function is to create audio pipeline for playing.
4120  *
4121  * @param       player          [in]    handle of player
4122  *
4123  * @return      This function returns zero on success.
4124  * @remark
4125  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4126  */
4127 /* macro for code readability. just for sinkbin-creation functions */
4128 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4129 do {\
4130         x_bin[x_id].id = x_id;\
4131         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4132         if (!x_bin[x_id].gst) {\
4133                 LOGE("failed to create %s \n", x_factory);\
4134                 goto ERROR;\
4135         } else {\
4136                 if (x_player->ini.set_dump_element_flag)\
4137                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4138         } \
4139         if (x_add_bucket)\
4140                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4141 } while (0);
4142
4143 static void
4144 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4145 {
4146         GList *l = NULL;
4147
4148         MMPLAYER_FENTER();
4149         MMPLAYER_RETURN_IF_FAIL(player);
4150
4151         if (player->audio_stream_buff_list) {
4152                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4153                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4154                         if (tmp) {
4155                                 if (send_all) {
4156                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4157                                         __mmplayer_audio_stream_send_data(player, tmp);
4158                                 }
4159                                 if (tmp->pcm_data)
4160                                         g_free(tmp->pcm_data);
4161                                 g_free(tmp);
4162                         }
4163                 }
4164                 g_list_free(player->audio_stream_buff_list);
4165                 player->audio_stream_buff_list = NULL;
4166         }
4167
4168         MMPLAYER_FLEAVE();
4169 }
4170
4171 static void
4172 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4173 {
4174         MMPlayerAudioStreamDataType audio_stream = { 0, };
4175
4176         MMPLAYER_FENTER();
4177         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4178
4179         audio_stream.bitrate = a_buffer->bitrate;
4180         audio_stream.channel = a_buffer->channel;
4181         audio_stream.depth = a_buffer->depth;
4182         audio_stream.is_little_endian = a_buffer->is_little_endian;
4183         audio_stream.channel_mask = a_buffer->channel_mask;
4184         audio_stream.data_size = a_buffer->data_size;
4185         audio_stream.data = a_buffer->pcm_data;
4186
4187         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4188         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4189
4190         MMPLAYER_FLEAVE();
4191 }
4192
4193 static void
4194 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4195 {
4196         mm_player_t* player = (mm_player_t*) data;
4197
4198         gint channel = 0;
4199         gint rate = 0;
4200         gint depth = 0;
4201         gint endianness = 0;
4202         guint64 channel_mask = 0;
4203         void *a_data = NULL;
4204         gint a_size = 0;
4205         mm_player_audio_stream_buff_t *a_buffer = NULL;
4206         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4207         GList *l = NULL;
4208
4209         MMPLAYER_FENTER();
4210         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4211
4212         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4213         a_data = mapinfo.data;
4214         a_size = mapinfo.size;
4215
4216         GstCaps *caps = gst_pad_get_current_caps(pad);
4217         GstStructure *structure = gst_caps_get_structure(caps, 0);
4218
4219         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4220         gst_structure_get_int(structure, "rate", &rate);
4221         gst_structure_get_int(structure, "channels", &channel);
4222         gst_structure_get_int(structure, "depth", &depth);
4223         gst_structure_get_int(structure, "endianness", &endianness);
4224         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4225         gst_caps_unref(GST_CAPS(caps));
4226
4227         /* In case of the sync is false, use buffer list.              *
4228          * The num of buffer list depends on the num of audio channels */
4229         if (player->audio_stream_buff_list) {
4230                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4231                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4232                         if (tmp) {
4233                                 if (channel_mask == tmp->channel_mask) {
4234                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4235                                         if (tmp->data_size + a_size < tmp->buff_size) {
4236                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4237                                                 tmp->data_size += a_size;
4238                                         } else {
4239                                                 /* send data to client */
4240                                                 __mmplayer_audio_stream_send_data(player, tmp);
4241
4242                                                 if (a_size > tmp->buff_size) {
4243                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4244                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4245                                                         if (tmp->pcm_data == NULL) {
4246                                                                 LOGE("failed to realloc data.");
4247                                                                 goto DONE;
4248                                                         }
4249                                                         tmp->buff_size = a_size;
4250                                                 }
4251                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4252                                                 memcpy(tmp->pcm_data, a_data, a_size);
4253                                                 tmp->data_size = a_size;
4254                                         }
4255                                         goto DONE;
4256                                 }
4257                         } else {
4258                                 LOGE("data is empty in list.");
4259                                 goto DONE;
4260                         }
4261                 }
4262         }
4263
4264         /* create new audio stream data */
4265         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4266         if (a_buffer == NULL) {
4267                 LOGE("failed to alloc data.");
4268                 goto DONE;
4269         }
4270         a_buffer->bitrate = rate;
4271         a_buffer->channel = channel;
4272         a_buffer->depth = depth;
4273         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4274         a_buffer->channel_mask = channel_mask;
4275         a_buffer->data_size = a_size;
4276
4277         if (!player->audio_stream_sink_sync) {
4278                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4279                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4280                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4281                 if (a_buffer->pcm_data == NULL) {
4282                         LOGE("failed to alloc data.");
4283                         g_free(a_buffer);
4284                         goto DONE;
4285                 }
4286                 memcpy(a_buffer->pcm_data, a_data, a_size);
4287                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4288                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4289         } else {
4290                 /* If sync is TRUE, send data directly. */
4291                 a_buffer->pcm_data = a_data;
4292                 __mmplayer_audio_stream_send_data(player, a_buffer);
4293                 g_free(a_buffer);
4294         }
4295
4296 DONE:
4297         gst_buffer_unmap(buffer, &mapinfo);
4298         MMPLAYER_FLEAVE();
4299 }
4300
4301 static void
4302 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4303 {
4304         mm_player_t* player = (mm_player_t*)data;
4305         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4306         GstPad* sinkpad = NULL;
4307         GstElement *queue = NULL, *sink = NULL;
4308
4309         MMPLAYER_FENTER();
4310         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4311
4312         queue = gst_element_factory_make("queue", NULL);
4313         if (queue == NULL) {
4314                 LOGD("fail make queue\n");
4315                 goto ERROR;
4316         }
4317
4318         sink = gst_element_factory_make("fakesink", NULL);
4319         if (sink == NULL) {
4320                 LOGD("fail make fakesink\n");
4321                 goto ERROR;
4322         }
4323
4324         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4325
4326         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4327                 LOGW("failed to link queue & sink\n");
4328                 goto ERROR;
4329         }
4330
4331         sinkpad = gst_element_get_static_pad(queue, "sink");
4332
4333         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4334                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4335                 goto ERROR;
4336         }
4337
4338         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4339
4340         gst_object_unref(sinkpad);
4341         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4342         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4343
4344         gst_element_set_state(sink, GST_STATE_PAUSED);
4345         gst_element_set_state(queue, GST_STATE_PAUSED);
4346
4347         MMPLAYER_SIGNAL_CONNECT(player,
4348                 G_OBJECT(sink),
4349                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4350                 "handoff",
4351                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4352                 (gpointer)player);
4353
4354         MMPLAYER_FLEAVE();
4355         return;
4356
4357 ERROR:
4358         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4359         if (queue) {
4360                 gst_object_unref(GST_OBJECT(queue));
4361                 queue = NULL;
4362         }
4363         if (sink) {
4364                 gst_object_unref(GST_OBJECT(sink));
4365                 sink = NULL;
4366         }
4367         if (sinkpad) {
4368                 gst_object_unref(GST_OBJECT(sinkpad));
4369                 sinkpad = NULL;
4370         }
4371
4372         return;
4373 }
4374
4375 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4376 {
4377         #define MAX_PROPS_LEN 128
4378         gint latency_mode = 0;
4379         gchar *stream_type = NULL;
4380         gchar *latency = NULL;
4381         gint stream_id = 0;
4382         gchar stream_props[MAX_PROPS_LEN] = {0,};
4383         GstStructure *props = NULL;
4384
4385         /* set volume table
4386          * It should be set after player creation through attribute.
4387          * But, it can not be changed during playing.
4388          */
4389         MMPLAYER_FENTER();
4390         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4391         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4392
4393         if (!stream_type) {
4394                 LOGE("stream_type is null.\n");
4395         } else {
4396                 if (player->sound.focus_id)
4397                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4398                                         stream_type, stream_id, player->sound.focus_id);
4399                 else
4400                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4401                                         stream_type, stream_id);
4402                 props = gst_structure_from_string(stream_props, NULL);
4403                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4404                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4405                         stream_type, stream_id, player->sound.focus_id, stream_props);
4406                 gst_structure_free(props);
4407         }
4408
4409         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4410
4411         switch (latency_mode) {
4412         case AUDIO_LATENCY_MODE_LOW:
4413                 latency = g_strndup("low", 3);
4414                 break;
4415         case AUDIO_LATENCY_MODE_MID:
4416                 latency = g_strndup("mid", 3);
4417                 break;
4418         case AUDIO_LATENCY_MODE_HIGH:
4419                 latency = g_strndup("high", 4);
4420                 break;
4421         };
4422
4423         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4424                         "latency", latency,
4425                         NULL);
4426
4427         LOGD("audiosink property - latency=%s \n", latency);
4428
4429         g_free(latency);
4430
4431         MMPLAYER_FLEAVE();
4432 }
4433
4434 static int
4435 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4436 {
4437         MMPlayerGstElement* first_element = NULL;
4438         MMPlayerGstElement* audiobin = NULL;
4439         MMHandleType attrs = 0;
4440         GstPad *pad = NULL;
4441         GstPad *ghostpad = NULL;
4442         GList* element_bucket = NULL;
4443         gboolean link_audio_sink_now = TRUE;
4444         int i = 0;
4445         GstCaps *acaps;
4446
4447         MMPLAYER_FENTER();
4448
4449         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4450
4451         /* alloc handles */
4452         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4453         if (!audiobin) {
4454                 LOGE("failed to allocate memory for audiobin\n");
4455                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4456         }
4457
4458         attrs = MMPLAYER_GET_ATTRS(player);
4459
4460         /* create bin */
4461         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4462         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4463         if (!audiobin[MMPLAYER_A_BIN].gst) {
4464                 LOGE("failed to create audiobin\n");
4465                 goto ERROR;
4466         }
4467
4468         /* take it */
4469         player->pipeline->audiobin = audiobin;
4470
4471         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4472
4473         /* Adding audiotp plugin for reverse trickplay feature */
4474 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4475
4476         /* converter */
4477         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4478
4479         /* replaygain volume */
4480         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4481         if (player->sound.rg_enable)
4482                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4483         else
4484                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4485
4486         /* resampler */
4487         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4488
4489         if (player->set_mode.pcm_extraction) {
4490                 // pcm extraction only and no sound output
4491                 if (player->audio_stream_render_cb_ex) {
4492                         char *caps_str = NULL;
4493                         GstCaps* caps = NULL;
4494                         gchar *format = NULL;
4495
4496                         /* capsfilter */
4497                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4498
4499                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4500
4501                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4502
4503                         caps = gst_caps_new_simple("audio/x-raw",
4504                                         "format", G_TYPE_STRING, format,
4505                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4506                                         "channels", G_TYPE_INT, player->pcm_channel,
4507                                         NULL);
4508                         caps_str = gst_caps_to_string(caps);
4509                         LOGD("new caps : %s\n", caps_str);
4510
4511                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4512
4513                         /* clean */
4514                         gst_caps_unref(caps);
4515                         MMPLAYER_FREEIF(caps_str);
4516
4517                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4518
4519                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4520                         /* raw pad handling signal */
4521                         MMPLAYER_SIGNAL_CONNECT(player,
4522                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4523                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4524                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4525                 } else {
4526                         int dst_samplerate = 0;
4527                         int dst_channels = 0;
4528                         int dst_depth = 0;
4529                         char *caps_str = NULL;
4530                         GstCaps* caps = NULL;
4531
4532                         /* get conf. values */
4533                         mm_attrs_multiple_get(player->attrs,
4534                                                 NULL,
4535                                                 "pcm_extraction_samplerate", &dst_samplerate,
4536                                                 "pcm_extraction_channels", &dst_channels,
4537                                                 "pcm_extraction_depth", &dst_depth,
4538                                                 NULL);
4539
4540                         /* capsfilter */
4541                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4542                         caps = gst_caps_new_simple("audio/x-raw",
4543                                         "rate", G_TYPE_INT, dst_samplerate,
4544                                         "channels", G_TYPE_INT, dst_channels,
4545                                         "depth", G_TYPE_INT, dst_depth,
4546                                         NULL);
4547                         caps_str = gst_caps_to_string(caps);
4548                         LOGD("new caps : %s\n", caps_str);
4549
4550                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4551
4552                         /* clean */
4553                         gst_caps_unref(caps);
4554                         MMPLAYER_FREEIF(caps_str);
4555
4556                         /* fake sink */
4557                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4558
4559                         /* set sync */
4560                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4561                 }
4562         } else {
4563                 // normal playback
4564                 //GstCaps* caps = NULL;
4565                 gint channels = 0;
4566
4567                 /* for logical volume control */
4568                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4569                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4570
4571                 if (player->sound.mute) {
4572                         LOGD("mute enabled\n");
4573                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4574                 }
4575
4576 #if 0
4577                 /*capsfilter */
4578                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4579                 caps = gst_caps_from_string("audio/x-raw-int, "
4580                                         "endianness = (int) LITTLE_ENDIAN, "
4581                                         "signed = (boolean) true, "
4582                                         "width = (int) 16, "
4583                                         "depth = (int) 16");
4584                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4585                 gst_caps_unref(caps);
4586 #endif
4587
4588                 /* check if multi-channels */
4589                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4590                         GstPad *srcpad = NULL;
4591                         GstCaps *caps = NULL;
4592
4593                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4594                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4595                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4596                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4597                                         if (str)
4598                                                 gst_structure_get_int(str, "channels", &channels);
4599                                         gst_caps_unref(caps);
4600                                 }
4601                                 gst_object_unref(srcpad);
4602                         }
4603                 }
4604
4605                 /* audio effect element. if audio effect is enabled */
4606                 if ((strcmp(player->ini.audioeffect_element, ""))
4607                         && (channels <= 2)
4608                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4609                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4610
4611                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4612
4613                         if ((!player->bypass_audio_effect)
4614                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4615                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4616                                         if (!_mmplayer_audio_effect_custom_apply(player))
4617                                                 LOGI("apply audio effect(custom) setting success\n");
4618                                 }
4619                         }
4620
4621                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4622                                 && (player->set_mode.rich_audio))
4623                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4624                 }
4625
4626                 /* create audio sink */
4627                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4628                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4629                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4630
4631                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4632                 if (player->is_content_spherical &&
4633                                 channels == 4 &&
4634                                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4635                                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4636                                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4637
4638                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4639
4640                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4641
4642                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4643                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4644                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4645                         gst_caps_unref(acaps);
4646
4647                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4648                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4649                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4650                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4651
4652                         player->is_openal_plugin_used = TRUE;
4653
4654                         if (player->video360_yaw_radians <= M_PI &&
4655                                         player->video360_yaw_radians >= -M_PI &&
4656                                         player->video360_pitch_radians <= M_PI_2 &&
4657                                         player->video360_pitch_radians >= -M_PI_2) {
4658                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4659                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4660                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4661                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4662                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4663                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4664                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4665                         }
4666                 } else {
4667                         if (player->is_content_spherical)
4668                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4669                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4670                 }
4671
4672                 /* qos on */
4673                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4674                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4675
4676
4677                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4678                         (player->videodec_linked && player->ini.use_system_clock)) {
4679                         LOGD("system clock will be used.\n");
4680                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4681                 }
4682
4683                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4684                         __mmplayer_gst_set_audiosink_property(player, attrs);
4685         }
4686
4687         if (audiobin[MMPLAYER_A_SINK].gst) {
4688                 GstPad *sink_pad = NULL;
4689                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4690                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4691                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4692                 gst_object_unref(GST_OBJECT(sink_pad));
4693         }
4694
4695         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4696
4697         /* adding created elements to bin */
4698         LOGD("adding created elements to bin\n");
4699         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4700                 LOGE("failed to add elements\n");
4701                 goto ERROR;
4702         }
4703
4704         /* linking elements in the bucket by added order. */
4705         LOGD("Linking elements in the bucket by added order.\n");
4706         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4707                 LOGE("failed to link elements\n");
4708                 goto ERROR;
4709         }
4710
4711         /* get first element's sinkpad for creating ghostpad */
4712         first_element = (MMPlayerGstElement *)element_bucket->data;
4713         if (!first_element) {
4714                 LOGE("failed to get first elem\n");
4715                 goto ERROR;
4716         }
4717
4718         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4719         if (!pad) {
4720                 LOGE("failed to get pad from first element of audiobin\n");
4721                 goto ERROR;
4722         }
4723
4724         ghostpad = gst_ghost_pad_new("sink", pad);
4725         if (!ghostpad) {
4726                 LOGE("failed to create ghostpad\n");
4727                 goto ERROR;
4728         }
4729
4730         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4731                 LOGE("failed to add ghostpad to audiobin\n");
4732                 goto ERROR;
4733         }
4734
4735         gst_object_unref(pad);
4736
4737         g_list_free(element_bucket);
4738         MMPLAYER_FLEAVE();
4739
4740         return MM_ERROR_NONE;
4741
4742 ERROR:
4743
4744         LOGD("ERROR : releasing audiobin\n");
4745
4746         if (pad)
4747                 gst_object_unref(GST_OBJECT(pad));
4748
4749         if (ghostpad)
4750                 gst_object_unref(GST_OBJECT(ghostpad));
4751
4752         if (element_bucket)
4753                 g_list_free(element_bucket);
4754
4755         /* release element which are not added to bin */
4756         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4757                 /* NOTE : skip bin */
4758                 if (audiobin[i].gst) {
4759                         GstObject* parent = NULL;
4760                         parent = gst_element_get_parent(audiobin[i].gst);
4761
4762                         if (!parent) {
4763                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4764                                 audiobin[i].gst = NULL;
4765                         } else
4766                                 gst_object_unref(GST_OBJECT(parent));
4767                 }
4768         }
4769
4770         /* release audiobin with it's childs */
4771         if (audiobin[MMPLAYER_A_BIN].gst)
4772                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4773
4774         MMPLAYER_FREEIF(audiobin);
4775
4776         player->pipeline->audiobin = NULL;
4777
4778         return MM_ERROR_PLAYER_INTERNAL;
4779 }
4780
4781 static GstPadProbeReturn
4782 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4783 {
4784         mm_player_t* player = (mm_player_t*) u_data;
4785         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4786         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4787
4788         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4789
4790         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4791                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4792
4793         return GST_PAD_PROBE_OK;
4794 }
4795
4796 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4797 {
4798         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4799 }
4800
4801 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4802 {
4803         int ret = MM_ERROR_NONE;
4804         GList *l = NULL;
4805         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4806         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4807
4808         MMPLAYER_VIDEO_BO_LOCK(player);
4809
4810         if (player->video_bo_list) {
4811                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4812                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4813                         if (tmp && tmp->bo == bo) {
4814                                 tmp->using = FALSE;
4815                                 LOGD("release bo %p", bo);
4816                                 tbm_bo_unref(tmp->bo);
4817                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4818                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4819                                 return ret;
4820                         }
4821                 }
4822         } else {
4823                 /* hw codec is running or the list was reset for DRC. */
4824                 LOGW("there is no bo list.");
4825         }
4826         MMPLAYER_VIDEO_BO_UNLOCK(player);
4827
4828         LOGW("failed to find bo %p", bo);
4829         return ret;
4830 }
4831
4832 static void
4833 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4834 {
4835         GList *l = NULL;
4836
4837         MMPLAYER_FENTER();
4838         MMPLAYER_RETURN_IF_FAIL(player);
4839
4840         MMPLAYER_VIDEO_BO_LOCK(player);
4841         if (player->video_bo_list) {
4842                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4843                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4844                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4845                         if (tmp) {
4846                                 if (tmp->bo)
4847                                         tbm_bo_unref(tmp->bo);
4848                                 g_free(tmp);
4849                         }
4850                 }
4851                 g_list_free(player->video_bo_list);
4852                 player->video_bo_list = NULL;
4853         }
4854         player->video_bo_size = 0;
4855         MMPLAYER_VIDEO_BO_UNLOCK(player);
4856
4857         MMPLAYER_FLEAVE();
4858         return;
4859 }
4860
4861 static void*
4862 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4863 {
4864         GList *l = NULL;
4865         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4866         gboolean ret = TRUE;
4867
4868         /* check DRC, if it is, destroy the prev bo list to create again */
4869         if (player->video_bo_size != size) {
4870                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4871                 __mmplayer_video_stream_destroy_bo_list(player);
4872                 player->video_bo_size = size;
4873         }
4874
4875         MMPLAYER_VIDEO_BO_LOCK(player);
4876
4877         if ((!player->video_bo_list) ||
4878                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4879
4880                 /* create bo list */
4881                 int idx = 0;
4882                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4883
4884                 if (player->video_bo_list) {
4885                         /* if bo list did not created all, try it again. */
4886                         idx = g_list_length(player->video_bo_list);
4887                         LOGD("bo list exist(len: %d)", idx);
4888                 }
4889
4890                 for (; idx < player->ini.num_of_video_bo; idx++) {
4891                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4892                         if (!bo_info) {
4893                                 LOGE("Fail to alloc bo_info.");
4894                                 break;
4895                         }
4896                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4897                         if (!bo_info->bo) {
4898                                 LOGE("Fail to tbm_bo_alloc.");
4899                                 g_free(bo_info);
4900                                 break;
4901                         }
4902                         bo_info->using = FALSE;
4903                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4904                 }
4905
4906                 /* update video num buffers */
4907                 player->video_num_buffers = idx;
4908                 if (idx == player->ini.num_of_video_bo)
4909                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4910
4911                 if (idx == 0) {
4912                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4913                         return NULL;
4914                 }
4915
4916                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4917         }
4918
4919         while (TRUE) {
4920                 /* get bo from list*/
4921                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4922                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4923                         if (tmp && (tmp->using == FALSE)) {
4924                                 LOGD("found bo %p to use", tmp->bo);
4925                                 tmp->using = TRUE;
4926                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4927                                 return tbm_bo_ref(tmp->bo);
4928                         }
4929                 }
4930                 if (!ret) {
4931                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4932                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4933                         return NULL;
4934                 }
4935
4936                 if (player->ini.video_bo_timeout <= 0) {
4937                         MMPLAYER_VIDEO_BO_WAIT(player);
4938                 } else {
4939                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4940                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4941                 }
4942                 continue;
4943         }
4944 }
4945
4946 static void
4947 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4948 {
4949         mm_player_t* player = (mm_player_t*)data;
4950         MMPLAYER_FENTER();
4951         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4952
4953         /* send prerolled pkt */
4954         player->video_stream_prerolled = FALSE;
4955
4956         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4957
4958         /* not to send prerolled pkt again */
4959         player->video_stream_prerolled = TRUE;
4960 }
4961
4962 static void
4963 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4964 {
4965         mm_player_t* player = (mm_player_t*)data;
4966         GstCaps *caps = NULL;
4967         MMPlayerVideoStreamDataType *stream = NULL;
4968         MMVideoBuffer *video_buffer = NULL;
4969         GstMemory *dataBlock = NULL;
4970         GstMemory *metaBlock = NULL;
4971         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4972         GstStructure *structure = NULL;
4973         const gchar *string_format = NULL;
4974         unsigned int fourcc = 0;
4975
4976         MMPLAYER_FENTER();
4977         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4978
4979         if (player->video_stream_prerolled) {
4980                 player->video_stream_prerolled = FALSE;
4981                 LOGD("skip the prerolled pkt not to send it again");
4982                 return;
4983         }
4984
4985         caps = gst_pad_get_current_caps(pad);
4986         if (caps == NULL) {
4987                 LOGE("Caps is NULL.");
4988                 return;
4989         }
4990
4991         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4992
4993         /* clear stream data structure */
4994         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4995         if (!stream) {
4996                 LOGE("failed to alloc mem for video data");
4997                 return;
4998         }
4999
5000         structure = gst_caps_get_structure(caps, 0);
5001         gst_structure_get_int(structure, "width", &(stream->width));
5002         gst_structure_get_int(structure, "height", &(stream->height));
5003         string_format = gst_structure_get_string(structure, "format");
5004         if (string_format)
5005                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5006         stream->format = util_get_pixtype(fourcc);
5007         gst_caps_unref(caps);
5008         caps = NULL;
5009
5010     /*
5011         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5012                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5013     */
5014
5015         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5016                 LOGE("Wrong condition!!");
5017                 goto ERROR;
5018         }
5019
5020         /* set size and timestamp */
5021         dataBlock = gst_buffer_peek_memory(buffer, 0);
5022         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5023         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5024
5025         /* check zero-copy */
5026         if (player->set_mode.video_zc &&
5027                 player->set_mode.media_packet_video_stream &&
5028                 gst_buffer_n_memory(buffer) > 1) {
5029                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5030                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5031                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5032         }
5033
5034         if (video_buffer) { /* hw codec */
5035                 /* set tbm bo */
5036                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5037                         int i = 0;
5038
5039                         /* copy pointer of tbm bo, stride, elevation */
5040                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5041                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5042                                 i++;
5043                         }
5044                 } else {
5045                         LOGE("Not support video buffer format");
5046                         goto ERROR;
5047                 }
5048                 memcpy(stream->stride, video_buffer->stride_width,
5049                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5050                 memcpy(stream->elevation, video_buffer->stride_height,
5051                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5052
5053                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5054                 stream->internal_buffer = gst_buffer_ref(buffer);
5055         } else { /* sw codec */
5056                 int i = 0;
5057                 int j = 0;
5058                 int k = 0;
5059                 int ret = TBM_SURFACE_ERROR_NONE;
5060                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5061                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5062                 int size = 0;
5063                 unsigned char *src = NULL;
5064                 unsigned char *dest = NULL;
5065                 tbm_bo_handle thandle;
5066                 tbm_surface_h surface;
5067                 tbm_surface_info_s info;
5068                 gboolean gst_ret;
5069
5070                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5071                 if (!gst_ret) {
5072                         LOGE("fail to gst_memory_map");
5073                         goto ERROR;
5074                 }
5075
5076
5077                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5078                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5079
5080                         ret = tbm_surface_get_info(surface, &info);
5081
5082                         if (ret != TBM_SURFACE_ERROR_NONE) {
5083                                 tbm_surface_destroy(surface);
5084                                 goto ERROR;
5085                         }
5086                         tbm_surface_destroy(surface);
5087
5088                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5089                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5090                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5091                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5092                         stream->stride[0] = info.planes[0].stride;
5093                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5094                         stream->stride[1] = info.planes[1].stride;
5095                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5096                         stream->stride[2] = info.planes[2].stride;
5097                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5098                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5099                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5100                         stream->stride[0] = stream->width * 4;
5101                         stream->elevation[0] = stream->height;
5102                         size = stream->stride[0] * stream->height;
5103                 } else {
5104                         LOGE("Not support format %d", stream->format);
5105                         goto ERROR;
5106                 }
5107
5108                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5109                 if (!stream->bo[0]) {
5110                         LOGE("Fail to tbm_bo_alloc!!");
5111                         goto ERROR;
5112                 }
5113
5114                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5115                 if (thandle.ptr && mapinfo.data) {
5116                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5117                                 for (i = 0; i < 3; i++) {
5118                                         src = mapinfo.data + src_offset[i];
5119                                         dest = thandle.ptr + info.planes[i].offset;
5120
5121                                         if (i > 0) k = 1;
5122                                         for (j = 0; j < stream->height>>k; j++) {
5123                                                 memcpy(dest, src, stream->width>>k);
5124                                                 src += src_stride[i];
5125                                                 dest += stream->stride[i];
5126                                         }
5127                                 }
5128                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5129                                 memcpy(thandle.ptr, mapinfo.data, size);
5130                         } else {
5131                                 LOGE("Not support format %d", stream->format);
5132                                 goto ERROR;
5133                         }
5134                 } else {
5135                         LOGE("data pointer is wrong. dest : %p, src : %p",
5136                                         thandle.ptr, mapinfo.data);
5137                         goto ERROR;
5138                 }
5139                 tbm_bo_unmap(stream->bo[0]);
5140         }
5141
5142         if (player->video_stream_cb) { /* This has been already checked at the entry */
5143                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5144                         LOGE("failed to send video stream data.");
5145                         goto ERROR;
5146                 }
5147         }
5148
5149         if (metaBlock)
5150                 gst_memory_unmap(metaBlock, &mapinfo);
5151         else
5152                 gst_memory_unmap(dataBlock, &mapinfo);
5153
5154         return;
5155
5156 ERROR:
5157         LOGE("release video stream resource.");
5158         if (metaBlock) {
5159                 int i = 0;
5160                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5161                         if (stream->bo[i])
5162                                 tbm_bo_unref(stream->bo[i]);
5163                 }
5164                 gst_memory_unmap(metaBlock, &mapinfo);
5165
5166                 /* unref gst buffer */
5167                 if (stream->internal_buffer)
5168                         gst_buffer_unref(stream->internal_buffer);
5169         } else if (dataBlock) {
5170                 if (stream->bo[0])
5171                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5172                 gst_memory_unmap(dataBlock, &mapinfo);
5173         }
5174
5175         g_free(stream);
5176         return;
5177 }
5178
5179 static int
5180 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5181 {
5182         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5183         GList* element_bucket = NULL;
5184
5185         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186
5187         MMPLAYER_FENTER();
5188
5189         if (player->set_mode.video_zc || player->is_content_spherical) {
5190                 LOGD("do not need to add video filters.");
5191                 return MM_ERROR_NONE;
5192         }
5193
5194         /* in case of sw codec except 360 playback,
5195          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5196         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5197         LOGD("using video converter: %s", video_csc);
5198
5199         /* set video rotator */
5200         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5201
5202         *bucket = element_bucket;
5203         MMPLAYER_FLEAVE();
5204         return MM_ERROR_NONE;
5205
5206 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5207         g_list_free(element_bucket);
5208
5209         *bucket = NULL;
5210         MMPLAYER_FLEAVE();
5211         return MM_ERROR_PLAYER_INTERNAL;
5212 }
5213
5214 /**
5215  * This function is to create video pipeline.
5216  *
5217  * @param       player          [in]    handle of player
5218  *              caps            [in]    src caps of decoder
5219  *              surface_type    [in]    surface type for video rendering
5220  *
5221  * @return      This function returns zero on success.
5222  * @remark
5223  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5224  */
5225 /**
5226   * VIDEO PIPELINE
5227   * - video overlay surface(arm/x86) : tizenwlsink
5228   */
5229 static int
5230 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5231 {
5232         GstPad *pad = NULL;
5233         MMHandleType attrs;
5234         GList*element_bucket = NULL;
5235         MMPlayerGstElement* first_element = NULL;
5236         MMPlayerGstElement* videobin = NULL;
5237         gchar *videosink_element = NULL;
5238
5239         MMPLAYER_FENTER();
5240
5241         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5242
5243         /* alloc handles */
5244         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5245         if (!videobin)
5246                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5247
5248         player->pipeline->videobin = videobin;
5249
5250         attrs = MMPLAYER_GET_ATTRS(player);
5251         if (!attrs) {
5252                 LOGE("cannot get content attribute");
5253                 return MM_ERROR_PLAYER_INTERNAL;
5254         }
5255
5256         /* create bin */
5257         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5258         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5259         if (!videobin[MMPLAYER_V_BIN].gst) {
5260                 LOGE("failed to create videobin");
5261                 goto ERROR;
5262         }
5263
5264         int enable_video_decoded_cb = 0;
5265         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5266
5267         if (player->is_content_spherical) {
5268                 LOGD("video360 elem will be added.");
5269
5270                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5271                                 "video-360", TRUE, player);
5272
5273                 /* Set spatial media metadata and/or user settings to the element.
5274                  * */
5275                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5276                                 "projection-type", player->video360_metadata.projection_type, NULL);
5277
5278                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5279                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5280
5281                 if (player->video360_metadata.full_pano_width_pixels &&
5282                                 player->video360_metadata.full_pano_height_pixels &&
5283                                 player->video360_metadata.cropped_area_image_width &&
5284                                 player->video360_metadata.cropped_area_image_height) {
5285                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5286                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5287                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5288                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5289                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5290                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5291                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5292                                         NULL);
5293                 }
5294
5295                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5296                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5297                                         "horizontal-fov", player->video360_horizontal_fov,
5298                                         "vertical-fov", player->video360_vertical_fov, NULL);
5299                 }
5300
5301                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5302                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5303                                         "zoom", 1.0f / player->video360_zoom, NULL);
5304                 }
5305
5306                 if (player->video360_yaw_radians <= M_PI &&
5307                                 player->video360_yaw_radians >= -M_PI &&
5308                                 player->video360_pitch_radians <= M_PI_2 &&
5309                                 player->video360_pitch_radians >= -M_PI_2) {
5310                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5311                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5312                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5313                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5314                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5315                                         "pose-yaw", player->video360_metadata.init_view_heading,
5316                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5317                 }
5318
5319                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5320                                 "passthrough", !player->is_video360_enabled, NULL);
5321         }
5322
5323         /* set video sink */
5324         switch (surface_type) {
5325         case MM_DISPLAY_SURFACE_OVERLAY:
5326                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5327                         goto ERROR;
5328                 if (strlen(player->ini.videosink_element_overlay) > 0)
5329                         videosink_element = player->ini.videosink_element_overlay;
5330                 else
5331                         goto ERROR;
5332                 break;
5333         case MM_DISPLAY_SURFACE_NULL:
5334                 if (strlen(player->ini.videosink_element_fake) > 0)
5335                         videosink_element = player->ini.videosink_element_fake;
5336                 else
5337                         goto ERROR;
5338                 break;
5339         case MM_DISPLAY_SURFACE_REMOTE:
5340                 if (strlen(player->ini.videosink_element_fake) > 0)
5341                         videosink_element = player->ini.videosink_element_fake;
5342                 else
5343                         goto ERROR;
5344                 break;
5345         default:
5346                 LOGE("unidentified surface type");
5347                 goto ERROR;
5348         }
5349         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5350
5351         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5352
5353         /* additional setting for sink plug-in */
5354         switch (surface_type) {
5355         case MM_DISPLAY_SURFACE_OVERLAY:
5356         {
5357                 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5358                 if (!use_tbm) {
5359                         LOGD("selected videosink name: %s", videosink_element);
5360
5361                         /* support shard memory with S/W codec on HawkP */
5362                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5363                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5364                                         "use-tbm", use_tbm, NULL);
5365                         }
5366                 } else {
5367                         if (attrs) {
5368                                 int gapless = 0;
5369
5370                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5371
5372                                 if (gapless > 0) {
5373                                         LOGD("disable last-sample");
5374                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5375                                 }
5376                         }
5377                 }
5378                 if (player->set_mode.media_packet_video_stream) {
5379                         int enable = 0;
5380                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5381                         if (enable)
5382                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5383
5384                         MMPLAYER_SIGNAL_CONNECT(player,
5385                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5386                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5387                                                                         "handoff",
5388                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5389                                                                         (gpointer)player);
5390
5391                         MMPLAYER_SIGNAL_CONNECT(player,
5392                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5394                                                                         "preroll-handoff",
5395                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5396                                                                         (gpointer)player);
5397                 }
5398                 break;
5399         }
5400         case MM_DISPLAY_SURFACE_REMOTE:
5401         {
5402                 if (player->set_mode.media_packet_video_stream) {
5403                         LOGE("add data probe at videosink");
5404                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5405                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5406
5407                         MMPLAYER_SIGNAL_CONNECT(player,
5408                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5409                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5410                                                                         "handoff",
5411                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5412                                                                         (gpointer)player);
5413
5414                         MMPLAYER_SIGNAL_CONNECT(player,
5415                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5416                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5417                                                                         "preroll-handoff",
5418                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5419                                                                         (gpointer)player);
5420                         if (attrs) {
5421                                 int gapless = 0;
5422
5423                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5424
5425                                 if (gapless > 0) {
5426                                         LOGD("disable last-sample");
5427                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5428                                 }
5429                         }
5430                 }
5431                 break;
5432         }
5433         default:
5434                 break;
5435         }
5436
5437         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5438                 goto ERROR;
5439
5440         if (videobin[MMPLAYER_V_SINK].gst) {
5441                 GstPad *sink_pad = NULL;
5442                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5443                 if (sink_pad) {
5444                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5445                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5446                         gst_object_unref(GST_OBJECT(sink_pad));
5447                 } else
5448                         LOGW("failed to get sink pad from videosink\n");
5449         }
5450
5451         /* store it as it's sink element */
5452         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5453
5454         /* adding created elements to bin */
5455         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5456                 LOGE("failed to add elements\n");
5457                 goto ERROR;
5458         }
5459
5460         /* Linking elements in the bucket by added order */
5461         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5462                 LOGE("failed to link elements\n");
5463                 goto ERROR;
5464         }
5465
5466         /* get first element's sinkpad for creating ghostpad */
5467         if (element_bucket)
5468                 first_element = (MMPlayerGstElement *)element_bucket->data;
5469         if (!first_element) {
5470                 LOGE("failed to get first element from bucket\n");
5471                 goto ERROR;
5472         }
5473
5474         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5475         if (!pad) {
5476                 LOGE("failed to get pad from first element\n");
5477                 goto ERROR;
5478         }
5479
5480         /* create ghostpad */
5481         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5482         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5483                 LOGE("failed to add ghostpad to videobin\n");
5484                 goto ERROR;
5485         }
5486         gst_object_unref(pad);
5487
5488         /* done. free allocated variables */
5489         if (element_bucket)
5490                 g_list_free(element_bucket);
5491
5492         MMPLAYER_FLEAVE();
5493
5494         return MM_ERROR_NONE;
5495
5496 ERROR:
5497         LOGE("ERROR : releasing videobin\n");
5498
5499         g_list_free(element_bucket);
5500
5501         if (pad)
5502                 gst_object_unref(GST_OBJECT(pad));
5503
5504         /* release videobin with it's childs */
5505         if (videobin[MMPLAYER_V_BIN].gst)
5506                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5507
5508
5509         MMPLAYER_FREEIF(videobin);
5510
5511         player->pipeline->videobin = NULL;
5512
5513         return MM_ERROR_PLAYER_INTERNAL;
5514 }
5515
5516 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5517 {
5518         GList *element_bucket = NULL;
5519         MMPlayerGstElement *textbin = player->pipeline->textbin;
5520
5521         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5522         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5523         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5524                                                         "signal-handoffs", FALSE,
5525                                                         NULL);
5526
5527         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5528         MMPLAYER_SIGNAL_CONNECT(player,
5529                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5530                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5531                                                         "handoff",
5532                                                         G_CALLBACK(__mmplayer_update_subtitle),
5533                                                         (gpointer)player);
5534
5535         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5536         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5537         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5538
5539         if (!player->play_subtitle) {
5540                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5541                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5542         }
5543
5544         /* adding created elements to bin */
5545         LOGD("adding created elements to bin\n");
5546         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5547                 LOGE("failed to add elements\n");
5548                 goto ERROR;
5549         }
5550
5551         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5552         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5553         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5554
5555         /* linking elements in the bucket by added order. */
5556         LOGD("Linking elements in the bucket by added order.\n");
5557         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5558                 LOGE("failed to link elements\n");
5559                 goto ERROR;
5560         }
5561
5562         /* done. free allocated variables */
5563         g_list_free(element_bucket);
5564
5565         if (textbin[MMPLAYER_T_QUEUE].gst) {
5566                 GstPad *pad = NULL;
5567                 GstPad *ghostpad = NULL;
5568
5569                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5570                 if (!pad) {
5571                         LOGE("failed to get sink pad of text queue");
5572                         goto ERROR;
5573                 }
5574
5575                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5576                 gst_object_unref(pad);
5577
5578                 if (!ghostpad) {
5579                         LOGE("failed to create ghostpad of textbin\n");
5580                         goto ERROR;
5581                 }
5582
5583                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5584                         LOGE("failed to add ghostpad to textbin\n");
5585                         gst_object_unref(ghostpad);
5586                         goto ERROR;
5587                 }
5588         }
5589
5590         return MM_ERROR_NONE;
5591
5592 ERROR:
5593         g_list_free(element_bucket);
5594
5595         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5596                 LOGE("remove textbin sink from sink list");
5597                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5598         }
5599
5600         /* release element at __mmplayer_gst_create_text_sink_bin */
5601         return MM_ERROR_PLAYER_INTERNAL;
5602 }
5603
5604 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5605 {
5606         MMPlayerGstElement *textbin = NULL;
5607         GList *element_bucket = NULL;
5608         int surface_type = 0;
5609         gint i = 0;
5610
5611         MMPLAYER_FENTER();
5612
5613         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5614
5615         /* alloc handles */
5616         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5617         if (!textbin) {
5618                 LOGE("failed to allocate memory for textbin\n");
5619                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5620         }
5621
5622         /* create bin */
5623         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5624         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5625         if (!textbin[MMPLAYER_T_BIN].gst) {
5626                 LOGE("failed to create textbin\n");
5627                 goto ERROR;
5628         }
5629
5630         /* take it */
5631         player->pipeline->textbin = textbin;
5632
5633         /* fakesink */
5634         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5635         LOGD("surface type for subtitle : %d", surface_type);
5636         switch (surface_type) {
5637         case MM_DISPLAY_SURFACE_OVERLAY:
5638         case MM_DISPLAY_SURFACE_NULL:
5639         case MM_DISPLAY_SURFACE_REMOTE:
5640                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5641                         LOGE("failed to make plain text elements\n");
5642                         goto ERROR;
5643                 }
5644                 break;
5645         default:
5646                 goto ERROR;
5647                 break;
5648         }
5649
5650         MMPLAYER_FLEAVE();
5651
5652         return MM_ERROR_NONE;
5653
5654 ERROR:
5655
5656         LOGD("ERROR : releasing textbin\n");
5657
5658         g_list_free(element_bucket);
5659
5660         /* release signal */
5661         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5662
5663         /* release element which are not added to bin */
5664         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5665                 /* NOTE : skip bin */
5666                 if (textbin[i].gst) {
5667                         GstObject* parent = NULL;
5668                         parent = gst_element_get_parent(textbin[i].gst);
5669
5670                         if (!parent) {
5671                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5672                                 textbin[i].gst = NULL;
5673                         } else {
5674                                 gst_object_unref(GST_OBJECT(parent));
5675                         }
5676                 }
5677         }
5678
5679         /* release textbin with it's childs */
5680         if (textbin[MMPLAYER_T_BIN].gst)
5681                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5682
5683         MMPLAYER_FREEIF(player->pipeline->textbin);
5684         player->pipeline->textbin = NULL;
5685
5686         MMPLAYER_FLEAVE();
5687         return MM_ERROR_PLAYER_INTERNAL;
5688 }
5689
5690
5691 static int
5692 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5693 {
5694         MMPlayerGstElement* mainbin = NULL;
5695         MMPlayerGstElement* textbin = NULL;
5696         MMHandleType attrs = 0;
5697         GstElement *subsrc = NULL;
5698         GstElement *subparse = NULL;
5699         gchar *subtitle_uri = NULL;
5700         const gchar *charset = NULL;
5701         GstPad *pad = NULL;
5702
5703         MMPLAYER_FENTER();
5704
5705         /* get mainbin */
5706         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5707                                                                 player->pipeline &&
5708                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5709
5710         mainbin = player->pipeline->mainbin;
5711
5712         attrs = MMPLAYER_GET_ATTRS(player);
5713         if (!attrs) {
5714                 LOGE("cannot get content attribute\n");
5715                 return MM_ERROR_PLAYER_INTERNAL;
5716         }
5717
5718         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5719         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5720                 LOGE("subtitle uri is not proper filepath.\n");
5721                 return MM_ERROR_PLAYER_INVALID_URI;
5722         }
5723
5724         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5725                 LOGE("failed to get storage info of subtitle path");
5726                 return MM_ERROR_PLAYER_INVALID_URI;
5727         }
5728
5729         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5730
5731         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5732         player->subtitle_language_list = NULL;
5733         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5734
5735         /* create the subtitle source */
5736         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5737         if (!subsrc) {
5738                 LOGE("failed to create filesrc element\n");
5739                 goto ERROR;
5740         }
5741         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5742
5743         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5744         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5745
5746         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5747                 LOGW("failed to add queue\n");
5748                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5749                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5750                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5751                 goto ERROR;
5752         }
5753
5754         /* subparse */
5755         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5756         if (!subparse) {
5757                 LOGE("failed to create subparse element\n");
5758                 goto ERROR;
5759         }
5760
5761         charset = util_get_charset(subtitle_uri);
5762         if (charset) {
5763                 LOGD("detected charset is %s\n", charset);
5764                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5765         }
5766
5767         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5768         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5769
5770         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5771                 LOGW("failed to add subparse\n");
5772                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5773                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5774                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5775                 goto ERROR;
5776         }
5777
5778         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5779                 LOGW("failed to link subsrc and subparse\n");
5780                 goto ERROR;
5781         }
5782
5783         player->play_subtitle = TRUE;
5784         player->adjust_subtitle_pos = 0;
5785
5786         LOGD("play subtitle using subtitle file\n");
5787
5788         if (player->pipeline->textbin == NULL) {
5789                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5790                         LOGE("failed to create text sink bin. continuing without text\n");
5791                         goto ERROR;
5792                 }
5793
5794                 textbin = player->pipeline->textbin;
5795
5796                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5797                         LOGW("failed to add textbin\n");
5798
5799                         /* release signal */
5800                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5801
5802                         /* release textbin with it's childs */
5803                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5804                         MMPLAYER_FREEIF(player->pipeline->textbin);
5805                         player->pipeline->textbin = textbin = NULL;
5806                         goto ERROR;
5807                 }
5808
5809                 LOGD("link text input selector and textbin ghost pad");
5810
5811                 player->textsink_linked = 1;
5812                 player->external_text_idx = 0;
5813                 LOGI("player->textsink_linked set to 1\n");
5814         } else {
5815                 textbin = player->pipeline->textbin;
5816                 LOGD("text bin has been created. reuse it.");
5817                 player->external_text_idx = 1;
5818         }
5819
5820         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5821                 LOGW("failed to link subparse and textbin\n");
5822                 goto ERROR;
5823         }
5824
5825         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5826         if (!pad) {
5827                 LOGE("failed to get sink pad from textsink to probe data");
5828                 goto ERROR;
5829         }
5830
5831         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5832                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5833
5834         gst_object_unref(pad);
5835         pad = NULL;
5836
5837         /* create dot. for debugging */
5838         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5839         MMPLAYER_FLEAVE();
5840
5841         return MM_ERROR_NONE;
5842
5843 ERROR:
5844         /* release text pipeline resource */
5845         player->textsink_linked = 0;
5846
5847         /* release signal */
5848         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5849
5850         if (player->pipeline->textbin) {
5851                 LOGE("remove textbin");
5852
5853                 /* release textbin with it's childs */
5854                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5855                 MMPLAYER_FREEIF(player->pipeline->textbin);
5856                 player->pipeline->textbin = NULL;
5857
5858         }
5859
5860         /* release subtitle elem */
5861         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5862         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5863
5864         return MM_ERROR_PLAYER_INTERNAL;
5865 }
5866
5867 gboolean
5868 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5869 {
5870         mm_player_t* player = (mm_player_t*) data;
5871         MMMessageParamType msg = {0, };
5872         GstClockTime duration = 0;
5873         gpointer text = NULL;
5874         guint text_size = 0;
5875         gboolean ret = TRUE;
5876         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5877
5878         MMPLAYER_FENTER();
5879
5880         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5881         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5882
5883         if (player->is_subtitle_force_drop) {
5884                 LOGW("subtitle is dropped forcedly.");
5885                 return ret;
5886         }
5887
5888         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5889         text = mapinfo.data;
5890         text_size = mapinfo.size;
5891         duration = GST_BUFFER_DURATION(buffer);
5892
5893         if (player->set_mode.subtitle_off) {
5894                 LOGD("subtitle is OFF.\n");
5895                 return TRUE;
5896         }
5897
5898         if (!text || (text_size == 0)) {
5899                 LOGD("There is no subtitle to be displayed.\n");
5900                 return TRUE;
5901         }
5902
5903         msg.data = (void *) text;
5904         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5905
5906         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5907
5908         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5909         gst_buffer_unmap(buffer, &mapinfo);
5910
5911         MMPLAYER_FLEAVE();
5912
5913         return ret;
5914 }
5915
5916 static GstPadProbeReturn
5917 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5918 {
5919         mm_player_t *player = (mm_player_t *) u_data;
5920         GstClockTime cur_timestamp = 0;
5921         gint64 adjusted_timestamp = 0;
5922         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5923
5924         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5925
5926         if (player->set_mode.subtitle_off) {
5927                 LOGD("subtitle is OFF.\n");
5928                 return TRUE;
5929         }
5930
5931         if (player->adjust_subtitle_pos == 0) {
5932                 LOGD("nothing to do");
5933                 return TRUE;
5934         }
5935
5936         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5937         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5938
5939         if (adjusted_timestamp < 0) {
5940                 LOGD("adjusted_timestamp under zero");
5941                 MMPLAYER_FLEAVE();
5942                 return FALSE;
5943         }
5944
5945         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5946         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5947                                 GST_TIME_ARGS(cur_timestamp),
5948                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5949
5950         return GST_PAD_PROBE_OK;
5951 }
5952 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5953 {
5954         MMPLAYER_FENTER();
5955
5956         /* check player and subtitlebin are created */
5957         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5958         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5959
5960         if (position == 0) {
5961                 LOGD("nothing to do\n");
5962                 MMPLAYER_FLEAVE();
5963                 return MM_ERROR_NONE;
5964         }
5965
5966         switch (format) {
5967         case MM_PLAYER_POS_FORMAT_TIME:
5968                 {
5969                         /* check current postion */
5970                         player->adjust_subtitle_pos = position;
5971
5972                         LOGD("save adjust_subtitle_pos in player") ;
5973                 }
5974                 break;
5975
5976         default:
5977                 {
5978                         LOGW("invalid format.\n");
5979                         MMPLAYER_FLEAVE();
5980                         return MM_ERROR_INVALID_ARGUMENT;
5981                 }
5982         }
5983
5984         MMPLAYER_FLEAVE();
5985
5986         return MM_ERROR_NONE;
5987 }
5988 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5989 {
5990         MMPLAYER_FENTER();
5991         LOGD("adjusting video_pos in player") ;
5992         int current_pos = 0;
5993         /* check player and videobin are created */
5994         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5995         if (!player->pipeline->videobin ||
5996                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5997                 LOGD("no video pipeline or sink is there");
5998                 return MM_ERROR_PLAYER_INVALID_STATE ;
5999         }
6000         if (offset == 0) {
6001                 LOGD("nothing to do\n");
6002                 MMPLAYER_FLEAVE();
6003                 return MM_ERROR_NONE;
6004         }
6005         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6006                 LOGD("failed to get current position");
6007                 return MM_ERROR_PLAYER_INTERNAL;
6008         }
6009         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6010                 LOGD("enter video delay is valid");
6011         } else {
6012                 LOGD("enter video delay is crossing content boundary");
6013                 return MM_ERROR_INVALID_ARGUMENT ;
6014         }
6015         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6016         LOGD("video delay has been done");
6017         MMPLAYER_FLEAVE();
6018
6019         return MM_ERROR_NONE;
6020 }
6021
6022 static void
6023 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6024 {
6025         GstElement *appsrc = element;
6026         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6027         GstBuffer *buffer = NULL;
6028         GstFlowReturn ret = GST_FLOW_OK;
6029         gint len = size;
6030
6031         MMPLAYER_RETURN_IF_FAIL(element);
6032         MMPLAYER_RETURN_IF_FAIL(buf);
6033
6034         buffer = gst_buffer_new();
6035
6036         if (buf->offset >= buf->len) {
6037                 LOGD("call eos appsrc\n");
6038                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6039                 return;
6040         }
6041
6042         if (buf->len - buf->offset < size)
6043                 len = buf->len - buf->offset;
6044
6045         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6046         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6047         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6048
6049         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6050         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6051
6052         buf->offset += len;
6053 }
6054
6055 static gboolean
6056 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6057 {
6058         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6059
6060         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6061
6062         buf->offset  = (int)size;
6063
6064         return TRUE;
6065 }
6066
6067 static GstBusSyncReply
6068 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6069 {
6070         mm_player_t *player = (mm_player_t *)data;
6071         GstBusSyncReply reply = GST_BUS_DROP;
6072
6073         if (!(player->pipeline && player->pipeline->mainbin)) {
6074                 LOGE("player pipeline handle is null");
6075                 return GST_BUS_PASS;
6076         }
6077
6078         if (!__mmplayer_check_useful_message(player, message)) {
6079                 gst_message_unref(message);
6080                 return GST_BUS_DROP;
6081         }
6082
6083         switch (GST_MESSAGE_TYPE(message)) {
6084         case GST_MESSAGE_STATE_CHANGED:
6085                 /* post directly for fast launch */
6086                 if (player->sync_handler) {
6087                         __mmplayer_gst_callback(message, player);
6088                         reply = GST_BUS_DROP;
6089                 } else
6090                         reply = GST_BUS_PASS;
6091                 break;
6092         case GST_MESSAGE_TAG:
6093                 __mmplayer_gst_extract_tag_from_msg(player, message);
6094
6095                 #if 0 // debug
6096                 {
6097                         GstTagList *tags = NULL;
6098
6099                         gst_message_parse_tag(message, &tags);
6100                         if (tags) {
6101                                 LOGE("TAGS received from element \"%s\".\n",
6102                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6103
6104                                 gst_tag_list_foreach(tags, print_tag, NULL);
6105                                 gst_tag_list_free(tags);
6106                                 tags = NULL;
6107                         }
6108                         break;
6109                 }
6110                 #endif
6111                 break;
6112
6113         case GST_MESSAGE_DURATION_CHANGED:
6114                 __mmplayer_gst_handle_duration(player, message);
6115                 break;
6116         case GST_MESSAGE_ASYNC_DONE:
6117                 /* NOTE:Don't call gst_callback directly
6118                  * because previous frame can be showed even though this message is received for seek.
6119                  */
6120         default:
6121                 reply = GST_BUS_PASS;
6122                 break;
6123         }
6124
6125         if (reply == GST_BUS_DROP)
6126                 gst_message_unref(message);
6127
6128         return reply;
6129 }
6130
6131 static gboolean
6132 __mmplayer_gst_create_decoder(mm_player_t *player,
6133                                                                 MMPlayerTrackType track,
6134                                                                 GstPad* srcpad,
6135                                                                 enum MainElementID elemId,
6136                                                                 const gchar* name)
6137 {
6138         gboolean ret = TRUE;
6139         GstPad *sinkpad = NULL;
6140
6141         MMPLAYER_FENTER();
6142
6143         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6144                                                 player->pipeline &&
6145                                                 player->pipeline->mainbin, FALSE);
6146         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6147         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6148         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6149
6150         GstElement *decodebin = NULL;
6151         GstCaps *dec_caps = NULL;
6152
6153         /* create decodebin */
6154         decodebin = gst_element_factory_make("decodebin", name);
6155
6156         if (!decodebin) {
6157                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6158                 ret = FALSE;
6159                 goto ERROR;
6160         }
6161
6162         /* raw pad handling signal */
6163         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6164                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6165
6166         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6167         before looking for any elements that can handle that stream.*/
6168         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6169                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6170
6171         /* This signal is emitted when a element is added to the bin.*/
6172         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6173                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6174
6175         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6176                 LOGE("failed to add new decodebin\n");
6177                 ret = FALSE;
6178                 goto ERROR;
6179         }
6180
6181         dec_caps = gst_pad_query_caps(srcpad, NULL);
6182         if (dec_caps) {
6183                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6184                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6185                 gst_caps_unref(dec_caps);
6186         }
6187
6188         player->pipeline->mainbin[elemId].id = elemId;
6189         player->pipeline->mainbin[elemId].gst = decodebin;
6190
6191         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6192
6193         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6194                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6195                 gst_object_unref(GST_OBJECT(decodebin));
6196         }
6197
6198         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6199                 LOGE("failed to sync second level decodebin state with parent\n");
6200
6201         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6202
6203 ERROR:
6204         if (sinkpad) {
6205                 gst_object_unref(GST_OBJECT(sinkpad));
6206                 sinkpad = NULL;
6207         }
6208         MMPLAYER_FLEAVE();
6209
6210         return ret;
6211 }
6212
6213 /**
6214  * This function is to create  audio or video pipeline for playing.
6215  *
6216  * @param       player          [in]    handle of player
6217  *
6218  * @return      This function returns zero on success.
6219  * @remark
6220  * @see
6221  */
6222 static int
6223 __mmplayer_gst_create_pipeline(mm_player_t* player)
6224 {
6225         GstBus  *bus = NULL;
6226         MMPlayerGstElement *mainbin = NULL;
6227         MMHandleType attrs = 0;
6228         GstElement* element = NULL;
6229         GstElement* elem_src_audio = NULL;
6230         GstElement* elem_src_subtitle = NULL;
6231         GstElement* es_video_queue = NULL;
6232         GstElement* es_audio_queue = NULL;
6233         GstElement* es_subtitle_queue = NULL;
6234         GList* element_bucket = NULL;
6235         gboolean need_state_holder = TRUE;
6236         gint i = 0;
6237 #ifdef SW_CODEC_ONLY
6238         int surface_type = 0;
6239 #endif
6240         MMPLAYER_FENTER();
6241
6242         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6243
6244         /* get profile attribute */
6245         attrs = MMPLAYER_GET_ATTRS(player);
6246         if (!attrs) {
6247                 LOGE("cannot get content attribute\n");
6248                 goto INIT_ERROR;
6249         }
6250
6251         /* create pipeline handles */
6252         if (player->pipeline) {
6253                 LOGW("pipeline should be released before create new one\n");
6254                 goto INIT_ERROR;
6255         }
6256
6257         player->video360_metadata.is_spherical = -1;
6258         player->is_openal_plugin_used = FALSE;
6259
6260         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6261         if (player->pipeline == NULL)
6262                 goto INIT_ERROR;
6263
6264         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6265
6266         /* create mainbin */
6267         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6268         if (mainbin == NULL)
6269                 goto INIT_ERROR;
6270
6271         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6272
6273         /* create pipeline */
6274         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6275         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6276         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6277                 LOGE("failed to create pipeline\n");
6278                 goto INIT_ERROR;
6279         }
6280         player->demux_pad_index = 0;
6281         player->subtitle_language_list = NULL;
6282
6283         player->is_subtitle_force_drop = FALSE;
6284         player->last_multiwin_status = FALSE;
6285
6286         _mmplayer_track_initialize(player);
6287         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6288
6289         /* create source element */
6290         switch (player->profile.uri_type) {
6291         /* rtsp streamming */
6292         case MM_PLAYER_URI_TYPE_URL_RTSP:
6293                 {
6294                         gchar *user_agent;
6295
6296                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6297
6298                         if (!element) {
6299                                 LOGE("failed to create streaming source element\n");
6300                                 break;
6301                         }
6302
6303                         /* make it zero */
6304                         user_agent = NULL;
6305
6306                         /* get attribute */
6307                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6308
6309                         SECURE_LOGD("user_agent : %s\n", user_agent);
6310
6311                         /* setting property to streaming source */
6312                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6313                         if (user_agent)
6314                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6315
6316                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6317                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6318                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6319                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6320                 }
6321                 break;
6322
6323         /* http streaming*/
6324         case MM_PLAYER_URI_TYPE_URL_HTTP:
6325                 {
6326                         gchar *user_agent, *cookies, **cookie_list;
6327                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6328                         user_agent = cookies = NULL;
6329                         cookie_list = NULL;
6330                         gint mode = MM_PLAYER_PD_MODE_NONE;
6331
6332                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6333
6334                         player->pd_mode = mode;
6335
6336                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6337
6338                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6339                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6340                                 if (!element) {
6341                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6342                                         break;
6343                                 }
6344                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6345
6346                                 /* get attribute */
6347                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6348                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6349
6350                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6351                                         LOGD("get timeout from ini\n");
6352                                         http_timeout = player->ini.http_timeout;
6353                                 }
6354
6355                                 /* get attribute */
6356                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6357                                 SECURE_LOGD("cookies : %s\n", cookies);
6358                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6359                                 LOGD("timeout : %d\n",  http_timeout);
6360
6361                                 /* setting property to streaming source */
6362                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6363                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6364                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6365
6366                                 /* parsing cookies */
6367                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6368                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6369                                         g_strfreev(cookie_list);
6370                                 }
6371                                 if (user_agent)
6372                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6373
6374                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6375                                         LOGW("it's dash. and it's still experimental feature.");
6376                         } else {
6377                                 // progressive download
6378                                 gchar* location = NULL;
6379
6380                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6381                                         gchar *path = NULL;
6382
6383                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6384
6385                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6386
6387                                         LOGD("PD Location : %s\n", path);
6388
6389                                         if (path) {
6390                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6391                                                         LOGE("failed to get storage info");
6392                                                         break;
6393                                                 }
6394                                                 player->pd_file_save_path = g_strdup(path);
6395                                         } else {
6396                                                 LOGE("can't find pd location so, it should be set \n");
6397                                                 break;
6398                                         }
6399                                 }
6400
6401                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6402                                 if (!element) {
6403                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6404                                         break;
6405                                 }
6406
6407                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6408                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6409                                 else
6410                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6411                                 g_object_get(element, "location", &location, NULL);
6412                                 LOGD("PD_LOCATION [%s].\n", location);
6413                                 if (location)
6414                                         g_free(location);
6415                         }
6416                 }
6417                 break;
6418
6419         /* file source */
6420         case MM_PLAYER_URI_TYPE_FILE:
6421                 {
6422                         LOGD("using filesrc for 'file://' handler.\n");
6423                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6424                                 LOGE("failed to get storage info");
6425                                 break;
6426                         }
6427
6428                         element = gst_element_factory_make("filesrc", "source");
6429                         if (!element) {
6430                                 LOGE("failed to create filesrc\n");
6431                                 break;
6432                         }
6433
6434                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6435                 }
6436                 break;
6437
6438         case MM_PLAYER_URI_TYPE_SS:
6439                 {
6440                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6441                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6442                         if (!element) {
6443                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6444                                 break;
6445                         }
6446
6447                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6448                                 LOGD("get timeout from ini\n");
6449                                 http_timeout = player->ini.http_timeout;
6450                         }
6451
6452                         /* setting property to streaming source */
6453                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6454                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6455                 }
6456                 break;
6457         case MM_PLAYER_URI_TYPE_MS_BUFF:
6458                 {
6459                         LOGD("MS buff src is selected\n");
6460
6461                         if (player->v_stream_caps) {
6462                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6463                                 if (!element) {
6464                                         LOGF("failed to create video app source element[appsrc].\n");
6465                                         break;
6466                                 }
6467
6468                                 if (player->a_stream_caps) {
6469                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6470                                         if (!elem_src_audio) {
6471                                                 LOGF("failed to create audio app source element[appsrc].\n");
6472                                                 break;
6473                                         }
6474                                 }
6475                         } else if (player->a_stream_caps) {
6476                                 /* no video, only audio pipeline*/
6477                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6478                                 if (!element) {
6479                                         LOGF("failed to create audio app source element[appsrc].\n");
6480                                         break;
6481                                 }
6482                         }
6483
6484                         if (player->s_stream_caps) {
6485                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6486                                 if (!elem_src_subtitle) {
6487                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6488                                         break;
6489                                 }
6490                         }
6491
6492                         LOGD("setting app sources properties.\n");
6493                         LOGD("location : %s\n", player->profile.uri);
6494
6495                         if (player->v_stream_caps && element) {
6496                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6497                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6498                                                                                                 "caps", player->v_stream_caps, NULL);
6499
6500                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6501                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6502                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6503                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6504
6505                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6506                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6507                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6508                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6509
6510                                 if (player->a_stream_caps && elem_src_audio) {
6511                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6512                                                                                                                         "caps", player->a_stream_caps, NULL);
6513
6514                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6515                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6516                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6517                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6518
6519                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6520                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6521                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6522                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6523                                 }
6524                         } else if (player->a_stream_caps && element) {
6525                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6526                                                                                                 "caps", player->a_stream_caps, NULL);
6527
6528                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6529                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6530                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6531                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6532
6533                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6534                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6535                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6536                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6537                         }
6538
6539                         if (player->s_stream_caps && elem_src_subtitle) {
6540                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6541                                                                                                                  "caps", player->s_stream_caps, NULL);
6542
6543                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6544                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6545                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6546                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6547
6548                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6549
6550                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6551                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6552                         }
6553
6554                         if (player->v_stream_caps && element) {
6555                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6556                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6557                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6558                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6559
6560                                 if (player->a_stream_caps && elem_src_audio) {
6561                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6562                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6563                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6564                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6565                                 }
6566                         } else if (player->a_stream_caps && element) {
6567                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6568                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6569                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6570                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6571                         }
6572
6573                         if (player->s_stream_caps && elem_src_subtitle)
6574                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6575                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6576
6577                         need_state_holder = FALSE;
6578
6579                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6580                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6581                                 LOGE("failed to commit\n");
6582                 }
6583                 break;
6584         /* appsrc */
6585         case MM_PLAYER_URI_TYPE_MEM:
6586                 {
6587                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6588
6589                         LOGD("mem src is selected\n");
6590
6591                         element = gst_element_factory_make("appsrc", "mem-source");
6592                         if (!element) {
6593                                 LOGE("failed to create appsrc element\n");
6594                                 break;
6595                         }
6596
6597                         g_object_set(element, "stream-type", stream_type, NULL);
6598                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6599                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6600
6601                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6602                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6603                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6605                 }
6606                 break;
6607         case MM_PLAYER_URI_TYPE_URL:
6608                 break;
6609
6610         case MM_PLAYER_URI_TYPE_TEMP:
6611                 break;
6612
6613         case MM_PLAYER_URI_TYPE_NONE:
6614         default:
6615                 break;
6616         }
6617
6618         /* check source element is OK */
6619         if (!element) {
6620                 LOGE("no source element was created.\n");
6621                 goto INIT_ERROR;
6622         }
6623
6624         /* take source element */
6625         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6626         mainbin[MMPLAYER_M_SRC].gst = element;
6627         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6628
6629         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6630                 player->streamer = __mm_player_streaming_create();
6631                 __mm_player_streaming_initialize(player->streamer);
6632         }
6633
6634         if (MMPLAYER_IS_HTTP_PD(player)) {
6635                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6636
6637                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6638                 element = gst_element_factory_make("queue2", "queue2");
6639                 if (!element) {
6640                         LOGE("failed to create http streaming buffer element\n");
6641                         goto INIT_ERROR;
6642                 }
6643
6644                 /* take it */
6645                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6646                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6647                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6648
6649                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6650
6651                 __mm_player_streaming_set_queue2(player->streamer,
6652                                 element,
6653                                 TRUE,
6654                                 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6655                                 pre_buffering_time,
6656                                 1.0,
6657                                 player->ini.http_buffering_limit,
6658                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6659                                 NULL,
6660                                 0);
6661         }
6662         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6663                 if (player->v_stream_caps) {
6664                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6665                         if (!es_video_queue) {
6666                                 LOGE("create es_video_queue for es player failed\n");
6667                                 goto INIT_ERROR;
6668                         }
6669                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6670                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6671                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6672                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6673
6674                         /* Adding audio appsrc to bucket */
6675                         if (player->a_stream_caps && elem_src_audio) {
6676                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6677                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6678                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6679
6680                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6681                                 if (!es_audio_queue) {
6682                                         LOGE("create es_audio_queue for es player failed\n");
6683                                         goto INIT_ERROR;
6684                                 }
6685                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6686
6687                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6688                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6689                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6690                         }
6691                 } else if (player->a_stream_caps) {
6692                         /* Only audio stream, no video */
6693                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6694                         if (!es_audio_queue) {
6695                                 LOGE("create es_audio_queue for es player failed\n");
6696                                 goto INIT_ERROR;
6697                         }
6698                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6699                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6700                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6701                 }
6702
6703                 if (player->s_stream_caps && elem_src_subtitle) {
6704                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6705                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6706                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6707
6708                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6709                         if (!es_subtitle_queue) {
6710                                 LOGE("create es_subtitle_queue for es player failed\n");
6711                                 goto INIT_ERROR;
6712                         }
6713                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6714                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6715                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6716                 }
6717         }
6718
6719         /* create autoplugging element if src element is not a rtsp src */
6720         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6721                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6722                 element = NULL;
6723                 enum MainElementID elemId = MMPLAYER_M_NUM;
6724
6725                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6726                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6727                         elemId = MMPLAYER_M_AUTOPLUG;
6728                         element = __mmplayer_create_decodebin(player);
6729                         if (element) {
6730                                 /* default size of mq in decodebin is 2M
6731                                  * but it can cause blocking issue during seeking depends on content. */
6732                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6733                         }
6734                         need_state_holder = FALSE;
6735                 } else {
6736                         elemId = MMPLAYER_M_TYPEFIND;
6737                         element = gst_element_factory_make("typefind", "typefinder");
6738                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6739                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6740                 }
6741
6742
6743                 /* check autoplug element is OK */
6744                 if (!element) {
6745                         LOGE("can not create element(%d)\n", elemId);
6746                         goto INIT_ERROR;
6747                 }
6748
6749                 mainbin[elemId].id = elemId;
6750                 mainbin[elemId].gst = element;
6751
6752                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6753         }
6754
6755         /* add elements to pipeline */
6756         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6757                 LOGE("Failed to add elements to pipeline\n");
6758                 goto INIT_ERROR;
6759         }
6760
6761
6762         /* linking elements in the bucket by added order. */
6763         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6764                 LOGE("Failed to link some elements\n");
6765                 goto INIT_ERROR;
6766         }
6767
6768
6769         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6770         if (need_state_holder) {
6771                 /* create */
6772                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6773                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6774
6775                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6776                         LOGE("fakesink element could not be created\n");
6777                         goto INIT_ERROR;
6778                 }
6779                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6780
6781                 /* take ownership of fakesink. we are reusing it */
6782                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6783
6784                 /* add */
6785                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6786                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6787                         LOGE("failed to add fakesink to bin\n");
6788                         goto INIT_ERROR;
6789                 }
6790         }
6791
6792         /* now we have completed mainbin. take it */
6793         player->pipeline->mainbin = mainbin;
6794
6795         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6796                 GstPad *srcpad = NULL;
6797
6798                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6799                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6800                         if (srcpad) {
6801                                 __mmplayer_gst_create_decoder(player,
6802                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6803                                                                                                 srcpad,
6804                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6805                                                                                                 "video_decodebin");
6806
6807                                 gst_object_unref(GST_OBJECT(srcpad));
6808                                 srcpad = NULL;
6809                         }
6810                 }
6811
6812                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6813                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6814                         if (srcpad) {
6815                                 __mmplayer_gst_create_decoder(player,
6816                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6817                                                                                                 srcpad,
6818                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6819                                                                                                 "audio_decodebin");
6820
6821                                 gst_object_unref(GST_OBJECT(srcpad));
6822                                 srcpad = NULL;
6823                         } // else error
6824                 } //  else error
6825
6826                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6827                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6828         }
6829
6830         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6831         if (__mmplayer_check_subtitle(player)) {
6832                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6833                         LOGE("fail to create text pipeline");
6834         }
6835
6836         /* connect bus callback */
6837         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6838         if (!bus) {
6839                 LOGE("cannot get bus from pipeline.\n");
6840                 goto INIT_ERROR;
6841         }
6842
6843         /* set sync handler to get tag synchronously */
6844         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6845
6846         /* finished */
6847         gst_object_unref(GST_OBJECT(bus));
6848         g_list_free(element_bucket);
6849
6850         /* create gst bus_msb_cb thread */
6851         g_mutex_init(&player->bus_msg_thread_mutex);
6852         g_cond_init(&player->bus_msg_thread_cond);
6853         player->bus_msg_thread_exit = FALSE;
6854         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6855         player->bus_msg_thread =
6856                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6857         if (!player->bus_msg_thread) {
6858                 LOGE("failed to create gst BUS msg thread");
6859                 g_mutex_clear(&player->bus_msg_thread_mutex);
6860                 g_cond_clear(&player->bus_msg_thread_cond);
6861                 goto INIT_ERROR;
6862         }
6863
6864         MMPLAYER_FLEAVE();
6865
6866         return MM_ERROR_NONE;
6867
6868 INIT_ERROR:
6869         __mmplayer_gst_destroy_pipeline(player);
6870         g_list_free(element_bucket);
6871
6872         if (mainbin) {
6873                 /* release element which are not added to bin */
6874                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6875                         /* NOTE : skip pipeline */
6876                         if (mainbin[i].gst) {
6877                                 GstObject* parent = NULL;
6878                                 parent = gst_element_get_parent(mainbin[i].gst);
6879
6880                                 if (!parent) {
6881                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6882                                         mainbin[i].gst = NULL;
6883                                 } else
6884                                         gst_object_unref(GST_OBJECT(parent));
6885                         }
6886                 }
6887
6888                 /* release pipeline with it's childs */
6889                 if (mainbin[MMPLAYER_M_PIPE].gst)
6890                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6891
6892                 MMPLAYER_FREEIF(mainbin);
6893         }
6894
6895         MMPLAYER_FREEIF(player->pipeline);
6896         return MM_ERROR_PLAYER_INTERNAL;
6897 }
6898
6899 static void
6900 __mmplayer_reset_gapless_state(mm_player_t* player)
6901 {
6902         MMPLAYER_FENTER();
6903         MMPLAYER_RETURN_IF_FAIL(player
6904                 && player->pipeline
6905                 && player->pipeline->audiobin
6906                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6907
6908         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6909
6910         MMPLAYER_FLEAVE();
6911         return;
6912 }
6913
6914 static int
6915 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6916 {
6917         gint timeout = 0;
6918         int ret = MM_ERROR_NONE;
6919
6920         MMPLAYER_FENTER();
6921
6922         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6923
6924         /* cleanup stuffs */
6925         MMPLAYER_FREEIF(player->type);
6926         player->have_dynamic_pad = FALSE;
6927         player->no_more_pad = FALSE;
6928         player->num_dynamic_pad = 0;
6929         player->demux_pad_index = 0;
6930         player->use_deinterleave = FALSE;
6931         player->max_audio_channels = 0;
6932         player->video_share_api_delta = 0;
6933         player->video_share_clock_delta = 0;
6934         player->video_hub_download_mode = 0;
6935
6936         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6937         player->subtitle_language_list = NULL;
6938         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6939
6940         __mmplayer_reset_gapless_state(player);
6941
6942         if (player->streamer) {
6943                 __mm_player_streaming_deinitialize(player->streamer);
6944                 __mm_player_streaming_destroy(player->streamer);
6945                 player->streamer = NULL;
6946         }
6947
6948         /* cleanup unlinked mime type */
6949         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6950         MMPLAYER_FREEIF(player->unlinked_video_mime);
6951         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6952
6953         /* cleanup running stuffs */
6954         __mmplayer_cancel_eos_timer(player);
6955
6956         /* cleanup gst stuffs */
6957         if (player->pipeline) {
6958                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6959                 GstTagList* tag_list = player->pipeline->tag_list;
6960
6961                 /* first we need to disconnect all signal hander */
6962                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6963
6964                 if (mainbin) {
6965                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6966                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6967                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6968                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6969                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6970                         gst_object_unref(bus);
6971
6972                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6973                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6974                         if (ret != MM_ERROR_NONE) {
6975                                 LOGE("fail to change state to NULL\n");
6976                                 return MM_ERROR_PLAYER_INTERNAL;
6977                         }
6978
6979                         LOGW("succeeded in chaning state to NULL\n");
6980
6981                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6982
6983                         /* free fakesink */
6984                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6985                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6986
6987                         /* free avsysaudiosink
6988                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6989                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6990                         */
6991                         MMPLAYER_FREEIF(audiobin);
6992                         MMPLAYER_FREEIF(videobin);
6993                         MMPLAYER_FREEIF(textbin);
6994                         MMPLAYER_FREEIF(mainbin);
6995                 }
6996
6997                 if (tag_list)
6998                         gst_tag_list_free(tag_list);
6999
7000                 MMPLAYER_FREEIF(player->pipeline);
7001         }
7002         MMPLAYER_FREEIF(player->album_art);
7003
7004         if (player->v_stream_caps) {
7005                 gst_caps_unref(player->v_stream_caps);
7006                 player->v_stream_caps = NULL;
7007         }
7008         if (player->a_stream_caps) {
7009                 gst_caps_unref(player->a_stream_caps);
7010                 player->a_stream_caps = NULL;
7011         }
7012
7013         if (player->s_stream_caps) {
7014                 gst_caps_unref(player->s_stream_caps);
7015                 player->s_stream_caps = NULL;
7016         }
7017         _mmplayer_track_destroy(player);
7018
7019         if (player->sink_elements)
7020                 g_list_free(player->sink_elements);
7021         player->sink_elements = NULL;
7022
7023         if (player->bufmgr) {
7024                 tbm_bufmgr_deinit(player->bufmgr);
7025                 player->bufmgr = NULL;
7026         }
7027
7028         LOGW("finished destroy pipeline\n");
7029
7030         MMPLAYER_FLEAVE();
7031
7032         return ret;
7033 }
7034
7035 static int __gst_realize(mm_player_t* player)
7036 {
7037         gint timeout = 0;
7038         int ret = MM_ERROR_NONE;
7039
7040         MMPLAYER_FENTER();
7041
7042         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7043
7044         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7045
7046         ret = __mmplayer_gst_create_pipeline(player);
7047         if (ret) {
7048                 LOGE("failed to create pipeline\n");
7049                 return ret;
7050         }
7051
7052         /* set pipeline state to READY */
7053         /* NOTE : state change to READY must be performed sync. */
7054         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7055         ret = __mmplayer_gst_set_state(player,
7056                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7057
7058         if (ret != MM_ERROR_NONE) {
7059                 /* return error if failed to set state */
7060                 LOGE("failed to set READY state");
7061                 return ret;
7062         }
7063
7064         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7065
7066         /* create dot before error-return. for debugging */
7067         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7068
7069         MMPLAYER_FLEAVE();
7070
7071         return ret;
7072 }
7073
7074 static int __gst_unrealize(mm_player_t* player)
7075 {
7076         int ret = MM_ERROR_NONE;
7077
7078         MMPLAYER_FENTER();
7079
7080         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7081
7082         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7083         MMPLAYER_PRINT_STATE(player);
7084
7085         /* release miscellaneous information */
7086         __mmplayer_release_misc(player);
7087
7088         /* destroy pipeline */
7089         ret = __mmplayer_gst_destroy_pipeline(player);
7090         if (ret != MM_ERROR_NONE) {
7091                 LOGE("failed to destory pipeline\n");
7092                 return ret;
7093         }
7094
7095         /* release miscellaneous information.
7096            these info needs to be released after pipeline is destroyed. */
7097         __mmplayer_release_misc_post(player);
7098
7099         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7100
7101         MMPLAYER_FLEAVE();
7102
7103         return ret;
7104 }
7105
7106 static int __gst_pending_seek(mm_player_t* player)
7107 {
7108         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7109         int ret = MM_ERROR_NONE;
7110
7111         MMPLAYER_FENTER();
7112
7113         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7114
7115         if (!player->pending_seek.is_pending) {
7116                 LOGD("pending seek is not reserved. nothing to do.\n");
7117                 return ret;
7118         }
7119
7120         /* check player state if player could pending seek or not. */
7121         current_state = MMPLAYER_CURRENT_STATE(player);
7122
7123         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7124                 LOGW("try to pending seek in %s state, try next time. \n",
7125                         MMPLAYER_STATE_GET_NAME(current_state));
7126                 return ret;
7127         }
7128
7129         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7130
7131         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7132
7133         if (MM_ERROR_NONE != ret)
7134                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7135
7136         player->pending_seek.is_pending = FALSE;
7137
7138         MMPLAYER_FLEAVE();
7139
7140         return ret;
7141 }
7142
7143 static int __gst_start(mm_player_t* player)
7144 {
7145         gboolean sound_extraction = 0;
7146         int ret = MM_ERROR_NONE;
7147         gboolean async = FALSE;
7148
7149         MMPLAYER_FENTER();
7150
7151         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7152
7153         /* get sound_extraction property */
7154         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7155
7156         /* NOTE : if SetPosition was called before Start. do it now */
7157         /* streaming doesn't support it. so it should be always sync */
7158         /* !!create one more api to check if there is pending seek rather than checking variables */
7159         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7160                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7161                 ret = __gst_pause(player, FALSE);
7162                 if (ret != MM_ERROR_NONE) {
7163                         LOGE("failed to set state to PAUSED for pending seek\n");
7164                         return ret;
7165                 }
7166
7167                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7168
7169                 if (sound_extraction) {
7170                         LOGD("setting pcm extraction\n");
7171
7172                         ret = __mmplayer_set_pcm_extraction(player);
7173                         if (MM_ERROR_NONE != ret) {
7174                                 LOGW("failed to set pcm extraction\n");
7175                                 return ret;
7176                         }
7177                 } else {
7178                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7179                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7180                 }
7181         }
7182
7183         LOGD("current state before doing transition");
7184         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7185         MMPLAYER_PRINT_STATE(player);
7186
7187         /* set pipeline state to PLAYING  */
7188         if (player->es_player_push_mode)
7189                 async = TRUE;
7190         /* set pipeline state to PLAYING  */
7191         ret = __mmplayer_gst_set_state(player,
7192                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7193
7194         if (ret == MM_ERROR_NONE) {
7195                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7196         } else {
7197                 LOGE("failed to set state to PLAYING");
7198                 return ret;
7199         }
7200
7201         /* generating debug info before returning error */
7202         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7203
7204         MMPLAYER_FLEAVE();
7205
7206         return ret;
7207 }
7208
7209 static int __gst_stop(mm_player_t* player)
7210 {
7211         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7212         MMHandleType attrs = 0;
7213         gboolean rewind = FALSE;
7214         gint timeout = 0;
7215         int ret = MM_ERROR_NONE;
7216         gboolean async = FALSE;
7217
7218         MMPLAYER_FENTER();
7219
7220         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7221         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7222
7223         LOGD("current state before doing transition");
7224         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7225         MMPLAYER_PRINT_STATE(player);
7226
7227         attrs = MMPLAYER_GET_ATTRS(player);
7228         if (!attrs) {
7229                 LOGE("cannot get content attribute\n");
7230                 return MM_ERROR_PLAYER_INTERNAL;
7231         }
7232
7233         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7234         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7235
7236         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7237                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7238                 rewind = TRUE;
7239
7240         if (player->es_player_push_mode)
7241                 async = TRUE;
7242         /* set gst state */
7243         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7244
7245         /* return if set_state has failed */
7246         if (ret != MM_ERROR_NONE) {
7247                 LOGE("failed to set state.\n");
7248                 return ret;
7249         }
7250
7251         /* rewind */
7252         if (rewind) {
7253                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7254                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7255                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7256                         LOGW("failed to rewind\n");
7257                         ret = MM_ERROR_PLAYER_SEEK;
7258                 }
7259         }
7260
7261         /* initialize */
7262         player->sent_bos = FALSE;
7263
7264         if (player->es_player_push_mode) //for cloudgame
7265                 timeout = 0;
7266
7267         /* wait for seek to complete */
7268         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7269         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7270                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7271         } else {
7272                 LOGE("fail to stop player.\n");
7273                 ret = MM_ERROR_PLAYER_INTERNAL;
7274                 __mmplayer_dump_pipeline_state(player);
7275         }
7276
7277         /* generate dot file if enabled */
7278         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7279
7280         MMPLAYER_FLEAVE();
7281
7282         return ret;
7283 }
7284
7285 int __gst_pause(mm_player_t* player, gboolean async)
7286 {
7287         int ret = MM_ERROR_NONE;
7288
7289         MMPLAYER_FENTER();
7290
7291         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7292         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7293
7294         LOGD("current state before doing transition");
7295         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7296         MMPLAYER_PRINT_STATE(player);
7297
7298         /* set pipeline status to PAUSED */
7299         ret = __mmplayer_gst_set_state(player,
7300                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7301
7302         if (FALSE == async) {
7303                 if (ret != MM_ERROR_NONE) {
7304                         GstMessage *msg = NULL;
7305                         GTimer *timer = NULL;
7306                         gdouble MAX_TIMEOUT_SEC = 3;
7307
7308                         LOGE("failed to set state to PAUSED");
7309
7310                         if (player->msg_posted) {
7311                                 LOGE("error msg is already posted.");
7312                                 return ret;
7313                         }
7314
7315                         timer = g_timer_new();
7316                         g_timer_start(timer);
7317
7318                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7319
7320                         do {
7321                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7322                                 if (msg) {
7323                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7324                                                 GError *error = NULL;
7325
7326                                                 /* parse error code */
7327                                                 gst_message_parse_error(msg, &error, NULL);
7328
7329                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7330                                                         /* Note : the streaming error from the streaming source is handled
7331                                                          *   using __mmplayer_handle_streaming_error.
7332                                                          */
7333                                                         __mmplayer_handle_streaming_error(player, msg);
7334
7335                                                 } else if (error) {
7336                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7337
7338                                                         if (error->domain == GST_STREAM_ERROR)
7339                                                                 ret = __gst_handle_stream_error(player, error, msg);
7340                                                         else if (error->domain == GST_RESOURCE_ERROR)
7341                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7342                                                         else if (error->domain == GST_LIBRARY_ERROR)
7343                                                                 ret = __gst_handle_library_error(player, error->code);
7344                                                         else if (error->domain == GST_CORE_ERROR)
7345                                                                 ret = __gst_handle_core_error(player, error->code);
7346
7347                                                         g_error_free(error);
7348                                                 }
7349                                                 player->msg_posted = TRUE;
7350                                         }
7351                                         gst_message_unref(msg);
7352                                 }
7353                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7354                         /* clean */
7355                         gst_object_unref(bus);
7356                         g_timer_stop(timer);
7357                         g_timer_destroy(timer);
7358
7359                         return ret;
7360
7361                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7362                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7363
7364                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7365
7366                 } else if (ret == MM_ERROR_NONE) {
7367
7368                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7369                 }
7370         }
7371
7372         /* generate dot file before returning error */
7373         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7374
7375         MMPLAYER_FLEAVE();
7376
7377         return ret;
7378 }
7379
7380 int __gst_resume(mm_player_t* player, gboolean async)
7381 {
7382         int ret = MM_ERROR_NONE;
7383         gint timeout = 0;
7384
7385         MMPLAYER_FENTER();
7386
7387         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7388                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7389
7390         LOGD("current state before doing transition");
7391         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7392         MMPLAYER_PRINT_STATE(player);
7393
7394         /* generate dot file before returning error */
7395         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7396
7397         if (async)
7398                 LOGD("do async state transition to PLAYING.\n");
7399
7400         /* set pipeline state to PLAYING */
7401         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7402
7403         ret = __mmplayer_gst_set_state(player,
7404                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7405         if (ret != MM_ERROR_NONE) {
7406                 LOGE("failed to set state to PLAYING\n");
7407                 return ret;
7408         } else {
7409                 if (async == FALSE) {
7410                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7411                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7412                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7413                 }
7414         }
7415
7416         /* generate dot file before returning error */
7417         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7418
7419         MMPLAYER_FLEAVE();
7420
7421         return ret;
7422 }
7423
7424 static int
7425 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7426 {
7427         unsigned long dur_msec = 0;
7428         gint64 dur_nsec = 0;
7429         gint64 pos_nsec = 0;
7430         gboolean ret = TRUE;
7431         gboolean accurated = FALSE;
7432         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7433
7434         MMPLAYER_FENTER();
7435         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7436         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7437
7438         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7439                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7440                 goto PENDING;
7441
7442         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7443                 /* check duration */
7444                 /* NOTE : duration cannot be zero except live streaming.
7445                  *              Since some element could have some timing problemn with quering duration, try again.
7446                  */
7447                 if (!player->duration) {
7448                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7449                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7450                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7451                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7452                                         player->pending_seek.is_pending = TRUE;
7453                                         player->pending_seek.format = format;
7454                                         player->pending_seek.pos = position;
7455                                         player->doing_seek = FALSE;
7456                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7457                                         return MM_ERROR_NONE;
7458                                 } else {
7459                                         goto SEEK_ERROR;
7460                                 }
7461                         }
7462                         player->duration = dur_nsec;
7463                 }
7464
7465                 if (player->duration) {
7466                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7467                 } else {
7468                         LOGE("could not get the duration. fail to seek.\n");
7469                         goto SEEK_ERROR;
7470                 }
7471         }
7472         LOGD("playback rate: %f\n", player->playback_rate);
7473
7474         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7475         if (accurated)
7476                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7477         else
7478                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7479
7480         /* do seek */
7481         switch (format) {
7482         case MM_PLAYER_POS_FORMAT_TIME:
7483         {
7484                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7485                         GstQuery *query = NULL;
7486                         gboolean seekable = FALSE;
7487
7488                         /* check position is valid or not */
7489                         if (position > dur_msec)
7490                                 goto INVALID_ARGS;
7491
7492                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7493                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7494                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7495                                 gst_query_unref(query);
7496
7497                                 if (!seekable) {
7498                                         LOGW("non-seekable content");
7499                                         player->doing_seek = FALSE;
7500                                         return MM_ERROR_PLAYER_NO_OP;
7501                                 }
7502                         } else {
7503                                 LOGW("failed to get seeking query");
7504                                 gst_query_unref(query); /* keep seeking operation */
7505                         }
7506
7507                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7508
7509                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7510                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7511                            This causes problem is position calculation during normal pause resume scenarios also.
7512                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7513                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7514                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7515                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7516                                         LOGW("getting current position failed in seek\n");
7517
7518                                 player->last_position = pos_nsec;
7519                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7520                         }
7521
7522                         if (player->doing_seek) {
7523                                 LOGD("not completed seek");
7524                                 return MM_ERROR_PLAYER_DOING_SEEK;
7525                         }
7526                 }
7527
7528                 if (!internal_called)
7529                         player->doing_seek = TRUE;
7530
7531                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7532
7533                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7534                         gint64 cur_time = 0;
7535
7536                         /* get current position */
7537                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7538
7539                         /* flush */
7540                         GstEvent *event = gst_event_new_seek(1.0,
7541                                                         GST_FORMAT_TIME,
7542                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7543                                                         GST_SEEK_TYPE_SET, cur_time,
7544                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7545                         if (event)
7546                                 __gst_send_event_to_sink(player, event);
7547
7548                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7549                                 __gst_pause(player, FALSE);
7550                 }
7551
7552                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7553                         that's why set position through property. */
7554                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7555                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7556                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7557                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7558
7559                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7560                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7561                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7562                         player->doing_seek = FALSE;
7563                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7564                 } else {
7565                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7566                                                         GST_FORMAT_TIME, seek_flags,
7567                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7568                 }
7569
7570                 if (!ret) {
7571                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7572                         goto SEEK_ERROR;
7573                 }
7574         }
7575         break;
7576
7577         case MM_PLAYER_POS_FORMAT_PERCENT:
7578         {
7579                 LOGD("seeking to(%lu)%% \n", position);
7580
7581                 if (player->doing_seek) {
7582                         LOGD("not completed seek");
7583                         return MM_ERROR_PLAYER_DOING_SEEK;
7584                 }
7585
7586                 if (!internal_called)
7587                         player->doing_seek = TRUE;
7588
7589                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7590                 pos_nsec = (gint64)((position * player->duration) / 100);
7591                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7592                                                 GST_FORMAT_TIME, seek_flags,
7593                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7594                 if (!ret) {
7595                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7596                         goto SEEK_ERROR;
7597                 }
7598         }
7599         break;
7600
7601         default:
7602                 goto INVALID_ARGS;
7603         }
7604
7605         /* NOTE : store last seeking point to overcome some bad operation
7606           *     (returning zero when getting current position) of some elements
7607           */
7608         player->last_position = pos_nsec;
7609
7610         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7611         if (player->playback_rate > 1.0)
7612                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7613
7614         MMPLAYER_FLEAVE();
7615         return MM_ERROR_NONE;
7616
7617 PENDING:
7618         player->pending_seek.is_pending = TRUE;
7619         player->pending_seek.format = format;
7620         player->pending_seek.pos = position;
7621
7622         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7623                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7624
7625         return MM_ERROR_NONE;
7626
7627 INVALID_ARGS:
7628         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7629         return MM_ERROR_INVALID_ARGUMENT;
7630
7631 SEEK_ERROR:
7632         player->doing_seek = FALSE;
7633         return MM_ERROR_PLAYER_SEEK;
7634 }
7635
7636 #define TRICKPLAY_OFFSET GST_MSECOND
7637
7638 static int
7639 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7640 {
7641         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7642         gint64 pos_msec = 0;
7643         gboolean ret = TRUE;
7644
7645         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7646                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7647
7648         current_state = MMPLAYER_CURRENT_STATE(player);
7649
7650         /* NOTE : query position except paused state to overcome some bad operation
7651          * please refer to below comments in details
7652          */
7653         if (current_state != MM_PLAYER_STATE_PAUSED)
7654                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7655
7656         /* NOTE : get last point to overcome some bad operation of some elements
7657          *(returning zero when getting current position in paused state
7658          * and when failed to get postion during seeking
7659          */
7660         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7661                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7662
7663                 if (player->playback_rate < 0.0)
7664                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7665                 else
7666                         pos_msec = player->last_position;
7667
7668                 if (!ret)
7669                         pos_msec = player->last_position;
7670                 else
7671                         player->last_position = pos_msec;
7672
7673                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7674
7675         } else {
7676                 if (player->duration > 0 && pos_msec > player->duration)
7677                         pos_msec = player->duration;
7678
7679                 player->last_position = pos_msec;
7680         }
7681
7682         switch (format) {
7683         case MM_PLAYER_POS_FORMAT_TIME:
7684                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7685                 break;
7686
7687         case MM_PLAYER_POS_FORMAT_PERCENT:
7688         {
7689                 if (player->duration <= 0) {
7690                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7691                         *position = 0;
7692                 } else {
7693                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7694                         *position = pos_msec * 100 / player->duration;
7695                 }
7696                 break;
7697         }
7698         default:
7699                 return MM_ERROR_PLAYER_INTERNAL;
7700         }
7701
7702         return MM_ERROR_NONE;
7703 }
7704
7705
7706 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7707 {
7708 #define STREAMING_IS_FINISHED   0
7709 #define BUFFERING_MAX_PER       100
7710 #define DEFAULT_PER_VALUE       -1
7711 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7712
7713         MMPlayerGstElement *mainbin = NULL;
7714         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7715         gint64 buffered_total = 0;
7716         unsigned long position = 0;
7717         gint buffered_sec = -1;
7718         GstBufferingMode mode = GST_BUFFERING_STREAM;
7719         gint64 content_size_time = player->duration;
7720         guint64 content_size_bytes = player->http_content_size;
7721
7722         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7723                                                 player->pipeline &&
7724                                                 player->pipeline->mainbin,
7725                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7726
7727         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7728
7729         *start_pos = 0;
7730         *stop_pos = 0;
7731
7732         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7733                 /* and rtsp is not ready yet. */
7734                 LOGW("it's only used for http streaming case.\n");
7735                 return MM_ERROR_PLAYER_NO_OP;
7736         }
7737
7738         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7739                 LOGW("Time format is not supported yet.\n");
7740                 return MM_ERROR_INVALID_ARGUMENT;
7741         }
7742
7743         if (content_size_time <= 0 || content_size_bytes <= 0) {
7744                 LOGW("there is no content size.");
7745                 return MM_ERROR_NONE;
7746         }
7747
7748         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7749                 LOGW("fail to get current position.");
7750                 return MM_ERROR_NONE;
7751         }
7752
7753         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7754                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7755
7756         mainbin = player->pipeline->mainbin;
7757         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7758
7759         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7760                 GstQuery *query = NULL;
7761                 gint byte_in_rate = 0, byte_out_rate = 0;
7762                 gint64 estimated_total = 0;
7763
7764                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7765                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7766                         LOGW("fail to get buffering query from queue2");
7767                         if (query)
7768                                 gst_query_unref(query);
7769                         return MM_ERROR_NONE;
7770                 }
7771
7772                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7773                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7774
7775                 if (mode == GST_BUFFERING_STREAM) {
7776                         /* using only queue in case of push mode(ts / mp3) */
7777                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7778                                 GST_FORMAT_BYTES, &buffered_total)) {
7779                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7780                                 stop_per = 100 * buffered_total / content_size_bytes;
7781                         }
7782                 } else {
7783                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7784                         guint idx = 0;
7785                         guint num_of_ranges = 0;
7786                         gint64 start_byte = 0, stop_byte = 0;
7787
7788                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7789                         if (estimated_total != STREAMING_IS_FINISHED) {
7790                                 /* buffered size info from queue2 */
7791                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7792                                 for (idx = 0; idx < num_of_ranges; idx++) {
7793                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7794                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7795
7796                                         buffered_total += (stop_byte - start_byte);
7797                                 }
7798                         } else
7799                                 stop_per = BUFFERING_MAX_PER;
7800                 }
7801                 gst_query_unref(query);
7802         }
7803
7804         if (stop_per == DEFAULT_PER_VALUE) {
7805                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7806                 if (dur_sec > 0) {
7807                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7808
7809                         /* buffered size info from multiqueue */
7810                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7811                                 guint curr_size_bytes = 0;
7812                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7813                                         "curr-size-bytes", &curr_size_bytes, NULL);
7814                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7815                                 buffered_total += curr_size_bytes;
7816                         }
7817
7818                         if (avg_byterate > 0)
7819                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7820                         else if (player->total_maximum_bitrate > 0)
7821                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7822                         else if (player->total_bitrate > 0)
7823                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7824
7825                         if (buffered_sec >= 0)
7826                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7827                 }
7828         }
7829
7830         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7831         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7832
7833         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7834                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7835
7836         return MM_ERROR_NONE;
7837 }
7838
7839 static int
7840 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7841 {
7842         MMPLAYER_FENTER();
7843
7844         if (!player) {
7845                 LOGW("set_message_callback is called with invalid player handle\n");
7846                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7847         }
7848
7849         player->msg_cb = callback;
7850         player->msg_cb_param = user_param;
7851
7852         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7853
7854         MMPLAYER_FLEAVE();
7855
7856         return MM_ERROR_NONE;
7857 }
7858
7859 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7860 {
7861         int ret = MM_ERROR_PLAYER_INVALID_URI;
7862         char *path = NULL;
7863
7864         MMPLAYER_FENTER();
7865
7866         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7867         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7868         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7869
7870         memset(data, 0, sizeof(MMPlayerParseProfile));
7871
7872         if ((path = strstr(uri, "es_buff://"))) {
7873                 if (strlen(path)) {
7874                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7875                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7876                         ret = MM_ERROR_NONE;
7877                 }
7878         } else if ((path = strstr(uri, "rtsp://"))) {
7879                 if (strlen(path)) {
7880                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7881                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7882                         ret = MM_ERROR_NONE;
7883                 }
7884         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7885                 if (strlen(path)) {
7886                         gchar *tmp = NULL;
7887                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7888                         tmp = g_ascii_strdown(uri, strlen(uri));
7889
7890                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7891                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7892                         else
7893                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7894
7895                         ret = MM_ERROR_NONE;
7896                         g_free(tmp);
7897                 }
7898         } else if ((path = strstr(uri, "rtspu://"))) {
7899                 if (strlen(path)) {
7900                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7901                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7902                         ret = MM_ERROR_NONE;
7903                 }
7904         } else if ((path = strstr(uri, "rtspr://"))) {
7905                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7906                 char *separater = strstr(path, "*");
7907
7908                 if (separater) {
7909                         int urgent_len = 0;
7910                         char *urgent = separater + strlen("*");
7911
7912                         if ((urgent_len = strlen(urgent))) {
7913                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7914                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7915                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7916                                 ret = MM_ERROR_NONE;
7917                         }
7918                 }
7919         } else if ((path = strstr(uri, "mms://"))) {
7920                 if (strlen(path)) {
7921                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7922                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7923                         ret = MM_ERROR_NONE;
7924                 }
7925         } else if ((path = strstr(uri, "mem://"))) {
7926                 if (strlen(path)) {
7927                         int mem_size = 0;
7928                         char *buffer = NULL;
7929                         char *seperator = strchr(path, ',');
7930                         char ext[100] = {0,}, size[100] = {0,};
7931
7932                         if (seperator) {
7933                                 if ((buffer = strstr(path, "ext="))) {
7934                                         buffer += strlen("ext=");
7935
7936                                         if (strlen(buffer)) {
7937                                                 strncpy(ext, buffer, 99);
7938
7939                                                 if ((seperator = strchr(ext, ','))
7940                                                         || (seperator = strchr(ext, ' '))
7941                                                         || (seperator = strchr(ext, '\0'))) {
7942                                                         seperator[0] = '\0';
7943                                                 }
7944                                         }
7945                                 }
7946
7947                                 if ((buffer = strstr(path, "size="))) {
7948                                         buffer += strlen("size=");
7949
7950                                         if (strlen(buffer) > 0) {
7951                                                 strncpy(size, buffer, 99);
7952
7953                                                 if ((seperator = strchr(size, ','))
7954                                                         || (seperator = strchr(size, ' '))
7955                                                         || (seperator = strchr(size, '\0'))) {
7956                                                         seperator[0] = '\0';
7957                                                 }
7958
7959                                                 mem_size = atoi(size);
7960                                         }
7961                                 }
7962                         }
7963
7964                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7965                         if (mem_size && param) {
7966                                 if (data->input_mem.buf)
7967                                         free(data->input_mem.buf);
7968                                 data->input_mem.buf = malloc(mem_size);
7969
7970                                 if (data->input_mem.buf) {
7971                                         memcpy(data->input_mem.buf, param, mem_size);
7972                                         data->input_mem.len = mem_size;
7973                                         ret = MM_ERROR_NONE;
7974                                 } else {
7975                                         LOGE("failed to alloc mem %d", mem_size);
7976                                         ret = MM_ERROR_PLAYER_INTERNAL;
7977                                 }
7978
7979                                 data->input_mem.offset = 0;
7980                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7981                         }
7982                 }
7983         } else {
7984                 gchar *location = NULL;
7985                 GError *err = NULL;
7986
7987                 if ((path = strstr(uri, "file://"))) {
7988
7989                         location = g_filename_from_uri(uri, NULL, &err);
7990
7991                         if (!location || (err != NULL)) {
7992                           LOGE("Invalid URI '%s' for filesrc: %s", path,
7993                                  (err != NULL) ? err->message : "unknown error");
7994
7995                           if (err) g_error_free(err);
7996                           if (location) g_free(location);
7997
7998                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
7999                           goto exit;
8000                         }
8001
8002                         LOGD("path from uri: %s", location);
8003                 }
8004
8005                 path = (location != NULL) ? (location) : ((char*)uri);
8006                 int file_stat = MM_ERROR_NONE;
8007
8008                 file_stat = util_exist_file_path(path);
8009
8010                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8011                 if (file_stat == MM_ERROR_NONE) {
8012                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8013
8014                         if (util_is_sdp_file(path)) {
8015                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8016                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8017                         } else {
8018                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8019                         }
8020                         ret = MM_ERROR_NONE;
8021                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8022                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8023                 } else {
8024                         LOGE("invalid uri, could not play..\n");
8025                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8026                 }
8027
8028                 if (location) g_free(location);
8029         }
8030
8031 exit:
8032         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8033                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8034         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8035                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8036
8037         /* dump parse result */
8038         SECURE_LOGW("incomming uri : %s\n", uri);
8039         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8040                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8041
8042         MMPLAYER_FLEAVE();
8043
8044         return ret;
8045 }
8046
8047 gboolean
8048 __mmplayer_can_do_interrupt(mm_player_t *player)
8049 {
8050         if (!player || !player->pipeline || !player->attrs) {
8051                 LOGW("not initialized");
8052                 goto FAILED;
8053         }
8054
8055         if (player->set_mode.pcm_extraction) {
8056                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8057                 goto FAILED;
8058         }
8059
8060         /* check if seeking */
8061         if (player->doing_seek) {
8062                 MMMessageParamType msg_param;
8063                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8064                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8065                 player->doing_seek = FALSE;
8066                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8067                 goto FAILED;
8068         }
8069
8070         /* check other thread */
8071         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8072                 LOGW("locked already, cmd state : %d", player->cmd);
8073
8074                 /* check application command */
8075                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8076                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8077
8078                         /* lock will be released at mrp_resource_release_cb() */
8079                         MMPLAYER_CMD_LOCK(player);
8080                         goto INTERRUPT;
8081                 }
8082                 LOGW("nothing to do");
8083                 goto FAILED;
8084         } else {
8085                 LOGW("can interrupt immediately");
8086                 goto INTERRUPT;
8087         }
8088
8089 FAILED:    /* with CMD UNLOCKED */
8090         return FALSE;
8091
8092 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8093         return TRUE;
8094 }
8095
8096 static int
8097 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8098                 void *user_data)
8099 {
8100         mm_player_t *player = NULL;
8101
8102         MMPLAYER_FENTER();
8103
8104         if (user_data == NULL) {
8105                 LOGE("- user_data is null\n");
8106                 return FALSE;
8107         }
8108         player = (mm_player_t *)user_data;
8109
8110         /* do something to release resource here.
8111          * player stop and interrupt forwarding */
8112         if (!__mmplayer_can_do_interrupt(player)) {
8113                 LOGW("no need to interrupt, so leave");
8114         } else {
8115                 MMMessageParamType msg = {0, };
8116                 unsigned long pos = 0;
8117
8118                 player->interrupted_by_resource = TRUE;
8119
8120                 /* get last play position */
8121                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8122                         LOGW("failed to get play position.");
8123                 } else {
8124                         msg.union_type = MM_MSG_UNION_TIME;
8125                         msg.time.elapsed = (unsigned int)pos;
8126                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8127                 }
8128                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8129                 if (_mmplayer_unrealize((MMHandleType)player))
8130                         LOGW("failed to unrealize");
8131
8132                 /* lock is called in __mmplayer_can_do_interrupt() */
8133                 MMPLAYER_CMD_UNLOCK(player);
8134         }
8135
8136         if (res == player->video_overlay_resource)
8137                 player->video_overlay_resource = FALSE;
8138         else
8139                 player->video_decoder_resource = FALSE;
8140
8141         MMPLAYER_FLEAVE();
8142
8143         return FALSE;
8144 }
8145
8146 int
8147 _mmplayer_create_player(MMHandleType handle)
8148 {
8149         int ret = MM_ERROR_PLAYER_INTERNAL;
8150         mm_player_t* player = MM_PLAYER_CAST(handle);
8151
8152         MMPLAYER_FENTER();
8153
8154         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8155
8156         /* initialize player state */
8157         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8158         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8159         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8160         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8161
8162         /* check current state */
8163         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8164
8165         /* construct attributes */
8166         player->attrs = _mmplayer_construct_attribute(handle);
8167
8168         if (!player->attrs) {
8169                 LOGE("Failed to construct attributes\n");
8170                 return ret;
8171         }
8172
8173         /* initialize gstreamer with configured parameter */
8174         if (!__mmplayer_init_gstreamer(player)) {
8175                 LOGE("Initializing gstreamer failed\n");
8176                 _mmplayer_deconstruct_attribute(handle);
8177                 return ret;
8178         }
8179
8180         /* create lock. note that g_tread_init() has already called in gst_init() */
8181         g_mutex_init(&player->fsink_lock);
8182
8183         /* create update tag lock */
8184         g_mutex_init(&player->update_tag_lock);
8185
8186         /* create next play mutex */
8187         g_mutex_init(&player->next_play_thread_mutex);
8188
8189         /* create next play cond */
8190         g_cond_init(&player->next_play_thread_cond);
8191
8192         /* create next play thread */
8193         player->next_play_thread =
8194                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8195         if (!player->next_play_thread) {
8196                 LOGE("failed to create next play thread");
8197                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8198                 g_mutex_clear(&player->next_play_thread_mutex);
8199                 g_cond_clear(&player->next_play_thread_cond);
8200                 goto ERROR;
8201         }
8202
8203         ret = _mmplayer_initialize_video_capture(player);
8204         if (ret != MM_ERROR_NONE) {
8205                 LOGE("failed to initialize video capture\n");
8206                 goto ERROR;
8207         }
8208
8209         /* initialize resource manager */
8210         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8211                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8212                         &player->resource_manager)) {
8213                 LOGE("failed to initialize resource manager\n");
8214                 goto ERROR;
8215         }
8216
8217         if (MMPLAYER_IS_HTTP_PD(player)) {
8218                 player->pd_downloader = NULL;
8219                 player->pd_file_save_path = NULL;
8220         }
8221
8222         /* create video bo lock and cond */
8223         g_mutex_init(&player->video_bo_mutex);
8224         g_cond_init(&player->video_bo_cond);
8225
8226         /* create media stream callback mutex */
8227         g_mutex_init(&player->media_stream_cb_lock);
8228
8229         /* create subtitle info lock and cond */
8230         g_mutex_init(&player->subtitle_info_mutex);
8231         g_cond_init(&player->subtitle_info_cond);
8232
8233         player->streaming_type = STREAMING_SERVICE_NONE;
8234
8235         /* give default value of audio effect setting */
8236         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8237         player->sound.rg_enable = false;
8238         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8239
8240         player->play_subtitle = FALSE;
8241         player->use_deinterleave = FALSE;
8242         player->max_audio_channels = 0;
8243         player->video_share_api_delta = 0;
8244         player->video_share_clock_delta = 0;
8245         player->has_closed_caption = FALSE;
8246         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8247         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8248         player->pending_resume = FALSE;
8249         if (player->ini.dump_element_keyword[0][0] == '\0')
8250                 player->ini.set_dump_element_flag = FALSE;
8251         else
8252                 player->ini.set_dump_element_flag = TRUE;
8253
8254         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8255         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8256         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8257
8258         /* Set video360 settings to their defaults for just-created player.
8259          * */
8260         player->is_content_spherical = FALSE;
8261         player->is_video360_enabled = TRUE;
8262         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8263         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8264         player->video360_yaw_radians = 4;
8265         player->video360_pitch_radians = 4;
8266         player->video360_zoom = 1.0f;
8267         player->video360_horizontal_fov = 0;
8268         player->video360_vertical_fov = 0;
8269
8270         /* set player state to null */
8271         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8272         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8273
8274         return MM_ERROR_NONE;
8275
8276 ERROR:
8277         /* free lock */
8278         g_mutex_clear(&player->fsink_lock);
8279
8280         /* free update tag lock */
8281         g_mutex_clear(&player->update_tag_lock);
8282
8283         /* free next play thread */
8284         if (player->next_play_thread) {
8285                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8286                 player->next_play_thread_exit = TRUE;
8287                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8288                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8289
8290                 g_thread_join(player->next_play_thread);
8291                 player->next_play_thread = NULL;
8292
8293                 g_mutex_clear(&player->next_play_thread_mutex);
8294                 g_cond_clear(&player->next_play_thread_cond);
8295         }
8296
8297         /* release attributes */
8298         _mmplayer_deconstruct_attribute(handle);
8299
8300         MMPLAYER_FLEAVE();
8301
8302         return ret;
8303 }
8304
8305 static gboolean
8306 __mmplayer_init_gstreamer(mm_player_t* player)
8307 {
8308         static gboolean initialized = FALSE;
8309         static const int max_argc = 50;
8310         gint* argc = NULL;
8311         gchar** argv = NULL;
8312         gchar** argv2 = NULL;
8313         GError *err = NULL;
8314         int i = 0;
8315         int arg_count = 0;
8316
8317         if (initialized) {
8318                 LOGD("gstreamer already initialized.\n");
8319                 return TRUE;
8320         }
8321
8322         /* alloc */
8323         argc = malloc(sizeof(int));
8324         argv = malloc(sizeof(gchar*) * max_argc);
8325         argv2 = malloc(sizeof(gchar*) * max_argc);
8326
8327         if (!argc || !argv || !argv2)
8328                 goto ERROR;
8329
8330         memset(argv, 0, sizeof(gchar*) * max_argc);
8331         memset(argv2, 0, sizeof(gchar*) * max_argc);
8332
8333         /* add initial */
8334         *argc = 1;
8335         argv[0] = g_strdup("mmplayer");
8336
8337         /* add gst_param */
8338         for (i = 0; i < 5; i++) {
8339                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8340                 if (strlen(player->ini.gst_param[i]) > 0) {
8341                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8342                         (*argc)++;
8343                 }
8344         }
8345
8346         /* we would not do fork for scanning plugins */
8347         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8348         (*argc)++;
8349
8350         /* check disable registry scan */
8351         if (player->ini.skip_rescan) {
8352                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8353                 (*argc)++;
8354         }
8355
8356         /* check disable segtrap */
8357         if (player->ini.disable_segtrap) {
8358                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8359                 (*argc)++;
8360         }
8361
8362         LOGD("initializing gstreamer with following parameter\n");
8363         LOGD("argc : %d\n", *argc);
8364         arg_count = *argc;
8365
8366         for (i = 0; i < arg_count; i++) {
8367                 argv2[i] = argv[i];
8368                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8369         }
8370
8371         /* initializing gstreamer */
8372         if (!gst_init_check(argc, &argv, &err)) {
8373                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8374                 if (err)
8375                         g_error_free(err);
8376
8377                 goto ERROR;
8378         }
8379         /* release */
8380         for (i = 0; i < arg_count; i++) {
8381                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8382                 MMPLAYER_FREEIF(argv2[i]);
8383         }
8384
8385         MMPLAYER_FREEIF(argv);
8386         MMPLAYER_FREEIF(argv2);
8387         MMPLAYER_FREEIF(argc);
8388
8389         /* done */
8390         initialized = TRUE;
8391
8392         return TRUE;
8393
8394 ERROR:
8395
8396         /* release */
8397         for (i = 0; i < arg_count; i++) {
8398                 LOGD("free[%d] : %s\n", i, argv2[i]);
8399                 MMPLAYER_FREEIF(argv2[i]);
8400         }
8401
8402         MMPLAYER_FREEIF(argv);
8403         MMPLAYER_FREEIF(argv2);
8404         MMPLAYER_FREEIF(argc);
8405
8406         return FALSE;
8407 }
8408
8409 int
8410 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8411 {
8412         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8413
8414         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8415                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8416                 MMPLAYER_FREEIF(player->pd_file_save_path);
8417         }
8418
8419         return MM_ERROR_NONE;
8420 }
8421
8422 static void
8423 __mmplayer_check_async_state_transition(mm_player_t* player)
8424 {
8425         GstState element_state = GST_STATE_VOID_PENDING;
8426         GstState element_pending_state = GST_STATE_VOID_PENDING;
8427         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8428         GstElement * element = NULL;
8429         gboolean async = FALSE;
8430
8431         /* check player handle */
8432         MMPLAYER_RETURN_IF_FAIL(player &&
8433                                                 player->pipeline &&
8434                                                 player->pipeline->mainbin &&
8435                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8436
8437         if (player->attrs)
8438                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8439
8440         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8441                 LOGD("don't need to check the pipeline state");
8442                 return;
8443         }
8444
8445         MMPLAYER_PRINT_STATE(player);
8446
8447         /* wait for state transition */
8448         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8449         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8450
8451         if (ret == GST_STATE_CHANGE_FAILURE) {
8452                 LOGE(" [%s] state : %s   pending : %s \n",
8453                         GST_ELEMENT_NAME(element),
8454                         gst_element_state_get_name(element_state),
8455                         gst_element_state_get_name(element_pending_state));
8456
8457                 /* dump state of all element */
8458                 __mmplayer_dump_pipeline_state(player);
8459
8460                 return;
8461         }
8462
8463         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8464         return;
8465 }
8466
8467 int
8468 _mmplayer_destroy(MMHandleType handle)
8469 {
8470         mm_player_t* player = MM_PLAYER_CAST(handle);
8471
8472         MMPLAYER_FENTER();
8473
8474         /* check player handle */
8475         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8476
8477         /* destroy can called at anytime */
8478         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8479
8480         /* check async state transition */
8481         __mmplayer_check_async_state_transition(player);
8482
8483         __mmplayer_destroy_streaming_ext(player);
8484
8485         /* release next play thread */
8486         if (player->next_play_thread) {
8487                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8488                 player->next_play_thread_exit = TRUE;
8489                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8490                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8491
8492                 LOGD("waitting for next play thread exit\n");
8493                 g_thread_join(player->next_play_thread);
8494                 g_mutex_clear(&player->next_play_thread_mutex);
8495                 g_cond_clear(&player->next_play_thread_cond);
8496                 LOGD("next play thread released\n");
8497         }
8498
8499         _mmplayer_release_video_capture(player);
8500
8501         /* de-initialize resource manager */
8502         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8503                         player->resource_manager))
8504                 LOGE("failed to deinitialize resource manager\n");
8505
8506         /* release pipeline */
8507         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8508                 LOGE("failed to destory pipeline\n");
8509                 return MM_ERROR_PLAYER_INTERNAL;
8510         }
8511
8512         /* release subtitle info lock and cond */
8513         g_mutex_clear(&player->subtitle_info_mutex);
8514         g_cond_clear(&player->subtitle_info_cond);
8515
8516         __mmplayer_release_dump_list(player->dump_list);
8517
8518         /* release miscellaneous information */
8519         __mmplayer_release_misc(player);
8520
8521         /* release miscellaneous information.
8522            these info needs to be released after pipeline is destroyed. */
8523         __mmplayer_release_misc_post(player);
8524
8525         /* release attributes */
8526         _mmplayer_deconstruct_attribute(handle);
8527
8528         /* release lock */
8529         g_mutex_clear(&player->fsink_lock);
8530
8531         /* release lock */
8532         g_mutex_clear(&player->update_tag_lock);
8533
8534         /* release video bo lock and cond */
8535         g_mutex_clear(&player->video_bo_mutex);
8536         g_cond_clear(&player->video_bo_cond);
8537
8538         /* release media stream callback lock */
8539         g_mutex_clear(&player->media_stream_cb_lock);
8540
8541         MMPLAYER_FLEAVE();
8542
8543         return MM_ERROR_NONE;
8544 }
8545
8546 int
8547 __mmplayer_realize_streaming_ext(mm_player_t* player)
8548 {
8549         int ret = MM_ERROR_NONE;
8550
8551         MMPLAYER_FENTER();
8552         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8553
8554         if (MMPLAYER_IS_HTTP_PD(player)) {
8555                 gboolean bret = FALSE;
8556
8557                 player->pd_downloader = _mmplayer_create_pd_downloader();
8558                 if (!player->pd_downloader) {
8559                         LOGE("Unable to create PD Downloader...");
8560                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8561                 }
8562
8563                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8564
8565                 if (FALSE == bret) {
8566                         LOGE("Unable to create PD Downloader...");
8567                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8568                 }
8569         }
8570
8571         MMPLAYER_FLEAVE();
8572         return ret;
8573 }
8574
8575 int
8576 _mmplayer_realize(MMHandleType hplayer)
8577 {
8578         mm_player_t* player = (mm_player_t*)hplayer;
8579         char *uri = NULL;
8580         void *param = NULL;
8581         MMHandleType attrs = 0;
8582         int ret = MM_ERROR_NONE;
8583
8584         MMPLAYER_FENTER();
8585
8586         /* check player handle */
8587         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8588
8589         /* check current state */
8590         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8591
8592         attrs = MMPLAYER_GET_ATTRS(player);
8593         if (!attrs) {
8594                 LOGE("fail to get attributes.\n");
8595                 return MM_ERROR_PLAYER_INTERNAL;
8596         }
8597         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8598         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8599
8600         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8601                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8602
8603                 if (ret != MM_ERROR_NONE) {
8604                         LOGE("failed to parse profile\n");
8605                         return ret;
8606                 }
8607         }
8608
8609         if (uri && (strstr(uri, "es_buff://"))) {
8610                 if (strstr(uri, "es_buff://push_mode"))
8611                         player->es_player_push_mode = TRUE;
8612                 else
8613                         player->es_player_push_mode = FALSE;
8614         }
8615
8616         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8617                 LOGW("mms protocol is not supported format.\n");
8618                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8619         }
8620
8621         if (MMPLAYER_IS_STREAMING(player))
8622                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8623         else
8624                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8625
8626         player->smooth_streaming = FALSE;
8627         player->videodec_linked  = 0;
8628         player->videosink_linked = 0;
8629         player->audiodec_linked  = 0;
8630         player->audiosink_linked = 0;
8631         player->textsink_linked = 0;
8632         player->is_external_subtitle_present = FALSE;
8633         player->is_external_subtitle_added_now = FALSE;
8634         /* set the subtitle ON default */
8635         player->is_subtitle_off = FALSE;
8636
8637         /* realize pipeline */
8638         ret = __gst_realize(player);
8639         if (ret != MM_ERROR_NONE)
8640                 LOGE("fail to realize the player.\n");
8641         else
8642                 ret = __mmplayer_realize_streaming_ext(player);
8643
8644         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8645         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8646
8647         MMPLAYER_FLEAVE();
8648
8649         return ret;
8650 }
8651
8652 int
8653 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8654 {
8655         MMPLAYER_FENTER();
8656         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8657
8658         /* destroy can called at anytime */
8659         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8660                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8661
8662         MMPLAYER_FLEAVE();
8663         return MM_ERROR_NONE;
8664 }
8665
8666 int
8667 _mmplayer_unrealize(MMHandleType hplayer)
8668 {
8669         mm_player_t* player = (mm_player_t*)hplayer;
8670         int ret = MM_ERROR_NONE;
8671
8672         MMPLAYER_FENTER();
8673
8674         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8675
8676         MMPLAYER_CMD_UNLOCK(player);
8677         /* destroy the gst bus msg thread which is created during realize.
8678            this funct have to be called before getting cmd lock. */
8679         _mmplayer_bus_msg_thread_destroy(player);
8680         MMPLAYER_CMD_LOCK(player);
8681
8682         /* check current state */
8683         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8684
8685         /* check async state transition */
8686         __mmplayer_check_async_state_transition(player);
8687
8688         __mmplayer_unrealize_streaming_ext(player);
8689
8690         /* unrealize pipeline */
8691         ret = __gst_unrealize(player);
8692
8693         /* set asm stop if success */
8694         if (MM_ERROR_NONE == ret) {
8695                 if (!player->interrupted_by_resource) {
8696                         if (player->video_decoder_resource != NULL) {
8697                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8698                                                 player->video_decoder_resource);
8699                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8700                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8701                                 else
8702                                         player->video_decoder_resource = NULL;
8703                         }
8704
8705                         if (player->video_overlay_resource != NULL) {
8706                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8707                                                 player->video_overlay_resource);
8708                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8709                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8710                                 else
8711                                         player->video_overlay_resource = NULL;
8712                         }
8713
8714                         ret = mm_resource_manager_commit(player->resource_manager);
8715                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8716                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8717                 }
8718         } else
8719                 LOGE("failed and don't change asm state to stop");
8720
8721         MMPLAYER_FLEAVE();
8722
8723         return ret;
8724 }
8725
8726 int
8727 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8728 {
8729         mm_player_t* player = (mm_player_t*)hplayer;
8730
8731         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8732
8733         return __gst_set_message_callback(player, callback, user_param);
8734 }
8735
8736 int
8737 _mmplayer_get_state(MMHandleType hplayer, int* state)
8738 {
8739         mm_player_t *player = (mm_player_t*)hplayer;
8740
8741         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8742
8743         *state = MMPLAYER_CURRENT_STATE(player);
8744
8745         return MM_ERROR_NONE;
8746 }
8747
8748
8749 int
8750 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8751 {
8752         mm_player_t* player = (mm_player_t*) hplayer;
8753         GstElement* vol_element = NULL;
8754         int i = 0;
8755
8756         MMPLAYER_FENTER();
8757
8758         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8759
8760         LOGD("volume [L]=%f:[R]=%f\n",
8761                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8762
8763         /* invalid factor range or not */
8764         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8765                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8766                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8767                         return MM_ERROR_INVALID_ARGUMENT;
8768                 }
8769         }
8770
8771         /* not support to set other value into each channel */
8772         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8773                 return MM_ERROR_INVALID_ARGUMENT;
8774
8775         /* Save volume to handle. Currently the first array element will be saved. */
8776         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8777
8778         /* check pipeline handle */
8779         if (!player->pipeline || !player->pipeline->audiobin) {
8780                 LOGD("audiobin is not created yet\n");
8781                 LOGD("but, current stored volume will be set when it's created.\n");
8782
8783                 /* NOTE : stored volume will be used in create_audiobin
8784                  * returning MM_ERROR_NONE here makes application to able to
8785                  * set volume at anytime.
8786                  */
8787                 return MM_ERROR_NONE;
8788         }
8789
8790         /* setting volume to volume element */
8791         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8792
8793         if (vol_element) {
8794                 LOGD("volume is set [%f]\n", player->sound.volume);
8795                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8796         }
8797
8798         MMPLAYER_FLEAVE();
8799
8800         return MM_ERROR_NONE;
8801 }
8802
8803
8804 int
8805 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8806 {
8807         mm_player_t* player = (mm_player_t*) hplayer;
8808         int i = 0;
8809
8810         MMPLAYER_FENTER();
8811
8812         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8813         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8814
8815         /* returning stored volume */
8816         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8817                 volume->level[i] = player->sound.volume;
8818
8819         MMPLAYER_FLEAVE();
8820
8821         return MM_ERROR_NONE;
8822 }
8823
8824 int
8825 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8826 {
8827         mm_player_t* player = (mm_player_t*) hplayer;
8828         GstElement* vol_element = NULL;
8829
8830         MMPLAYER_FENTER();
8831
8832         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8833
8834         /* mute value shoud 0 or 1 */
8835         if (mute != 0 && mute != 1) {
8836                 LOGE("bad mute value\n");
8837
8838                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8839                 return MM_ERROR_INVALID_ARGUMENT;
8840         }
8841
8842         player->sound.mute = mute;
8843
8844         /* just hold mute value if pipeline is not ready */
8845         if (!player->pipeline || !player->pipeline->audiobin) {
8846                 LOGD("pipeline is not ready. holding mute value\n");
8847                 return MM_ERROR_NONE;
8848         }
8849
8850         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8851
8852         /* NOTE : volume will only created when the bt is enabled */
8853         if (vol_element) {
8854                 LOGD("mute : %d\n", mute);
8855                 g_object_set(vol_element, "mute", mute, NULL);
8856         } else
8857                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8858
8859         MMPLAYER_FLEAVE();
8860
8861         return MM_ERROR_NONE;
8862 }
8863
8864 int
8865 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8866 {
8867         mm_player_t* player = (mm_player_t*) hplayer;
8868
8869         MMPLAYER_FENTER();
8870
8871         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8872         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8873
8874         /* just hold mute value if pipeline is not ready */
8875         if (!player->pipeline || !player->pipeline->audiobin) {
8876                 LOGD("pipeline is not ready. returning stored value\n");
8877                 *pmute = player->sound.mute;
8878                 return MM_ERROR_NONE;
8879         }
8880
8881         *pmute = player->sound.mute;
8882
8883         MMPLAYER_FLEAVE();
8884
8885         return MM_ERROR_NONE;
8886 }
8887
8888 int
8889 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8890 {
8891         mm_player_t* player = (mm_player_t*) hplayer;
8892
8893         MMPLAYER_FENTER();
8894
8895         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8896
8897         player->video_stream_changed_cb = callback;
8898         player->video_stream_changed_cb_user_param = user_param;
8899         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8900
8901         MMPLAYER_FLEAVE();
8902
8903         return MM_ERROR_NONE;
8904 }
8905
8906 int
8907 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8908 {
8909         mm_player_t* player = (mm_player_t*) hplayer;
8910
8911         MMPLAYER_FENTER();
8912
8913         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8914
8915         player->audio_stream_changed_cb = callback;
8916         player->audio_stream_changed_cb_user_param = user_param;
8917         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8918
8919         MMPLAYER_FLEAVE();
8920
8921         return MM_ERROR_NONE;
8922 }
8923
8924 int
8925 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8926 {
8927         mm_player_t* player = (mm_player_t*) hplayer;
8928
8929         MMPLAYER_FENTER();
8930
8931         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8932
8933         player->audio_stream_render_cb_ex = callback;
8934         player->audio_stream_cb_user_param = user_param;
8935         player->audio_stream_sink_sync = sync;
8936         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);
8937
8938         MMPLAYER_FLEAVE();
8939
8940         return MM_ERROR_NONE;
8941 }
8942
8943 int
8944 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8945 {
8946         mm_player_t* player = (mm_player_t*) hplayer;
8947
8948         MMPLAYER_FENTER();
8949
8950         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8951
8952         if (callback && !player->bufmgr)
8953                 player->bufmgr = tbm_bufmgr_init(-1);
8954
8955         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8956         player->video_stream_cb = callback;
8957         player->video_stream_cb_user_param = user_param;
8958
8959         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8960
8961         MMPLAYER_FLEAVE();
8962
8963         return MM_ERROR_NONE;
8964 }
8965
8966 int
8967 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8968 {
8969         mm_player_t* player = (mm_player_t*) hplayer;
8970
8971         MMPLAYER_FENTER();
8972
8973         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8974
8975         player->audio_stream_cb = callback;
8976         player->audio_stream_cb_user_param = user_param;
8977         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8978
8979         MMPLAYER_FLEAVE();
8980
8981         return MM_ERROR_NONE;
8982 }
8983
8984 static int
8985 __mmplayer_start_streaming_ext(mm_player_t *player)
8986 {
8987         gint ret = MM_ERROR_NONE;
8988
8989         MMPLAYER_FENTER();
8990         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991
8992         if (MMPLAYER_IS_HTTP_PD(player)) {
8993                 if (!player->pd_downloader) {
8994                         ret = __mmplayer_realize_streaming_ext(player);
8995
8996                         if (ret != MM_ERROR_NONE) {
8997                                 LOGE("failed to realize streaming ext\n");
8998                                 return ret;
8999                         }
9000                 }
9001
9002                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9003                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9004                         if (!ret) {
9005                                 LOGE("ERROR while starting PD...\n");
9006                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9007                         }
9008                         ret = MM_ERROR_NONE;
9009                 }
9010         }
9011
9012         MMPLAYER_FLEAVE();
9013         return ret;
9014 }
9015
9016 int
9017 _mmplayer_start(MMHandleType hplayer)
9018 {
9019         mm_player_t* player = (mm_player_t*) hplayer;
9020         gint ret = MM_ERROR_NONE;
9021
9022         MMPLAYER_FENTER();
9023
9024         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9025
9026         /* check current state */
9027         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9028
9029         /* NOTE : we should check and create pipeline again if not created as we destroy
9030          * whole pipeline when stopping in streamming playback
9031          */
9032         if (!player->pipeline) {
9033                 ret = __gst_realize(player);
9034                 if (MM_ERROR_NONE != ret) {
9035                         LOGE("failed to realize before starting. only in streamming\n");
9036                         /* unlock */
9037                         return ret;
9038                 }
9039         }
9040
9041         ret = __mmplayer_start_streaming_ext(player);
9042         if (ret != MM_ERROR_NONE) {
9043                 LOGE("failed to start streaming ext 0x%X", ret);
9044                 return ret;
9045         }
9046
9047         /* start pipeline */
9048         ret = __gst_start(player);
9049         if (ret != MM_ERROR_NONE)
9050                 LOGE("failed to start player.\n");
9051
9052         MMPLAYER_FLEAVE();
9053
9054         return ret;
9055 }
9056
9057 /* NOTE: post "not supported codec message" to application
9058  * when one codec is not found during AUTOPLUGGING in MSL.
9059  * So, it's separated with error of __mmplayer_gst_callback().
9060  * And, if any codec is not found, don't send message here.
9061  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9062  */
9063 int
9064 __mmplayer_handle_missed_plugin(mm_player_t* player)
9065 {
9066         MMMessageParamType msg_param;
9067         memset(&msg_param, 0, sizeof(MMMessageParamType));
9068         gboolean post_msg_direct = FALSE;
9069
9070         MMPLAYER_FENTER();
9071
9072         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9073
9074         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9075                         player->not_supported_codec, player->can_support_codec);
9076
9077         if (player->not_found_demuxer) {
9078                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9079                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9080
9081                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9082                 MMPLAYER_FREEIF(msg_param.data);
9083
9084                 return MM_ERROR_NONE;
9085         }
9086
9087         if (player->not_supported_codec) {
9088                 if (player->can_support_codec) {
9089                         // There is one codec to play
9090                         post_msg_direct = TRUE;
9091                 } else {
9092                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9093                                 post_msg_direct = TRUE;
9094                 }
9095
9096                 if (post_msg_direct) {
9097                         MMMessageParamType msg_param;
9098                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9099
9100                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9101                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9102
9103                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9104                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9105                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9106                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9107
9108                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9109                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9110                         }
9111
9112                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9113
9114                         MMPLAYER_FREEIF(msg_param.data);
9115
9116                         return MM_ERROR_NONE;
9117                 } else {
9118                         // no any supported codec case
9119                         LOGW("not found any codec, posting error code to application.\n");
9120
9121                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9122                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9123                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9124                         } else {
9125                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9126                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9127                         }
9128
9129                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9130
9131                         MMPLAYER_FREEIF(msg_param.data);
9132                 }
9133         }
9134
9135         MMPLAYER_FLEAVE();
9136
9137         return MM_ERROR_NONE;
9138 }
9139
9140 static void __mmplayer_check_pipeline(mm_player_t* player)
9141 {
9142         GstState element_state = GST_STATE_VOID_PENDING;
9143         GstState element_pending_state = GST_STATE_VOID_PENDING;
9144         gint timeout = 0;
9145         int ret = MM_ERROR_NONE;
9146
9147         if (player->gapless.reconfigure) {
9148                 LOGW("pipeline is under construction.\n");
9149
9150                 MMPLAYER_PLAYBACK_LOCK(player);
9151                 MMPLAYER_PLAYBACK_UNLOCK(player);
9152
9153                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9154
9155                 /* wait for state transition */
9156                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9157
9158                 if (ret == GST_STATE_CHANGE_FAILURE)
9159                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9160         }
9161 }
9162
9163 /* NOTE : it should be able to call 'stop' anytime*/
9164 int
9165 _mmplayer_stop(MMHandleType hplayer)
9166 {
9167         mm_player_t* player = (mm_player_t*)hplayer;
9168         int ret = MM_ERROR_NONE;
9169
9170         MMPLAYER_FENTER();
9171
9172         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9173
9174         /* check current state */
9175         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9176
9177         /* check pipline building state */
9178         __mmplayer_check_pipeline(player);
9179         __mmplayer_reset_gapless_state(player);
9180
9181         /* NOTE : application should not wait for EOS after calling STOP */
9182         __mmplayer_cancel_eos_timer(player);
9183
9184         __mmplayer_unrealize_streaming_ext(player);
9185
9186         /* reset */
9187         player->doing_seek = FALSE;
9188
9189         /* stop pipeline */
9190         ret = __gst_stop(player);
9191
9192         if (ret != MM_ERROR_NONE)
9193                 LOGE("failed to stop player.\n");
9194
9195         MMPLAYER_FLEAVE();
9196
9197         return ret;
9198 }
9199
9200 int
9201 _mmplayer_pause(MMHandleType hplayer)
9202 {
9203         mm_player_t* player = (mm_player_t*)hplayer;
9204         gint64 pos_msec = 0;
9205         gboolean async = FALSE;
9206         gint ret = MM_ERROR_NONE;
9207
9208         MMPLAYER_FENTER();
9209
9210         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9211
9212         /* check current state */
9213         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9214
9215         /* check pipline building state */
9216         __mmplayer_check_pipeline(player);
9217
9218         switch (MMPLAYER_CURRENT_STATE(player)) {
9219         case MM_PLAYER_STATE_READY:
9220                 {
9221                         /* check prepare async or not.
9222                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9223                          */
9224                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9225                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9226
9227                         /* Changing back sync of rtspsrc to async */
9228                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9229                                 LOGD("async prepare working mode for rtsp");
9230                                 async = TRUE;
9231                         }
9232                 }
9233                 break;
9234
9235         case MM_PLAYER_STATE_PLAYING:
9236                 {
9237                         /* NOTE : store current point to overcome some bad operation
9238                         *(returning zero when getting current position in paused state) of some
9239                         * elements
9240                         */
9241                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9242                                 LOGW("getting current position failed in paused\n");
9243
9244                         player->last_position = pos_msec;
9245
9246                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9247                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9248                            This causes problem is position calculation during normal pause resume scenarios also.
9249                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9250                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9251                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9252                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9253                         }
9254                 }
9255                 break;
9256         }
9257
9258         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9259                 LOGD("doing async pause in case of ms buff src");
9260                 async = TRUE;
9261         }
9262
9263         /* pause pipeline */
9264         ret = __gst_pause(player, async);
9265
9266         if (ret != MM_ERROR_NONE)
9267                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9268
9269         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9270                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9271                         LOGE("failed to update display_rotation");
9272         }
9273
9274         MMPLAYER_FLEAVE();
9275
9276         return ret;
9277 }
9278
9279 int
9280 _mmplayer_resume(MMHandleType hplayer)
9281 {
9282         mm_player_t* player = (mm_player_t*)hplayer;
9283         int ret = MM_ERROR_NONE;
9284         gboolean async = FALSE;
9285
9286         MMPLAYER_FENTER();
9287
9288         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9289
9290         /* Changing back sync mode rtspsrc to async */
9291         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9292                 LOGD("async resume for rtsp case");
9293                 async = TRUE;
9294         }
9295
9296         /* check current state */
9297         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9298
9299         ret = __gst_resume(player, async);
9300
9301         if (ret != MM_ERROR_NONE)
9302                 LOGE("failed to resume player.\n");
9303
9304         MMPLAYER_FLEAVE();
9305
9306         return ret;
9307 }
9308
9309 static int
9310 __mmplayer_set_pcm_extraction(mm_player_t* player)
9311 {
9312         gint64 start_nsec = 0;
9313         gint64 end_nsec = 0;
9314         gint64 dur_nsec = 0;
9315         gint64 dur_msec = 0;
9316         int required_start = 0;
9317         int required_end = 0;
9318         int ret = 0;
9319
9320         MMPLAYER_FENTER();
9321
9322         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9323
9324         mm_attrs_multiple_get(player->attrs,
9325                 NULL,
9326                 "pcm_extraction_start_msec", &required_start,
9327                 "pcm_extraction_end_msec", &required_end,
9328                 NULL);
9329
9330         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9331
9332         if (required_start == 0 && required_end == 0) {
9333                 LOGD("extracting entire stream");
9334                 return MM_ERROR_NONE;
9335         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9336                 LOGD("invalid range for pcm extraction");
9337                 return MM_ERROR_INVALID_ARGUMENT;
9338         }
9339
9340         /* get duration */
9341         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9342         if (!ret) {
9343                 LOGE("failed to get duration");
9344                 return MM_ERROR_PLAYER_INTERNAL;
9345         }
9346         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9347
9348         if (dur_msec < required_end) {
9349                 // FIXME
9350                 LOGD("invalid end pos for pcm extraction");
9351                 return MM_ERROR_INVALID_ARGUMENT;
9352         }
9353
9354         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9355         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9356
9357         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9358                                         1.0,
9359                                         GST_FORMAT_TIME,
9360                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9361                                         GST_SEEK_TYPE_SET, start_nsec,
9362                                         GST_SEEK_TYPE_SET, end_nsec))) {
9363                 LOGE("failed to seek for pcm extraction\n");
9364
9365                 return MM_ERROR_PLAYER_SEEK;
9366         }
9367
9368         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9369
9370         MMPLAYER_FLEAVE();
9371
9372         return MM_ERROR_NONE;
9373 }
9374
9375 int
9376 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9377 {
9378         mm_player_t* player = (mm_player_t*)hplayer;
9379         gint64 pos_msec = 0;
9380         int ret = MM_ERROR_NONE;
9381         int mute = FALSE;
9382         signed long long start = 0, stop = 0;
9383         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9384         MMPLAYER_FENTER();
9385
9386         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9387         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9388
9389         /* The sound of video is not supported under 0.0 and over 2.0. */
9390         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9391                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9392                         mute = TRUE;
9393         }
9394         _mmplayer_set_mute(hplayer, mute);
9395
9396         if (player->playback_rate == rate)
9397                 return MM_ERROR_NONE;
9398
9399         /* If the position is reached at start potion during fast backward, EOS is posted.
9400          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9401          * */
9402         player->playback_rate = rate;
9403
9404         current_state = MMPLAYER_CURRENT_STATE(player);
9405
9406         if (current_state != MM_PLAYER_STATE_PAUSED)
9407                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9408
9409         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9410
9411         if ((current_state == MM_PLAYER_STATE_PAUSED)
9412                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9413                 LOGW("returning last point : %lld\n", player->last_position);
9414                 pos_msec = player->last_position;
9415         }
9416
9417         if (rate >= 0) {
9418                 start = pos_msec;
9419                 stop = GST_CLOCK_TIME_NONE;
9420         } else {
9421                 start = GST_CLOCK_TIME_NONE;
9422                 stop = pos_msec;
9423         }
9424
9425         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9426                                 player->playback_rate,
9427                                 GST_FORMAT_TIME,
9428                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9429                                 GST_SEEK_TYPE_SET, start,
9430                                 GST_SEEK_TYPE_SET, stop)) {
9431                 LOGE("failed to set speed playback\n");
9432                 return MM_ERROR_PLAYER_SEEK;
9433         }
9434
9435         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9436
9437         MMPLAYER_FLEAVE();
9438
9439         return MM_ERROR_NONE;;
9440 }
9441
9442 int
9443 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9444 {
9445         mm_player_t* player = (mm_player_t*)hplayer;
9446         int ret = MM_ERROR_NONE;
9447
9448         MMPLAYER_FENTER();
9449
9450         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9451
9452         /* check pipline building state */
9453         __mmplayer_check_pipeline(player);
9454
9455         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9456
9457         MMPLAYER_FLEAVE();
9458
9459         return ret;
9460 }
9461
9462 int
9463 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9464 {
9465         mm_player_t* player = (mm_player_t*)hplayer;
9466         int ret = MM_ERROR_NONE;
9467
9468         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9469
9470         ret = __gst_get_position(player, format, position);
9471
9472         return ret;
9473 }
9474
9475 int
9476 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9477 {
9478         mm_player_t* player = (mm_player_t*)hplayer;
9479         int ret = MM_ERROR_NONE;
9480
9481         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9482
9483         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9484
9485         return ret;
9486 }
9487
9488 int
9489 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9490 {
9491         mm_player_t* player = (mm_player_t*)hplayer;
9492         int ret = MM_ERROR_NONE;
9493
9494         MMPLAYER_FENTER();
9495
9496         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9497
9498         ret = __gst_adjust_subtitle_position(player, format, position);
9499
9500         MMPLAYER_FLEAVE();
9501
9502         return ret;
9503 }
9504 int
9505 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9506 {
9507         mm_player_t* player = (mm_player_t*)hplayer;
9508         int ret = MM_ERROR_NONE;
9509
9510         MMPLAYER_FENTER();
9511
9512         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9513
9514         ret = __gst_adjust_video_position(player, offset);
9515
9516         MMPLAYER_FLEAVE();
9517
9518         return ret;
9519 }
9520
9521 static gboolean
9522 __mmplayer_is_midi_type(gchar* str_caps)
9523 {
9524         if ((g_strrstr(str_caps, "audio/midi")) ||
9525                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9526                 (g_strrstr(str_caps, "application/x-smaf")) ||
9527                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9528                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9529                 (g_strrstr(str_caps, "audio/xmf")) ||
9530                 (g_strrstr(str_caps, "audio/mxmf"))) {
9531                 LOGD("midi\n");
9532                 return TRUE;
9533         }
9534
9535         return FALSE;
9536 }
9537
9538 static gboolean
9539 __mmplayer_is_only_mp3_type(gchar *str_caps)
9540 {
9541         if (g_strrstr(str_caps, "application/x-id3") ||
9542                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9543                 return TRUE;
9544         return FALSE;
9545 }
9546
9547 static void
9548 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9549 {
9550         GstStructure* caps_structure = NULL;
9551         gint samplerate = 0;
9552         gint channels = 0;
9553
9554         MMPLAYER_FENTER();
9555         MMPLAYER_RETURN_IF_FAIL(player && caps);
9556
9557         caps_structure = gst_caps_get_structure(caps, 0);
9558
9559         /* set stream information */
9560         gst_structure_get_int(caps_structure, "rate", &samplerate);
9561         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9562
9563         gst_structure_get_int(caps_structure, "channels", &channels);
9564         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9565
9566         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9567 }
9568
9569 static void
9570 __mmplayer_update_content_type_info(mm_player_t* player)
9571 {
9572         MMPLAYER_FENTER();
9573         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9574
9575         if (__mmplayer_is_midi_type(player->type)) {
9576                 player->bypass_audio_effect = TRUE;
9577         } else if (g_strrstr(player->type, "application/x-hls")) {
9578                 /* If it can't know exact type when it parses uri because of redirection case,
9579                  * it will be fixed by typefinder or when doing autoplugging.
9580                  */
9581                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9582                 if (player->streamer) {
9583                         player->streamer->is_adaptive_streaming = TRUE;
9584                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9585                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9586                 }
9587         } else if (g_strrstr(player->type, "application/dash+xml")) {
9588                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9589         }
9590
9591         MMPLAYER_FLEAVE();
9592 }
9593
9594 static void
9595 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9596 GstCaps *caps, gpointer data)
9597 {
9598         mm_player_t* player = (mm_player_t*)data;
9599         GstPad* pad = NULL;
9600
9601         MMPLAYER_FENTER();
9602
9603         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9604
9605         /* store type string */
9606         MMPLAYER_FREEIF(player->type);
9607         player->type = gst_caps_to_string(caps);
9608         if (player->type) {
9609                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9610                                 player, player->type, probability, gst_caps_get_size(caps));
9611         }
9612
9613         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9614                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9615                 LOGE("not support media format\n");
9616
9617                 if (player->msg_posted == FALSE) {
9618                         MMMessageParamType msg_param;
9619                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9620
9621                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9622                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9623
9624                         /* don't post more if one was sent already */
9625                         player->msg_posted = TRUE;
9626                 }
9627                 return;
9628         }
9629
9630         __mmplayer_update_content_type_info(player);
9631
9632         pad = gst_element_get_static_pad(tf, "src");
9633         if (!pad) {
9634                 LOGE("fail to get typefind src pad.\n");
9635                 return;
9636         }
9637
9638         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9639                 gboolean async = FALSE;
9640                 LOGE("failed to autoplug %s\n", player->type);
9641
9642                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9643
9644                 if (async && player->msg_posted == FALSE)
9645                         __mmplayer_handle_missed_plugin(player);
9646
9647                 goto DONE;
9648         }
9649
9650 DONE:
9651         gst_object_unref(GST_OBJECT(pad));
9652
9653         MMPLAYER_FLEAVE();
9654
9655         return;
9656 }
9657
9658 static GstElement *
9659 __mmplayer_create_decodebin(mm_player_t* player)
9660 {
9661         GstElement *decodebin = NULL;
9662
9663         MMPLAYER_FENTER();
9664
9665         /* create decodebin */
9666         decodebin = gst_element_factory_make("decodebin", NULL);
9667
9668         if (!decodebin) {
9669                 LOGE("fail to create decodebin\n");
9670                 goto ERROR;
9671         }
9672
9673         /* raw pad handling signal */
9674         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9675                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9676
9677         /* no-more-pad pad handling signal */
9678         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9679                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9680
9681         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9682                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9683
9684         /* This signal is emitted when a pad for which there is no further possible
9685            decoding is added to the decodebin.*/
9686         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9687                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9688
9689         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9690            before looking for any elements that can handle that stream.*/
9691         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9692                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9693
9694         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9695            before looking for any elements that can handle that stream.*/
9696         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9697                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9698
9699         /* This signal is emitted once decodebin has finished decoding all the data.*/
9700         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9701                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9702
9703         /* This signal is emitted when a element is added to the bin.*/
9704         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9705                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9706
9707 ERROR:
9708         return decodebin;
9709 }
9710
9711 static gboolean
9712 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9713 {
9714         MMPlayerGstElement* mainbin = NULL;
9715         GstElement* decodebin = NULL;
9716         GstElement* queue2 = NULL;
9717         GstPad* sinkpad = NULL;
9718         GstPad* qsrcpad = NULL;
9719         gint64 dur_bytes = 0L;
9720
9721         guint max_buffer_size_bytes = 0;
9722         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9723
9724         MMPLAYER_FENTER();
9725         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9726
9727         mainbin = player->pipeline->mainbin;
9728
9729         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9730                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9731                 LOGD("creating http streaming buffering queue(queue2)\n");
9732
9733                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9734                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9735                 } else {
9736                         queue2 = gst_element_factory_make("queue2", "queue2");
9737                         if (!queue2) {
9738                                 LOGE("failed to create buffering queue element\n");
9739                                 goto ERROR;
9740                         }
9741
9742                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9743                                 LOGE("failed to add buffering queue\n");
9744                                 goto ERROR;
9745                         }
9746
9747                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9748                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9749
9750                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9751                                 LOGE("failed to link buffering queue\n");
9752                                 goto ERROR;
9753                         }
9754
9755                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9756                                 LOGE("fail to get duration.\n");
9757
9758                         LOGD("dur_bytes = %lld\n", dur_bytes);
9759
9760                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9761
9762                         if (dur_bytes > 0) {
9763                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9764                                         type = MUXED_BUFFER_TYPE_FILE;
9765                                 } else {
9766                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9767                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9768                                 }
9769                         } else {
9770                                 dur_bytes = 0;
9771                         }
9772
9773                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9774                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9775                         if (!g_strrstr(player->type, "video/mpegts")) {
9776                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9777                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9778
9779                                 // FIXME : pass ini setting directly. is this ok?
9780                                 __mm_player_streaming_set_queue2(player->streamer,
9781                                                                                                 queue2,
9782                                                                                                 FALSE,
9783                                                                                                 max_buffer_size_bytes,
9784                                                                                                 player->ini.http_buffering_time,
9785                                                                                                 1.0,                                                            // no meaning
9786                                                                                                 player->ini.http_buffering_limit,       // no meaning
9787                                                                                                 type,
9788                                                                                                 player->http_file_buffering_path,
9789                                                                                                 (guint64)dur_bytes);
9790                         }
9791
9792                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9793                                 LOGE("failed to sync queue2 state with parent\n");
9794                                 goto ERROR;
9795                         }
9796
9797                         srcpad = qsrcpad;
9798
9799                         gst_object_unref(GST_OBJECT(sinkpad));
9800
9801                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9802                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9803                 }
9804         }
9805
9806         /* create decodebin */
9807         decodebin = __mmplayer_create_decodebin(player);
9808
9809         if (!decodebin) {
9810                 LOGE("can not create autoplug element\n");
9811                 goto ERROR;
9812         }
9813
9814         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9815                 LOGE("failed to add decodebin\n");
9816                 goto ERROR;
9817         }
9818
9819         /* to force caps on the decodebin element and avoid reparsing stuff by
9820         * typefind. It also avoids a deadlock in the way typefind activates pads in
9821         * the state change */
9822         g_object_set(decodebin, "sink-caps", caps, NULL);
9823
9824         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9825
9826         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9827                 LOGE("failed to link decodebin\n");
9828                 goto ERROR;
9829         }
9830
9831         gst_object_unref(GST_OBJECT(sinkpad));
9832
9833         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9834         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9835
9836         /* set decodebin property about buffer in streaming playback. *
9837          * in case of HLS/DASH, it does not need to have big buffer        *
9838          * because it is kind of adaptive streaming.                  */
9839         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9840                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9841                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9842                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9843
9844                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9845                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9846                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9847                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9848                 }
9849
9850                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9851                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9852                                                                                         "low-percent", 1,   // 1%
9853                                                                                         "max-size-bytes", max_size_bytes,
9854                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9855                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9856         }
9857
9858         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9859                 LOGE("failed to sync decodebin state with parent\n");
9860                 goto ERROR;
9861         }
9862
9863         MMPLAYER_FLEAVE();
9864
9865         return TRUE;
9866
9867 ERROR:
9868
9869         if (sinkpad)
9870                 gst_object_unref(GST_OBJECT(sinkpad));
9871
9872         if (queue2) {
9873                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9874                  * You need to explicitly set elements to the NULL state before
9875                  * dropping the final reference, to allow them to clean up.
9876                  */
9877                 gst_element_set_state(queue2, GST_STATE_NULL);
9878
9879                 /* And, it still has a parent "player".
9880                  * You need to let the parent manage the object instead of unreffing the object directly.
9881                  */
9882                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9883                 gst_object_unref(queue2);
9884                 queue2 = NULL;
9885         }
9886
9887         if (decodebin) {
9888                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9889                  * You need to explicitly set elements to the NULL state before
9890                  * dropping the final reference, to allow them to clean up.
9891                  */
9892                 gst_element_set_state(decodebin, GST_STATE_NULL);
9893
9894                 /* And, it still has a parent "player".
9895                  * You need to let the parent manage the object instead of unreffing the object directly.
9896                  */
9897
9898                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9899                 gst_object_unref(decodebin);
9900                 decodebin = NULL;
9901         }
9902
9903         return FALSE;
9904 }
9905
9906 static int
9907 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9908 {
9909         MMPLAYER_FENTER();
9910
9911         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9912         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9913
9914         LOGD("class : %s, mime : %s \n", factory_class, mime);
9915
9916         /* add missing plugin */
9917         /* NOTE : msl should check missing plugin for image mime type.
9918          * Some motion jpeg clips can have playable audio track.
9919          * So, msl have to play audio after displaying popup written video format not supported.
9920          */
9921         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9922                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9923                         LOGD("not found demuxer\n");
9924                         player->not_found_demuxer = TRUE;
9925                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9926
9927                         goto DONE;
9928                 }
9929         }
9930
9931         if (!g_strrstr(factory_class, "Demuxer")) {
9932                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9933                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9934                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9935
9936                         /* check that clip have multi tracks or not */
9937                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9938                                 LOGD("video plugin is already linked\n");
9939                         } else {
9940                                 LOGW("add VIDEO to missing plugin\n");
9941                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9942                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9943                         }
9944                 } else if (g_str_has_prefix(mime, "audio")) {
9945                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9946                                 LOGD("audio plugin is already linked\n");
9947                         } else {
9948                                 LOGW("add AUDIO to missing plugin\n");
9949                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9950                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9951                         }
9952                 }
9953         }
9954
9955 DONE:
9956         MMPLAYER_FLEAVE();
9957
9958         return MM_ERROR_NONE;
9959 }
9960
9961
9962 static void
9963 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
9964 {
9965         mm_player_t* player = (mm_player_t*)data;
9966
9967         MMPLAYER_FENTER();
9968
9969         MMPLAYER_RETURN_IF_FAIL(player);
9970
9971         /* remove fakesink. */
9972         if (!__mmplayer_gst_remove_fakesink(player,
9973                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9974                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9975                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9976                  * source element are not same. To overcome this situation, this function will called
9977                  * several places and several times. Therefore, this is not an error case.
9978                  */
9979                 return;
9980         }
9981
9982         LOGD("[handle: %p] pipeline has completely constructed", player);
9983
9984         if ((player->ini.async_start) &&
9985                 (player->msg_posted == FALSE) &&
9986                 (player->cmd >= MMPLAYER_COMMAND_START))
9987                 __mmplayer_handle_missed_plugin(player);
9988
9989         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
9990 }
9991
9992 static gboolean
9993 __mmplayer_verify_next_play_path(mm_player_t *player)
9994 {
9995         MMHandleType attrs = 0;
9996         MMPlayerParseProfile profile;
9997         gint uri_idx = 0, check_cnt = 0;
9998         char *uri = NULL;
9999         gint mode = MM_PLAYER_PD_MODE_NONE;
10000         gint video = 0;
10001         gint count = 0;
10002         gint gapless = 0;
10003         guint num_of_list = 0;
10004         static int profile_tv = -1;
10005
10006         MMPLAYER_FENTER();
10007
10008         LOGD("checking for gapless play");
10009
10010         if (player->pipeline->textbin) {
10011                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10012                 goto ERROR;
10013         }
10014
10015         attrs = MMPLAYER_GET_ATTRS(player);
10016         if (!attrs) {
10017                 LOGE("fail to get attributes.\n");
10018                 goto ERROR;
10019         }
10020
10021         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10022
10023         if (__builtin_expect(profile_tv == -1, 0)) {
10024                 char *profileName;
10025                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10026                 switch (*profileName) {
10027                 case 't':
10028                 case 'T':
10029                         profile_tv = 1;
10030                         break;
10031                 default:
10032                         profile_tv = 0;
10033                 }
10034                 free(profileName);
10035         }
10036         /* gapless playback is not supported in case of video at TV profile. */
10037         if (profile_tv && video) {
10038                 LOGW("not support video gapless playback");
10039                 goto ERROR;
10040         }
10041
10042         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10043                 if (mode == TRUE) {
10044                         LOGW("pd mode\n");
10045                         goto ERROR;
10046                 }
10047         }
10048
10049         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10050                 LOGE("can not get play count\n");
10051
10052         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10053                 LOGE("can not get gapless mode\n");
10054
10055         if (video && !gapless) {
10056                 LOGW("not enabled video gapless playback");
10057                 goto ERROR;
10058         }
10059
10060         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10061                 gapless = 1;
10062
10063         if (!gapless) {
10064                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10065                 goto ERROR;
10066         }
10067
10068         num_of_list = g_list_length(player->uri_info.uri_list);
10069
10070         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10071
10072         if (num_of_list == 0) {
10073                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10074                         LOGE("can not get profile_uri\n");
10075                         goto ERROR;
10076                 }
10077
10078                 if (!uri) {
10079                         LOGE("uri list is empty.\n");
10080                         goto ERROR;
10081                 }
10082
10083                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10084                 LOGD("add original path : %s ", uri);
10085
10086                 num_of_list = 1;
10087                 uri = NULL;
10088         }
10089
10090         uri_idx = player->uri_info.uri_idx;
10091
10092         while (TRUE) {
10093                 check_cnt++;
10094
10095                 if (check_cnt > num_of_list) {
10096                         LOGE("there is no valid uri.");
10097                         goto ERROR;
10098                 }
10099
10100                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10101
10102                 if (uri_idx < num_of_list-1) {
10103                         uri_idx++;
10104                 } else {
10105                         if ((count <= 1) && (count != -1)) {
10106                                 LOGD("no repeat.");
10107                                 goto ERROR;
10108                         } else if (count > 1) {
10109                                 /* decrease play count */
10110                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10111                                 count--;
10112
10113                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10114
10115                                 /* commit attribute */
10116                                 if (mmf_attrs_commit(attrs))
10117                                         LOGE("failed to commit attribute\n");
10118                         }
10119
10120                         /* count < 0 : repeat continually */
10121                         uri_idx = 0;
10122                 }
10123
10124                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10125                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10126
10127                 if (uri == NULL) {
10128                         LOGW("next uri does not exist\n");
10129                         continue;
10130                 }
10131
10132                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10133                         LOGE("failed to parse profile\n");
10134                         continue;
10135                 }
10136
10137                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10138                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10139                         LOGW("uri type is not supported(%d).", profile.uri_type);
10140                         continue;
10141                 }
10142
10143                 break;
10144         }
10145
10146         player->uri_info.uri_idx = uri_idx;
10147         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10148
10149         if (mmf_attrs_commit(player->attrs)) {
10150                 LOGE("failed to commit.\n");
10151                 goto ERROR;
10152         }
10153
10154         LOGD("next uri %s(%d)\n", uri, uri_idx);
10155
10156         return TRUE;
10157
10158 ERROR:
10159
10160         LOGE("unable to play next path. EOS will be posted soon.\n");
10161         return FALSE;
10162 }
10163
10164 static void
10165 __mmplayer_initialize_next_play(mm_player_t *player)
10166 {
10167         int i;
10168
10169         MMPLAYER_FENTER();
10170
10171         player->smooth_streaming = FALSE;
10172         player->videodec_linked = 0;
10173         player->audiodec_linked = 0;
10174         player->videosink_linked = 0;
10175         player->audiosink_linked = 0;
10176         player->textsink_linked = 0;
10177         player->is_external_subtitle_present = FALSE;
10178         player->is_external_subtitle_added_now = FALSE;
10179         player->not_supported_codec = MISSING_PLUGIN_NONE;
10180         player->can_support_codec = FOUND_PLUGIN_NONE;
10181         player->pending_seek.is_pending = FALSE;
10182         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10183         player->pending_seek.pos = 0;
10184         player->msg_posted = FALSE;
10185         player->has_many_types = FALSE;
10186         player->no_more_pad = FALSE;
10187         player->not_found_demuxer = 0;
10188         player->doing_seek = FALSE;
10189         player->max_audio_channels = 0;
10190         player->is_subtitle_force_drop = FALSE;
10191         player->play_subtitle = FALSE;
10192         player->adjust_subtitle_pos = 0;
10193
10194         player->total_bitrate = 0;
10195         player->total_maximum_bitrate = 0;
10196
10197         _mmplayer_track_initialize(player);
10198         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10199
10200         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10201                 player->bitrate[i] = 0;
10202                 player->maximum_bitrate[i] = 0;
10203         }
10204
10205         if (player->v_stream_caps) {
10206                 gst_caps_unref(player->v_stream_caps);
10207                 player->v_stream_caps = NULL;
10208         }
10209
10210         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10211
10212         /* clean found parsers */
10213         if (player->parsers) {
10214                 GList *parsers = player->parsers;
10215                 for (; parsers; parsers = g_list_next(parsers)) {
10216                         gchar *name = parsers->data;
10217                         MMPLAYER_FREEIF(name);
10218                 }
10219                 g_list_free(player->parsers);
10220                 player->parsers = NULL;
10221         }
10222
10223         /* clean found audio decoders */
10224         if (player->audio_decoders) {
10225                 GList *a_dec = player->audio_decoders;
10226                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10227                         gchar *name = a_dec->data;
10228                         MMPLAYER_FREEIF(name);
10229                 }
10230                 g_list_free(player->audio_decoders);
10231                 player->audio_decoders = NULL;
10232         }
10233
10234         MMPLAYER_FLEAVE();
10235 }
10236
10237 static void
10238 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10239 {
10240         MMPlayerGstElement *mainbin = NULL;
10241         MMMessageParamType msg_param = {0,};
10242         GstElement *element = NULL;
10243         MMHandleType attrs = 0;
10244         char *uri = NULL;
10245         enum MainElementID elemId = MMPLAYER_M_NUM;
10246
10247         MMPLAYER_FENTER();
10248
10249         if ((player == NULL) ||
10250                 (player->pipeline == NULL) ||
10251                 (player->pipeline->mainbin == NULL)) {
10252                 LOGE("player is null.\n");
10253                 goto ERROR;
10254         }
10255
10256         mainbin = player->pipeline->mainbin;
10257         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10258
10259         attrs = MMPLAYER_GET_ATTRS(player);
10260         if (!attrs) {
10261                 LOGE("fail to get attributes.\n");
10262                 goto ERROR;
10263         }
10264
10265         /* Initialize Player values */
10266         __mmplayer_initialize_next_play(player);
10267
10268         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10269
10270         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10271                 LOGE("failed to parse profile\n");
10272                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10273                 goto ERROR;
10274         }
10275
10276         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10277                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10278                 LOGE("it's dash or hls. not support.");
10279                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10280                 goto ERROR;
10281         }
10282
10283         /* setup source */
10284         switch (player->profile.uri_type) {
10285         /* file source */
10286         case MM_PLAYER_URI_TYPE_FILE:
10287         {
10288                 LOGD("using filesrc for 'file://' handler.\n");
10289                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10290                         LOGE("failed to get storage info");
10291                         break;
10292                 }
10293
10294                 element = gst_element_factory_make("filesrc", "source");
10295
10296                 if (!element) {
10297                         LOGE("failed to create filesrc\n");
10298                         break;
10299                 }
10300
10301                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10302                 break;
10303         }
10304         case MM_PLAYER_URI_TYPE_URL_HTTP:
10305         {
10306                 gchar *user_agent, *cookies, **cookie_list;
10307                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10308                 user_agent = cookies = NULL;
10309                 cookie_list = NULL;
10310
10311                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10312                 if (!element) {
10313                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10314                         break;
10315                 }
10316                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10317
10318                 /* get attribute */
10319                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10320                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10321
10322                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10323                         LOGD("get timeout from ini\n");
10324                         http_timeout = player->ini.http_timeout;
10325                 }
10326
10327                 /* get attribute */
10328                 SECURE_LOGD("location : %s\n", player->profile.uri);
10329                 SECURE_LOGD("cookies : %s\n", cookies);
10330                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10331                 LOGD("timeout : %d\n", http_timeout);
10332
10333                 /* setting property to streaming source */
10334                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10335                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10336                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10337
10338                 /* parsing cookies */
10339                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10340                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10341                 if (user_agent)
10342                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10343                 break;
10344         }
10345         default:
10346                 LOGE("not support uri type %d\n", player->profile.uri_type);
10347                 break;
10348         }
10349
10350         if (!element) {
10351                 LOGE("no source element was created.\n");
10352                 goto ERROR;
10353         }
10354
10355         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10356                 LOGE("failed to add source element to pipeline\n");
10357                 gst_object_unref(GST_OBJECT(element));
10358                 element = NULL;
10359                 goto ERROR;
10360         }
10361
10362         /* take source element */
10363         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10364         mainbin[MMPLAYER_M_SRC].gst = element;
10365
10366         element = NULL;
10367
10368         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10369                 if (player->streamer == NULL) {
10370                         player->streamer = __mm_player_streaming_create();
10371                         __mm_player_streaming_initialize(player->streamer);
10372                 }
10373
10374                 elemId = MMPLAYER_M_TYPEFIND;
10375                 element = gst_element_factory_make("typefind", "typefinder");
10376                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10377                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10378         } else {
10379                 elemId = MMPLAYER_M_AUTOPLUG;
10380                 element = __mmplayer_create_decodebin(player);
10381         }
10382
10383         /* check autoplug element is OK */
10384         if (!element) {
10385                 LOGE("can not create element(%d)\n", elemId);
10386                 goto ERROR;
10387         }
10388
10389         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10390                 LOGE("failed to add sinkbin to pipeline\n");
10391                 gst_object_unref(GST_OBJECT(element));
10392                 element = NULL;
10393                 goto ERROR;
10394         }
10395
10396         mainbin[elemId].id = elemId;
10397         mainbin[elemId].gst = element;
10398
10399         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10400                 LOGE("Failed to link src - autoplug(or typefind)\n");
10401                 goto ERROR;
10402         }
10403
10404         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10405                 LOGE("Failed to change state of src element\n");
10406                 goto ERROR;
10407         }
10408
10409         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10410                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10411                         LOGE("Failed to change state of decodebin\n");
10412                         goto ERROR;
10413                 }
10414         } else {
10415                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10416                         LOGE("Failed to change state of src element\n");
10417                         goto ERROR;
10418                 }
10419         }
10420
10421         player->gapless.stream_changed = TRUE;
10422         player->gapless.running = TRUE;
10423         MMPLAYER_FLEAVE();
10424         return;
10425
10426 ERROR:
10427         if (player) {
10428                 MMPLAYER_PLAYBACK_UNLOCK(player);
10429
10430                 if (!player->msg_posted) {
10431                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10432                         player->msg_posted = TRUE;
10433                 }
10434         }
10435         return;
10436 }
10437
10438 static gboolean
10439 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10440 {
10441         mm_player_selector_t *selector = &player->selector[type];
10442         MMPlayerGstElement *sinkbin = NULL;
10443         enum MainElementID selectorId = MMPLAYER_M_NUM;
10444         enum MainElementID sinkId = MMPLAYER_M_NUM;
10445         GstPad *srcpad = NULL;
10446         GstPad *sinkpad = NULL;
10447         gboolean send_notice = FALSE;
10448
10449         MMPLAYER_FENTER();
10450         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10451
10452         LOGD("type %d", type);
10453
10454         switch (type) {
10455         case MM_PLAYER_TRACK_TYPE_AUDIO:
10456                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10457                 sinkId = MMPLAYER_A_BIN;
10458                 sinkbin = player->pipeline->audiobin;
10459                 break;
10460         case MM_PLAYER_TRACK_TYPE_VIDEO:
10461                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10462                 sinkId = MMPLAYER_V_BIN;
10463                 sinkbin = player->pipeline->videobin;
10464                 send_notice = TRUE;
10465                 break;
10466         case MM_PLAYER_TRACK_TYPE_TEXT:
10467                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10468                 sinkId = MMPLAYER_T_BIN;
10469                 sinkbin = player->pipeline->textbin;
10470                 break;
10471         default:
10472                 LOGE("requested type is not supportable");
10473                 return FALSE;
10474                 break;
10475         }
10476
10477         if (player->pipeline->mainbin[selectorId].gst) {
10478                 gint n;
10479
10480                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10481
10482                 if (selector->event_probe_id != 0)
10483                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10484                 selector->event_probe_id = 0;
10485
10486                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10487                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10488
10489                         if (srcpad && sinkpad) {
10490                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10491                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10492                                 gst_pad_unlink(srcpad, sinkpad);
10493
10494                                 /* send custom event to sink pad to handle it at video sink */
10495                                 if (send_notice) {
10496                                         LOGD("send custom event to sinkpad");
10497                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10498                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10499                                         gst_pad_send_event(sinkpad, event);
10500                                 }
10501                         }
10502
10503                         gst_object_unref(sinkpad);
10504                         sinkpad = NULL;
10505                 }
10506                 gst_object_unref(srcpad);
10507                 srcpad = NULL;
10508
10509                 LOGD("selector release");
10510
10511                 /* release and unref requests pad from the selector */
10512                 for (n = 0; n < selector->channels->len; n++) {
10513                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10514                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10515                 }
10516                 g_ptr_array_set_size(selector->channels, 0);
10517
10518                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10519                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10520
10521                 player->pipeline->mainbin[selectorId].gst = NULL;
10522                 selector = NULL;
10523         }
10524
10525         return TRUE;
10526 }
10527
10528 static void
10529 __mmplayer_deactivate_old_path(mm_player_t *player)
10530 {
10531         MMPLAYER_FENTER();
10532         MMPLAYER_RETURN_IF_FAIL(player);
10533
10534         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10535                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10536                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10537                 LOGE("deactivate selector error");
10538                 goto ERROR;
10539         }
10540
10541         _mmplayer_track_destroy(player);
10542         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10543
10544         if (player->streamer) {
10545                 __mm_player_streaming_deinitialize(player->streamer);
10546                 __mm_player_streaming_destroy(player->streamer);
10547                 player->streamer = NULL;
10548         }
10549
10550         MMPLAYER_PLAYBACK_LOCK(player);
10551         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10552
10553         MMPLAYER_FLEAVE();
10554         return;
10555
10556 ERROR:
10557
10558         if (!player->msg_posted) {
10559                 MMMessageParamType msg = {0,};
10560
10561                 /*post error*/
10562                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10563                 LOGE("next_uri_play> deactivate error");
10564
10565                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10566                 player->msg_posted = TRUE;
10567         }
10568         return;
10569 }
10570
10571 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10572 {
10573         int result = MM_ERROR_NONE;
10574         mm_player_t* player = (mm_player_t*) hplayer;
10575         MMPLAYER_FENTER();
10576
10577         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10578
10579         if (file_path) {
10580                 player->http_file_buffering_path = (gchar*)file_path;
10581                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10582         }
10583         MMPLAYER_FLEAVE();
10584         return result;
10585 }
10586
10587 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10588 {
10589         int result = MM_ERROR_NONE;
10590         mm_player_t* player = (mm_player_t*) hplayer;
10591         MMPLAYER_FENTER();
10592
10593         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10594
10595         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10596         if (mmf_attrs_commit(player->attrs)) {
10597                 LOGE("failed to commit the original uri.\n");
10598                 result = MM_ERROR_PLAYER_INTERNAL;
10599         } else {
10600                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10601                         LOGE("failed to add the original uri in the uri list.\n");
10602         }
10603
10604         MMPLAYER_FLEAVE();
10605         return result;
10606 }
10607
10608 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10609 {
10610         mm_player_t* player = (mm_player_t*) hplayer;
10611         guint num_of_list = 0;
10612
10613         MMPLAYER_FENTER();
10614
10615         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10616         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10617
10618         if (player->pipeline && player->pipeline->textbin) {
10619                 LOGE("subtitle path is enabled.\n");
10620                 return MM_ERROR_PLAYER_INVALID_STATE;
10621         }
10622
10623         num_of_list = g_list_length(player->uri_info.uri_list);
10624
10625         if (is_first_path == TRUE) {
10626                 if (num_of_list == 0) {
10627                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10628                         LOGD("add original path : %s", uri);
10629                 } else {
10630                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10631                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10632
10633                         LOGD("change original path : %s", uri);
10634                 }
10635         } else {
10636                 MMHandleType attrs = 0;
10637                 attrs = MMPLAYER_GET_ATTRS(player);
10638
10639                 if (num_of_list == 0) {
10640                         char *original_uri = NULL;
10641
10642                         if (attrs) {
10643                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10644
10645                                 if (!original_uri) {
10646                                         LOGE("there is no original uri.");
10647                                         return MM_ERROR_PLAYER_INVALID_STATE;
10648                                 }
10649
10650                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10651                                 player->uri_info.uri_idx = 0;
10652
10653                                 LOGD("add original path at first : %s(%d)", original_uri);
10654                         }
10655                 }
10656
10657                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10658                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10659         }
10660
10661         MMPLAYER_FLEAVE();
10662         return MM_ERROR_NONE;
10663 }
10664
10665 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10666 {
10667         mm_player_t* player = (mm_player_t*) hplayer;
10668         char *next_uri = NULL;
10669         guint num_of_list = 0;
10670
10671         MMPLAYER_FENTER();
10672         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10673
10674         num_of_list = g_list_length(player->uri_info.uri_list);
10675
10676         if (num_of_list > 0) {
10677                 gint uri_idx = player->uri_info.uri_idx;
10678
10679                 if (uri_idx < num_of_list-1)
10680                         uri_idx++;
10681                 else
10682                         uri_idx = 0;
10683
10684                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10685                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10686
10687                 *uri = g_strdup(next_uri);
10688         }
10689
10690         MMPLAYER_FLEAVE();
10691         return MM_ERROR_NONE;
10692 }
10693
10694 static void
10695 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10696 GstCaps *caps, gpointer data)
10697 {
10698         mm_player_t* player = (mm_player_t*)data;
10699         const gchar* klass = NULL;
10700         const gchar* mime = NULL;
10701         gchar* caps_str = NULL;
10702
10703         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10704         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10705         caps_str = gst_caps_to_string(caps);
10706
10707         LOGW("unknown type of caps : %s from %s",
10708                                         caps_str, GST_ELEMENT_NAME(elem));
10709
10710         MMPLAYER_FREEIF(caps_str);
10711
10712         /* There is no available codec. */
10713         __mmplayer_check_not_supported_codec(player, klass, mime);
10714 }
10715
10716 static gboolean
10717 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10718 GstCaps * caps,  gpointer data)
10719 {
10720         mm_player_t* player = (mm_player_t*)data;
10721         const char* mime = NULL;
10722         gboolean ret = TRUE;
10723
10724         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10725         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10726
10727         if (g_str_has_prefix(mime, "audio")) {
10728                 GstStructure* caps_structure = NULL;
10729                 gint samplerate = 0;
10730                 gint channels = 0;
10731                 gchar *caps_str = NULL;
10732
10733                 caps_structure = gst_caps_get_structure(caps, 0);
10734                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10735                 gst_structure_get_int(caps_structure, "channels", &channels);
10736
10737                 if ((channels > 0 && samplerate == 0)) {
10738                         LOGD("exclude audio...");
10739                         ret = FALSE;
10740                 }
10741
10742                 caps_str = gst_caps_to_string(caps);
10743                 /* set it directly because not sent by TAG */
10744                 if (g_strrstr(caps_str, "mobile-xmf"))
10745                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10746                 MMPLAYER_FREEIF(caps_str);
10747         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10748                 MMMessageParamType msg_param;
10749                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10750                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10751                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10752                 LOGD("video file is not supported on this device");
10753                 ret = FALSE;
10754         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10755                 LOGD("already video linked");
10756                 ret = FALSE;
10757         } else {
10758                 LOGD("found new stream");
10759         }
10760
10761         return ret;
10762 }
10763
10764 static int
10765 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10766 {
10767         int ret = MM_ERROR_NONE;
10768         int idx = 0;
10769         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10770
10771         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10772                 GstStructure* str = NULL;
10773                 gint channels = 0;
10774                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10775
10776                 LOGD("audio codec type: %d", codec_type);
10777                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10778                         /* sw codec will be skipped */
10779                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10780                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10781                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10782                                         ret = MM_ERROR_PLAYER_INTERNAL;
10783                                         goto DONE;
10784                                 }
10785                         }
10786                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10787                         /* hw codec will be skipped */
10788                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10789                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10790                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10791                                 ret = MM_ERROR_PLAYER_INTERNAL;
10792                                 goto DONE;
10793                         }
10794                 }
10795
10796                 str = gst_caps_get_structure(caps, 0);
10797                 if (str) {
10798                         gst_structure_get_int(str, "channels", &channels);
10799
10800                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10801                         if (player->max_audio_channels < channels)
10802                                 player->max_audio_channels = channels;
10803                 }
10804                 /* set stream information */
10805                 if (!player->audiodec_linked)
10806                         __mmplayer_set_audio_attrs(player, caps);
10807
10808                 /* update codec info */
10809                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10810                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10811                 player->audiodec_linked = 1;
10812
10813         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10814
10815                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10816
10817                 LOGD("video codec type: %d", codec_type);
10818                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10819                         /* sw codec is skipped */
10820                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10821                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10822                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10823                                         ret = MM_ERROR_PLAYER_INTERNAL;
10824                                         goto DONE;
10825                                 }
10826                         }
10827                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10828                         /* hw codec is skipped */
10829                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10830                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10831                                 ret = MM_ERROR_PLAYER_INTERNAL;
10832                                 goto DONE;
10833                         }
10834                 }
10835
10836                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10837                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10838
10839                         /* mark video decoder for acquire */
10840                         if (player->video_decoder_resource == NULL) {
10841                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10842                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10843                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10844                                                 &player->video_decoder_resource)
10845                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10846                                         LOGE("could not mark video_decoder resource for acquire");
10847                                         ret = MM_ERROR_PLAYER_INTERNAL;
10848                                         goto DONE;
10849                                 }
10850                         } else {
10851                                 LOGW("video decoder resource is already acquired, skip it.");
10852                                 ret = MM_ERROR_PLAYER_INTERNAL;
10853                                 goto DONE;
10854                         }
10855
10856                         player->interrupted_by_resource = FALSE;
10857                         /* acquire resources for video playing */
10858                         if (mm_resource_manager_commit(player->resource_manager)
10859                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10860                                 LOGE("could not acquire resources for video decoding\n");
10861                                 ret = MM_ERROR_PLAYER_INTERNAL;
10862                                 goto DONE;
10863                         }
10864                 }
10865
10866                 /* update codec info */
10867                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10868                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10869                 player->videodec_linked = 1;
10870         }
10871
10872 DONE:
10873         return ret;
10874 }
10875
10876 static gint
10877 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10878 GstCaps* caps, GstElementFactory* factory, gpointer data)
10879 {
10880         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10881          We are defining our own and will be removed when it actually exposed */
10882         typedef enum {
10883                 GST_AUTOPLUG_SELECT_TRY,
10884                 GST_AUTOPLUG_SELECT_EXPOSE,
10885                 GST_AUTOPLUG_SELECT_SKIP
10886         } GstAutoplugSelectResult;
10887
10888         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10889         mm_player_t* player = (mm_player_t*)data;
10890
10891         gchar* factory_name = NULL;
10892         gchar* caps_str = NULL;
10893         const gchar* klass = NULL;
10894         gint idx = 0;
10895
10896         factory_name = GST_OBJECT_NAME(factory);
10897         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10898         caps_str = gst_caps_to_string(caps);
10899
10900         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10901
10902         /* store type string */
10903         if (player->type == NULL) {
10904                 player->type = gst_caps_to_string(caps);
10905                 __mmplayer_update_content_type_info(player);
10906         }
10907
10908         /* filtering exclude keyword */
10909         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10910                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10911                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10912                                         factory_name, player->ini.exclude_element_keyword[idx]);
10913
10914                         result = GST_AUTOPLUG_SELECT_SKIP;
10915                         goto DONE;
10916                 }
10917         }
10918
10919         /* exclude webm format */
10920         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10921          * because webm format is not supportable.
10922          * If webm is disabled in "autoplug-continue", there is no state change
10923          * failure or error because the decodebin will expose the pad directly.
10924          * It make MSL invoke _prepare_async_callback.
10925          * So, we need to disable webm format in "autoplug-select" */
10926         if (caps_str && strstr(caps_str, "webm")) {
10927                 LOGW("webm is not supported");
10928                 result = GST_AUTOPLUG_SELECT_SKIP;
10929                 goto DONE;
10930         }
10931
10932         /* check factory class for filtering */
10933         /* NOTE : msl don't need to use image plugins.
10934          * So, those plugins should be skipped for error handling.
10935          */
10936         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10937                 LOGD("skipping [%s] by not required\n", factory_name);
10938                 result = GST_AUTOPLUG_SELECT_SKIP;
10939                 goto DONE;
10940         }
10941
10942         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10943                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10944                 // TO CHECK : subtitle if needed, add subparse exception.
10945                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10946                 result = GST_AUTOPLUG_SELECT_SKIP;
10947                 goto DONE;
10948         }
10949
10950         if (g_strrstr(factory_name, "mpegpsdemux")) {
10951                 LOGD("skipping PS container - not support\n");
10952                 result = GST_AUTOPLUG_SELECT_SKIP;
10953                 goto DONE;
10954         }
10955
10956         if (g_strrstr(factory_name, "mssdemux"))
10957                 player->smooth_streaming = TRUE;
10958
10959         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10960                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10961                 gint stype = 0;
10962                 gint width = 0;
10963                 GstStructure *str = NULL;
10964                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10965
10966                 /* don't make video because of not required */
10967                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10968                         (player->set_mode.media_packet_video_stream == FALSE)) {
10969                         LOGD("no video because it's not required. -> return expose");
10970                         result = GST_AUTOPLUG_SELECT_EXPOSE;
10971                         goto DONE;
10972                 }
10973
10974                 /* get w/h for omx state-tune */
10975                 /* FIXME: deprecated? */
10976                 str = gst_caps_get_structure(caps, 0);
10977                 gst_structure_get_int(str, "width", &width);
10978
10979                 if (width != 0) {
10980                         if (player->v_stream_caps) {
10981                                 gst_caps_unref(player->v_stream_caps);
10982                                 player->v_stream_caps = NULL;
10983                         }
10984
10985                         player->v_stream_caps = gst_caps_copy(caps);
10986                         LOGD("take caps for video state tune");
10987                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
10988                 }
10989         }
10990
10991         if (g_strrstr(klass, "Codec/Decoder")) {
10992                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
10993                         LOGD("skipping %s codec", factory_name);
10994                         result = GST_AUTOPLUG_SELECT_SKIP;
10995                         goto DONE;
10996                 }
10997         }
10998
10999 DONE:
11000         MMPLAYER_FREEIF(caps_str);
11001
11002         return result;
11003 }
11004
11005 static void
11006 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11007 gpointer data)
11008 {
11009         //mm_player_t* player = (mm_player_t*)data;
11010         GstCaps* caps = NULL;
11011
11012         LOGD("[Decodebin2] pad-removed signal\n");
11013
11014         caps = gst_pad_query_caps(new_pad, NULL);
11015         if (caps) {
11016                 gchar* caps_str = NULL;
11017                 caps_str = gst_caps_to_string(caps);
11018
11019                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11020
11021                 MMPLAYER_FREEIF(caps_str);
11022                 gst_caps_unref(caps);
11023         }
11024 }
11025
11026 static void
11027 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11028 {
11029         mm_player_t* player = (mm_player_t*)data;
11030         GstIterator *iter = NULL;
11031         GValue item = { 0, };
11032         GstPad *pad = NULL;
11033         gboolean done = FALSE;
11034         gboolean is_all_drained = TRUE;
11035
11036         MMPLAYER_FENTER();
11037         MMPLAYER_RETURN_IF_FAIL(player);
11038
11039         LOGD("__mmplayer_gst_decode_drained");
11040
11041         if (player->use_deinterleave == TRUE) {
11042                 LOGD("group playing mode.");
11043                 return;
11044         }
11045
11046         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11047                 LOGW("Fail to get cmd lock");
11048                 return;
11049         }
11050
11051         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11052                 !__mmplayer_verify_next_play_path(player)) {
11053                 LOGD("decoding is finished.");
11054                 __mmplayer_reset_gapless_state(player);
11055                 MMPLAYER_CMD_UNLOCK(player);
11056                 return;
11057         }
11058
11059         player->gapless.reconfigure = TRUE;
11060
11061         /* check decodebin src pads whether they received EOS or not */
11062         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11063
11064         while (!done) {
11065                 switch (gst_iterator_next(iter, &item)) {
11066                 case GST_ITERATOR_OK:
11067                         pad = g_value_get_object(&item);
11068                         if (pad && !GST_PAD_IS_EOS(pad)) {
11069                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11070                                 is_all_drained = FALSE;
11071                                 break;
11072                         }
11073                         g_value_reset(&item);
11074                         break;
11075                 case GST_ITERATOR_RESYNC:
11076                         gst_iterator_resync(iter);
11077                         break;
11078                 case GST_ITERATOR_ERROR:
11079                 case GST_ITERATOR_DONE:
11080                         done = TRUE;
11081                         break;
11082                 }
11083         }
11084         g_value_unset(&item);
11085         gst_iterator_free(iter);
11086
11087         if (!is_all_drained) {
11088                 LOGD("Wait util the all pads get EOS.");
11089                 MMPLAYER_CMD_UNLOCK(player);
11090                 MMPLAYER_FLEAVE();
11091                 return;
11092         }
11093
11094         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11095         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11096
11097         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11098         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11099         __mmplayer_deactivate_old_path(player);
11100         MMPLAYER_CMD_UNLOCK(player);
11101
11102         MMPLAYER_FLEAVE();
11103 }
11104
11105 static void
11106 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11107 {
11108         mm_player_t* player = (mm_player_t*)data;
11109         const gchar* klass = NULL;
11110         gchar* factory_name = NULL;
11111
11112         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11113         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11114
11115         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11116
11117         if (__mmplayer_add_dump_buffer_probe(player, element))
11118                 LOGD("add buffer probe");
11119
11120         //<-
11121         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11122                 gchar* selected = NULL;
11123                 selected = g_strdup(GST_ELEMENT_NAME(element));
11124                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11125         }
11126         //-> temp code
11127
11128         if (g_strrstr(klass, "Parser")) {
11129                 gchar* selected = NULL;
11130
11131                 selected = g_strdup(factory_name);
11132                 player->parsers = g_list_append(player->parsers, selected);
11133         }
11134
11135         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11136                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11137                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11138
11139                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11140                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11141
11142                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11143                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11144                                                 "max-video-width", player->adaptive_info.limit.width,
11145                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11146
11147         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11148                 /* FIXIT : first value will be overwritten if there's more
11149                  * than 1 demuxer/parser
11150                  */
11151
11152                 //LOGD("plugged element is demuxer. take it\n");
11153                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11154                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11155
11156                 /*Added for multi audio support */ // Q. del?
11157                 if (g_strrstr(klass, "Demux")) {
11158                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11159                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11160                 }
11161         }
11162
11163         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11164                 int surface_type = 0;
11165
11166                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11167         }
11168
11169         // to support trust-zone only
11170         if (g_strrstr(factory_name, "asfdemux")) {
11171                 LOGD("set file-location %s\n", player->profile.uri);
11172                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11173
11174                 if (player->video_hub_download_mode == TRUE)
11175                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11176         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11177                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11178                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11179         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11180                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11181                         (__mmplayer_is_only_mp3_type(player->type))) {
11182                         LOGD("[mpegaudioparse] set streaming pull mode.");
11183                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11184                 }
11185         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11186                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11187         }
11188
11189         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11190                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11191                 LOGD("plugged element is multiqueue. take it\n");
11192
11193                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11194                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11195
11196                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11197                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11198                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11199                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11200                         __mm_player_streaming_set_multiqueue(player->streamer,
11201                                 element,
11202                                 TRUE,
11203                                 player->ini.http_buffering_time,
11204                                 1.0,
11205                                 player->ini.http_buffering_limit);
11206
11207                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11208                 }
11209         }
11210
11211         return;
11212 }
11213
11214 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11215 {
11216         MMPLAYER_FENTER();
11217         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11218
11219         if (MMPLAYER_IS_STREAMING(player))
11220                 return FALSE;
11221
11222         /* This callback can be set to music player only. */
11223         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11224                 LOGW("audio callback is not supported for video");
11225                 return FALSE;
11226         }
11227
11228         if (player->audio_stream_cb) {
11229                 GstPad *pad = NULL;
11230
11231                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11232
11233                 if (!pad) {
11234                         LOGE("failed to get sink pad from audiosink to probe data\n");
11235                         return FALSE;
11236                 }
11237                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11238                         __mmplayer_audio_stream_probe, player, NULL);
11239
11240                 gst_object_unref(pad);
11241
11242                 pad = NULL;
11243         } else {
11244                 LOGE("There is no audio callback to configure.\n");
11245                 return FALSE;
11246         }
11247
11248         MMPLAYER_FLEAVE();
11249
11250         return TRUE;
11251 }
11252
11253 static void
11254 __mmplayer_release_misc(mm_player_t* player)
11255 {
11256         int i;
11257         bool cur_mode = player->set_mode.rich_audio;
11258         MMPLAYER_FENTER();
11259
11260         MMPLAYER_RETURN_IF_FAIL(player);
11261
11262         player->video_stream_cb = NULL;
11263         player->video_stream_cb_user_param = NULL;
11264         player->video_stream_prerolled = FALSE;
11265
11266         player->audio_stream_cb = NULL;
11267         player->audio_stream_render_cb_ex = NULL;
11268         player->audio_stream_cb_user_param = NULL;
11269         player->audio_stream_sink_sync = false;
11270
11271         player->video_stream_changed_cb = NULL;
11272         player->video_stream_changed_cb_user_param = NULL;
11273
11274         player->audio_stream_changed_cb = NULL;
11275         player->audio_stream_changed_cb_user_param = NULL;
11276
11277         player->sent_bos = FALSE;
11278         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11279
11280         player->doing_seek = FALSE;
11281
11282         player->total_bitrate = 0;
11283         player->total_maximum_bitrate = 0;
11284
11285         player->not_found_demuxer = 0;
11286
11287         player->last_position = 0;
11288         player->duration = 0;
11289         player->http_content_size = 0;
11290         player->not_supported_codec = MISSING_PLUGIN_NONE;
11291         player->can_support_codec = FOUND_PLUGIN_NONE;
11292         player->pending_seek.is_pending = FALSE;
11293         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11294         player->pending_seek.pos = 0;
11295         player->msg_posted = FALSE;
11296         player->has_many_types = FALSE;
11297         player->max_audio_channels = 0;
11298         player->video_share_api_delta = 0;
11299         player->video_share_clock_delta = 0;
11300         player->is_subtitle_force_drop = FALSE;
11301         player->play_subtitle = FALSE;
11302         player->adjust_subtitle_pos = 0;
11303         player->last_multiwin_status = FALSE;
11304         player->has_closed_caption = FALSE;
11305         player->set_mode.media_packet_video_stream = FALSE;
11306         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11307         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11308         /* recover mode */
11309         player->set_mode.rich_audio = cur_mode;
11310
11311         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11312                 player->bitrate[i] = 0;
11313                 player->maximum_bitrate[i] = 0;
11314         }
11315
11316         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11317
11318         /* remove media stream cb(appsrc cb) */
11319         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11320                 player->media_stream_buffer_status_cb[i] = NULL;
11321                 player->media_stream_seek_data_cb[i] = NULL;
11322                 player->buffer_cb_user_param[i] = NULL;
11323                 player->seek_cb_user_param[i] = NULL;
11324         }
11325         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11326
11327         /* free memory related to audio effect */
11328         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11329
11330         if (player->adaptive_info.var_list) {
11331                 g_list_free_full(player->adaptive_info.var_list, g_free);
11332                 player->adaptive_info.var_list = NULL;
11333         }
11334
11335         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11336         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11337         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11338
11339         /* Reset video360 settings to their defaults in case if the pipeline is to be
11340          * re-created.
11341          * */
11342         player->video360_metadata.is_spherical = -1;
11343         player->is_openal_plugin_used = FALSE;
11344
11345         player->is_content_spherical = FALSE;
11346         player->is_video360_enabled = TRUE;
11347         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11348         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11349         player->video360_yaw_radians = 4;
11350         player->video360_pitch_radians = 4;
11351         player->video360_zoom = 1.0f;
11352         player->video360_horizontal_fov = 0;
11353         player->video360_vertical_fov = 0;
11354
11355         player->sound.rg_enable = false;
11356
11357         MMPLAYER_FLEAVE();
11358 }
11359
11360 static void
11361 __mmplayer_release_misc_post(mm_player_t* player)
11362 {
11363         char *original_uri = NULL;
11364         MMPLAYER_FENTER();
11365
11366         /* player->pipeline is already released before. */
11367
11368         MMPLAYER_RETURN_IF_FAIL(player);
11369
11370         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11371
11372         /* clean found parsers */
11373         if (player->parsers) {
11374                 GList *parsers = player->parsers;
11375                 for (; parsers; parsers = g_list_next(parsers)) {
11376                         gchar *name = parsers->data;
11377                         MMPLAYER_FREEIF(name);
11378                 }
11379                 g_list_free(player->parsers);
11380                 player->parsers = NULL;
11381         }
11382
11383         /* clean found audio decoders */
11384         if (player->audio_decoders) {
11385                 GList *a_dec = player->audio_decoders;
11386                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11387                         gchar *name = a_dec->data;
11388                         MMPLAYER_FREEIF(name);
11389                 }
11390                 g_list_free(player->audio_decoders);
11391                 player->audio_decoders = NULL;
11392         }
11393
11394         /* clean the uri list except original uri */
11395         if (player->uri_info.uri_list) {
11396                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11397
11398                 if (player->attrs) {
11399                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11400                         LOGD("restore original uri = %s\n", original_uri);
11401
11402                         if (mmf_attrs_commit(player->attrs))
11403                                 LOGE("failed to commit the original uri.\n");
11404                 }
11405
11406                 GList *uri_list = player->uri_info.uri_list;
11407                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11408                         gchar *uri = uri_list->data;
11409                         MMPLAYER_FREEIF(uri);
11410                 }
11411                 g_list_free(player->uri_info.uri_list);
11412                 player->uri_info.uri_list = NULL;
11413         }
11414
11415         /* clear the audio stream buffer list */
11416         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11417
11418         /* clear the video stream bo list */
11419         __mmplayer_video_stream_destroy_bo_list(player);
11420         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11421
11422         if (player->profile.input_mem.buf) {
11423                 free(player->profile.input_mem.buf);
11424                 player->profile.input_mem.buf = NULL;
11425         }
11426         player->profile.input_mem.len = 0;
11427         player->profile.input_mem.offset = 0;
11428
11429         player->uri_info.uri_idx = 0;
11430         MMPLAYER_FLEAVE();
11431 }
11432
11433 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11434 {
11435         GstElement *element = NULL;
11436         GstPad *sinkpad;
11437
11438         LOGD("creating %s to plug\n", name);
11439
11440         element = gst_element_factory_make(name, NULL);
11441         if (!element) {
11442                 LOGE("failed to create queue\n");
11443                 return NULL;
11444         }
11445
11446         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11447                 LOGE("failed to set state READY to %s\n", name);
11448                 gst_object_unref(element);
11449                 return NULL;
11450         }
11451
11452         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11453                 LOGE("failed to add %s\n", name);
11454                 gst_object_unref(element);
11455                 return NULL;
11456         }
11457
11458         sinkpad = gst_element_get_static_pad(element, "sink");
11459
11460         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11461                 LOGE("failed to link %s\n", name);
11462                 gst_object_unref(sinkpad);
11463                 gst_object_unref(element);
11464                 return NULL;
11465         }
11466
11467         LOGD("linked %s to pipeline successfully\n", name);
11468
11469         gst_object_unref(sinkpad);
11470
11471         return element;
11472 }
11473
11474 gboolean
11475 __mmplayer_check_subtitle(mm_player_t* player)
11476 {
11477         MMHandleType attrs = 0;
11478         char *subtitle_uri = NULL;
11479
11480         MMPLAYER_FENTER();
11481
11482         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11483
11484         /* get subtitle attribute */
11485         attrs = MMPLAYER_GET_ATTRS(player);
11486         if (!attrs)
11487                 return FALSE;
11488
11489         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11490         if (!subtitle_uri || !strlen(subtitle_uri))
11491                 return FALSE;
11492
11493         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11494         player->is_external_subtitle_present = TRUE;
11495
11496         MMPLAYER_FLEAVE();
11497
11498         return TRUE;
11499 }
11500
11501 static gboolean
11502 __mmplayer_can_extract_pcm(mm_player_t* player)
11503 {
11504         MMHandleType attrs = 0;
11505         gboolean sound_extraction = FALSE;
11506
11507         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11508
11509         attrs = MMPLAYER_GET_ATTRS(player);
11510         if (!attrs) {
11511                 LOGE("fail to get attributes.");
11512                 return FALSE;
11513         }
11514
11515         /* get sound_extraction property */
11516         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11517
11518         if (!sound_extraction) {
11519                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11520                 return FALSE;
11521         }
11522
11523         return TRUE;
11524 }
11525
11526 static gboolean
11527 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11528 {
11529         LOGD("\n");
11530         MMMessageParamType msg_param;
11531         gchar *msg_src_element = NULL;
11532         GstStructure *s = NULL;
11533         guint error_id = 0;
11534         gchar *error_string = NULL;
11535
11536         MMPLAYER_FENTER();
11537
11538         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11539         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11540
11541         s = gst_structure_copy(gst_message_get_structure(message));
11542
11543
11544         if (!gst_structure_get_uint(s, "error_id", &error_id))
11545                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11546
11547         switch (error_id) {
11548         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11549                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11550                 break;
11551         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11552                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11553                 break;
11554         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11555                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11556                 break;
11557         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11558                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11559                 break;
11560         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11561                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11562                 break;
11563         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11564                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11565                 break;
11566         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11567                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11568                 break;
11569         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11570                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11571                 break;
11572         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11573                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11574                 break;
11575         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11576                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11577                 break;
11578         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11579                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11580                 break;
11581         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11582                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11583                 break;
11584         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11585                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11586                 break;
11587         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11588                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11589                 break;
11590         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11591                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11592                 break;
11593         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11594                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11595                 break;
11596         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11597                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11598                 break;
11599         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11600                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11601                 break;
11602         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11603                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11604                 break;
11605         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11606                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11607                 break;
11608         case MMPLAYER_STREAMING_ERROR_GONE:
11609                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11610                 break;
11611         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11612                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11613                 break;
11614         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11615                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11616                 break;
11617         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11618                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11619                 break;
11620         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11621                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11622                 break;
11623         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11624                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11625                 break;
11626         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11627                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11628                 break;
11629         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11630                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11631                 break;
11632         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11633                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11634                 break;
11635         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11636                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11637                 break;
11638         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11639                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11640                 break;
11641         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11642                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11643                 break;
11644         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11645                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11646                 break;
11647         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11648                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11649                 break;
11650         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11651                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11652                 break;
11653         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11654                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11655                 break;
11656         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11657                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11658                 break;
11659         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11660                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11661                 break;
11662         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11663                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11664                 break;
11665         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11666                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11667                 break;
11668         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11669                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11670                 break;
11671         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11672                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11673                 break;
11674         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11675                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11676                 break;
11677         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11678                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11679                 break;
11680         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11681                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11682                 break;
11683         default:
11684                 {
11685                         gst_structure_free(s);
11686                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11687                 }
11688         }
11689
11690         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11691         if (error_string)
11692                 msg_param.data = (void *) error_string;
11693
11694         if (message->src) {
11695                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11696
11697                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11698                         msg_src_element, msg_param.code, (char*)msg_param.data);
11699         }
11700
11701         /* post error to application */
11702         if (!player->msg_posted) {
11703                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11704
11705                 /* don't post more if one was sent already */
11706                 player->msg_posted = TRUE;
11707         } else
11708                 LOGD("skip error post because it's sent already.\n");
11709
11710         gst_structure_free(s);
11711         MMPLAYER_FLEAVE();
11712         g_free(error_string);
11713
11714         return TRUE;
11715
11716 }
11717
11718 static void
11719 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11720 {
11721         MMPLAYER_RETURN_IF_FAIL(player);
11722
11723         /* post now if delay is zero */
11724         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11725                 LOGD("eos delay is zero. posting EOS now\n");
11726                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11727
11728                 if (player->set_mode.pcm_extraction)
11729                         __mmplayer_cancel_eos_timer(player);
11730
11731                 return;
11732         }
11733
11734         /* cancel if existing */
11735         __mmplayer_cancel_eos_timer(player);
11736
11737         /* init new timeout */
11738         /* NOTE : consider give high priority to this timer */
11739         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11740
11741         player->eos_timer = g_timeout_add(delay_in_ms,
11742                 __mmplayer_eos_timer_cb, player);
11743
11744         player->global_default = g_main_context_default();
11745         LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11746
11747         /* check timer is valid. if not, send EOS now */
11748         if (player->eos_timer == 0) {
11749                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11750                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11751         }
11752 }
11753
11754 static void
11755 __mmplayer_cancel_eos_timer(mm_player_t* player)
11756 {
11757         MMPLAYER_RETURN_IF_FAIL(player);
11758
11759         if (player->eos_timer) {
11760                 LOGD("cancel eos timer");
11761                 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11762                 player->eos_timer = 0;
11763         }
11764
11765         return;
11766 }
11767
11768 static gboolean
11769 __mmplayer_eos_timer_cb(gpointer u_data)
11770 {
11771         mm_player_t* player = NULL;
11772         MMHandleType attrs = 0;
11773         int count = 0;
11774
11775         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11776
11777         player = (mm_player_t*) u_data;
11778         attrs = MMPLAYER_GET_ATTRS(player);
11779
11780         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11781
11782         if (count == -1) {
11783                 gint ret_value = 0;
11784                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11785                 if (ret_value != MM_ERROR_NONE) {
11786                         LOGE("seeking to 0 failed in repeat play");
11787                 }
11788         } else {
11789                 /* posting eos */
11790                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11791         }
11792
11793         /* we are returning FALSE as we need only one posting */
11794         return FALSE;
11795 }
11796
11797 /* sending event to one of sinkelements */
11798 static gboolean
11799 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11800 {
11801         GstEvent * event2 = NULL;
11802         GList *sinks = NULL;
11803         gboolean res = FALSE;
11804         MMPLAYER_FENTER();
11805
11806         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11807         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11808
11809         /* While adding subtitles in live feeds seek is getting called.
11810            Adding defensive check in framework layer.*/
11811         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11812                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11813                         LOGE("Should not send seek event during live playback");
11814                         return TRUE;
11815                 }
11816         }
11817
11818         if (player->play_subtitle)
11819                 event2 = gst_event_copy((const GstEvent *)event);
11820
11821         sinks = player->sink_elements;
11822         while (sinks) {
11823                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11824
11825                 if (GST_IS_ELEMENT(sink)) {
11826                         /* keep ref to the event */
11827                         gst_event_ref(event);
11828
11829                         if ((res = gst_element_send_event(sink, event))) {
11830                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11831                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11832
11833                                 /* rtsp case, asyn_done is not called after seek during pause state */
11834                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11835                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11836                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11837                                                         LOGD("RTSP seek completed, after pause state..\n");
11838                                                         player->doing_seek = FALSE;
11839                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11840                                                 }
11841
11842                                         }
11843                                 }
11844
11845                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11846                                         sinks = g_list_next(sinks);
11847                                         continue;
11848                                 } else {
11849                                         break;
11850                                 }
11851                         }
11852
11853                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11854                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11855                 }
11856
11857                 sinks = g_list_next(sinks);
11858         }
11859
11860         /* Note : Textbin is not linked to the video or audio bin.
11861          * It needs to send the event to the text sink seperatelly.
11862          */
11863          if (player->play_subtitle && player->pipeline) {
11864                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11865
11866                 if (GST_IS_ELEMENT(text_sink)) {
11867                         /* keep ref to the event */
11868                         gst_event_ref(event2);
11869
11870                         if ((res = gst_element_send_event(text_sink, event2)))
11871                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11872                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11873                         else
11874                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11875                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11876
11877                         gst_event_unref(event2);
11878                 }
11879          }
11880
11881         gst_event_unref(event);
11882
11883         MMPLAYER_FLEAVE();
11884
11885         return res;
11886 }
11887
11888 static void
11889 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11890 {
11891         MMPLAYER_FENTER();
11892
11893         MMPLAYER_RETURN_IF_FAIL(player);
11894         MMPLAYER_RETURN_IF_FAIL(sink);
11895
11896         player->sink_elements =
11897                 g_list_append(player->sink_elements, sink);
11898
11899         MMPLAYER_FLEAVE();
11900 }
11901
11902 static void
11903 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11904 {
11905         MMPLAYER_FENTER();
11906
11907         MMPLAYER_RETURN_IF_FAIL(player);
11908         MMPLAYER_RETURN_IF_FAIL(sink);
11909
11910         player->sink_elements =
11911                         g_list_remove(player->sink_elements, sink);
11912
11913         MMPLAYER_FLEAVE();
11914 }
11915
11916 static gboolean
11917 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11918                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11919                         gint64 cur, GstSeekType stop_type, gint64 stop)
11920 {
11921         GstEvent* event = NULL;
11922         gboolean result = FALSE;
11923
11924         MMPLAYER_FENTER();
11925
11926         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11927
11928         if (player->pipeline && player->pipeline->textbin)
11929                 __mmplayer_drop_subtitle(player, FALSE);
11930
11931         event = gst_event_new_seek(rate, format, flags, cur_type,
11932                 cur, stop_type, stop);
11933
11934         result = __gst_send_event_to_sink(player, event);
11935
11936         MMPLAYER_FLEAVE();
11937
11938         return result;
11939 }
11940
11941 /* NOTE : be careful with calling this api. please refer to below glib comment
11942  * glib comment : Note that there is a bug in GObject that makes this function much
11943  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11944  * will no longer be called, but, the signal handler is not currently disconnected.
11945  * If the instance is itself being freed at the same time than this doesn't matter,
11946  * since the signal will automatically be removed, but if instance persists,
11947  * then the signal handler will leak. You should not remove the signal yourself
11948  * because in a future versions of GObject, the handler will automatically be
11949  * disconnected.
11950  *
11951  * It's possible to work around this problem in a way that will continue to work
11952  * with future versions of GObject by checking that the signal handler is still
11953  * connected before disconnected it:
11954  *
11955  *  if (g_signal_handler_is_connected(instance, id))
11956  *    g_signal_handler_disconnect(instance, id);
11957  */
11958 static void
11959 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11960 {
11961         GList* sig_list = NULL;
11962         MMPlayerSignalItem* item = NULL;
11963
11964         MMPLAYER_FENTER();
11965
11966         MMPLAYER_RETURN_IF_FAIL(player);
11967
11968         LOGD("release signals type : %d", type);
11969
11970         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11971                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11972                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11973                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11974                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11975                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11976                 return;
11977         }
11978
11979         sig_list = player->signals[type];
11980
11981         for (; sig_list; sig_list = sig_list->next) {
11982                 item = sig_list->data;
11983
11984                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11985                         if (g_signal_handler_is_connected(item->obj, item->sig))
11986                                 g_signal_handler_disconnect(item->obj, item->sig);
11987                 }
11988
11989                 MMPLAYER_FREEIF(item);
11990         }
11991
11992         g_list_free(player->signals[type]);
11993         player->signals[type] = NULL;
11994
11995         MMPLAYER_FLEAVE();
11996
11997         return;
11998 }
11999
12000 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12001 {
12002         mm_player_t* player = 0;
12003         int prev_display_surface_type = 0;
12004         void *prev_display_overlay = NULL;
12005         const gchar *klass = NULL;
12006         gchar *cur_videosink_name = NULL;
12007         int ret = 0;
12008         int i = 0;
12009         int num_of_dec = 2; /* DEC1, DEC2 */
12010
12011         MMPLAYER_FENTER();
12012
12013         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12014         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12015
12016         player = MM_PLAYER_CAST(handle);
12017
12018         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12019                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12020                 MMPLAYER_FLEAVE();
12021                 return MM_ERROR_INVALID_ARGUMENT;
12022         }
12023
12024         /* load previous attributes */
12025         if (player->attrs) {
12026                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12027                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12028                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12029                 if (prev_display_surface_type == surface_type) {
12030                         LOGD("incoming display surface type is same as previous one, do nothing..");
12031                         MMPLAYER_FLEAVE();
12032                         return MM_ERROR_NONE;
12033                 }
12034         } else {
12035                 LOGE("failed to load attributes");
12036                 MMPLAYER_FLEAVE();
12037                 return MM_ERROR_PLAYER_INTERNAL;
12038         }
12039
12040         /* check videosink element is created */
12041         if (!player->pipeline || !player->pipeline->videobin ||
12042                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12043                 LOGD("videosink element is not yet ready");
12044
12045                 /* videobin is not created yet, so we just set attributes related to display surface */
12046                 LOGD("store display attribute for given surface type(%d)", surface_type);
12047                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12048                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12049                 if (mmf_attrs_commit(player->attrs)) {
12050                         LOGE("failed to commit attribute");
12051                         MMPLAYER_FLEAVE();
12052                         return MM_ERROR_PLAYER_INTERNAL;
12053                 }
12054                 MMPLAYER_FLEAVE();
12055                 return MM_ERROR_NONE;
12056         } else {
12057                 /* get player command status */
12058                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12059                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12060                         MMPLAYER_FLEAVE();
12061                         return MM_ERROR_PLAYER_INVALID_STATE;
12062                 }
12063
12064                 /* surface change */
12065                 for (i = 0 ; i < num_of_dec ; i++) {
12066                         if (player->pipeline->mainbin &&
12067                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12068                                 GstElementFactory *decfactory;
12069                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12070
12071                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12072                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12073                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12074                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12075                                                 if (ret) {
12076                                                         goto ERROR_CASE;
12077                                                 } else {
12078                                                         LOGW("success to changing display surface(%d)", surface_type);
12079                                                         MMPLAYER_FLEAVE();
12080                                                         return MM_ERROR_NONE;
12081                                                 }
12082                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12083                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12084                                                 if (ret) {
12085                                                         goto ERROR_CASE;
12086                                                 } else {
12087                                                         LOGW("success to changing display surface(%d)", surface_type);
12088                                                         MMPLAYER_FLEAVE();
12089                                                         return MM_ERROR_NONE;
12090                                                 }
12091                                         } else {
12092                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12093                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12094                                                 goto ERROR_CASE;
12095                                         }
12096                                 }
12097                         }
12098                 }
12099         }
12100
12101 ERROR_CASE:
12102         /* rollback to previous attributes */
12103         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12104         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12105         if (mmf_attrs_commit(player->attrs)) {
12106                 LOGE("failed to commit attributes to rollback");
12107                 MMPLAYER_FLEAVE();
12108                 return MM_ERROR_PLAYER_INTERNAL;
12109         }
12110         MMPLAYER_FLEAVE();
12111         return ret;
12112 }
12113
12114 /* NOTE : It does not support some use cases, eg using colorspace converter */
12115 int
12116 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12117 {
12118         GstPad *src_pad_dec = NULL;
12119         GstPad *sink_pad_videosink = NULL;
12120         GstPad *sink_pad_videobin = NULL;
12121         GstClock *clock = NULL;
12122         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12123         int ret = MM_ERROR_NONE;
12124         gboolean is_audiobin_created = TRUE;
12125
12126         MMPLAYER_FENTER();
12127
12128         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12129         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12130         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12131
12132         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12133         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12134
12135         /* get information whether if audiobin is created */
12136         if (!player->pipeline->audiobin ||
12137                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12138                 LOGW("audiobin is null, this video content may not have audio data");
12139                 is_audiobin_created = FALSE;
12140         }
12141
12142         /* get current state of player */
12143         previous_state = MMPLAYER_CURRENT_STATE(player);
12144         LOGD("previous state(%d)", previous_state);
12145
12146
12147         /* get src pad of decoder and block it */
12148         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12149         if (!src_pad_dec) {
12150                 LOGE("failed to get src pad from decode in mainbin");
12151                 return MM_ERROR_PLAYER_INTERNAL;
12152         }
12153
12154         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12155                 LOGW("trying to block pad(video)");
12156 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12157                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12158                         NULL, NULL, NULL);
12159                 {
12160                         LOGE("failed to set block pad(video)");
12161                         return MM_ERROR_PLAYER_INTERNAL;
12162                 }
12163                 LOGW("pad is blocked(video)");
12164         } else {
12165                 /* no data flows, so no need to do pad_block */
12166                 if (player->doing_seek)
12167                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12168
12169                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12170         }
12171
12172         /* remove pad */
12173         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12174                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12175                 LOGE("failed to remove previous ghost_pad for videobin");
12176                 return MM_ERROR_PLAYER_INTERNAL;
12177         }
12178
12179         /* change state of videobin to NULL */
12180         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12181         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12182         if (ret != GST_STATE_CHANGE_SUCCESS) {
12183                 LOGE("failed to change state of videobin to NULL");
12184                 return MM_ERROR_PLAYER_INTERNAL;
12185         }
12186
12187         /* unlink between decoder and videobin and remove previous videosink from videobin */
12188         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12189         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12190                 LOGE("failed to remove former videosink from videobin");
12191                 return MM_ERROR_PLAYER_INTERNAL;
12192         }
12193
12194         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12195
12196         /* create a new videosink and add it to videobin */
12197         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12198         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12199                 LOGE("failed to create videosink element\n");
12200                 MMPLAYER_FLEAVE();
12201                 return MM_ERROR_PLAYER_INTERNAL;
12202         }
12203         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12204         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12205         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12206
12207         /* save attributes */
12208         if (player->attrs) {
12209                 /* set a new display surface type */
12210                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12211                 /* set a new diplay overlay */
12212                 switch (surface_type) {
12213                 case MM_DISPLAY_SURFACE_OVERLAY:
12214                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12215                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12216                         break;
12217                 default:
12218                         LOGE("invalid type(%d) for changing display surface", surface_type);
12219                         MMPLAYER_FLEAVE();
12220                         return MM_ERROR_INVALID_ARGUMENT;
12221                 }
12222                 if (mmf_attrs_commit(player->attrs)) {
12223                         LOGE("failed to commit");
12224                         MMPLAYER_FLEAVE();
12225                         return MM_ERROR_PLAYER_INTERNAL;
12226                 }
12227         } else {
12228                 LOGE("player->attrs is null, failed to save attributes");
12229                 MMPLAYER_FLEAVE();
12230                 return MM_ERROR_PLAYER_INTERNAL;
12231         }
12232
12233         /* update video param */
12234         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12235                 LOGE("failed to update video param");
12236                 return MM_ERROR_PLAYER_INTERNAL;
12237         }
12238
12239         /* change state of videobin to READY */
12240         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12241         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12242         if (ret != GST_STATE_CHANGE_SUCCESS) {
12243                 LOGE("failed to change state of videobin to READY");
12244                 return MM_ERROR_PLAYER_INTERNAL;
12245         }
12246
12247         /* change ghostpad */
12248         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12249         if (!sink_pad_videosink) {
12250                 LOGE("failed to get sink pad from videosink element");
12251                 return MM_ERROR_PLAYER_INTERNAL;
12252         }
12253         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12254         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12255                 LOGE("failed to set active to ghost_pad");
12256                 return MM_ERROR_PLAYER_INTERNAL;
12257         }
12258         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12259                 LOGE("failed to change ghostpad for videobin");
12260                 return MM_ERROR_PLAYER_INTERNAL;
12261         }
12262         gst_object_unref(sink_pad_videosink);
12263
12264         /* link decoder with videobin */
12265         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12266         if (!sink_pad_videobin) {
12267                 LOGE("failed to get sink pad from videobin");
12268                 return MM_ERROR_PLAYER_INTERNAL;
12269         }
12270         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12271                 LOGE("failed to link");
12272                 return MM_ERROR_PLAYER_INTERNAL;
12273         }
12274         gst_object_unref(sink_pad_videobin);
12275
12276         /* clock setting for a new videosink plugin */
12277         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12278                         so we set it from audiosink plugin or pipeline(system clock) */
12279         if (!is_audiobin_created) {
12280                 LOGW("audiobin is not created, get clock from pipeline..");
12281                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12282         } else {
12283                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12284         }
12285         if (clock) {
12286                 GstClockTime now;
12287                 GstClockTime base_time;
12288                 LOGD("set the clock to videosink");
12289                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12290                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12291                 if (clock) {
12292                         LOGD("got clock of videosink");
12293                         now = gst_clock_get_time(clock);
12294                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12295                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12296                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12297                 } else {
12298                         LOGE("failed to get clock of videosink after setting clock");
12299                         return MM_ERROR_PLAYER_INTERNAL;
12300                 }
12301         } else
12302                 LOGW("failed to get clock, maybe it is the time before first playing");
12303
12304         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12305                 /* change state of videobin to PAUSED */
12306                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12307                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12308                 if (ret != GST_STATE_CHANGE_FAILURE) {
12309                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12310                 } else {
12311                         LOGE("failed to change state of videobin to PLAYING");
12312                         return MM_ERROR_PLAYER_INTERNAL;
12313                 }
12314
12315                 /* release blocked and unref src pad of video decoder */
12316                 #if 0
12317                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12318                         LOGE("failed to set pad blocked FALSE(video)");
12319                         return MM_ERROR_PLAYER_INTERNAL;
12320                 }
12321                 #endif
12322                 LOGW("pad is unblocked(video)");
12323         } else {
12324                 if (player->doing_seek)
12325                         LOGW("not completed seek(%d)", player->doing_seek);
12326                 /* change state of videobin to PAUSED */
12327                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12328                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12329                 if (ret != GST_STATE_CHANGE_FAILURE) {
12330                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12331                 } else {
12332                         LOGE("failed to change state of videobin to PLAYING");
12333                         return MM_ERROR_PLAYER_INTERNAL;
12334                 }
12335
12336                 /* already skipped pad block */
12337                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12338         }
12339
12340         /* do get/set position for new videosink plugin */
12341         {
12342                 unsigned long position = 0;
12343                 gint64 pos_msec = 0;
12344
12345                 LOGD("do get/set position for new videosink plugin");
12346                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12347                         LOGE("failed to get position");
12348                         return MM_ERROR_PLAYER_INTERNAL;
12349                 }
12350 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12351                 /* accurate seek */
12352                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12353                         LOGE("failed to set position");
12354                         return MM_ERROR_PLAYER_INTERNAL;
12355                 }
12356 #else
12357                 /* key unit seek */
12358                 pos_msec = position * G_GINT64_CONSTANT(1000000);
12359                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12360                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12361                                                         GST_SEEK_TYPE_SET, pos_msec,
12362                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12363                 if (!ret) {
12364                         LOGE("failed to set position");
12365                         return MM_ERROR_PLAYER_INTERNAL;
12366                 }
12367 #endif
12368         }
12369
12370         if (src_pad_dec)
12371                 gst_object_unref(src_pad_dec);
12372         LOGD("success to change sink");
12373
12374         MMPLAYER_FLEAVE();
12375
12376         return MM_ERROR_NONE;
12377 }
12378
12379
12380 /* Note : if silent is true, then subtitle would not be displayed. :*/
12381 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12382 {
12383         mm_player_t* player = (mm_player_t*) hplayer;
12384
12385         MMPLAYER_FENTER();
12386
12387         /* check player handle */
12388         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12389
12390         player->set_mode.subtitle_off = silent;
12391
12392         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12393
12394         MMPLAYER_FLEAVE();
12395
12396         return MM_ERROR_NONE;
12397 }
12398
12399 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12400 {
12401         MMPlayerGstElement* mainbin = NULL;
12402         MMPlayerGstElement* textbin = NULL;
12403         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12404         GstState current_state = GST_STATE_VOID_PENDING;
12405         GstState element_state = GST_STATE_VOID_PENDING;
12406         GstState element_pending_state = GST_STATE_VOID_PENDING;
12407         gint64 time = 0;
12408         GstEvent *event = NULL;
12409         int result = MM_ERROR_NONE;
12410
12411         GstClock *curr_clock = NULL;
12412         GstClockTime base_time, start_time, curr_time;
12413
12414
12415         MMPLAYER_FENTER();
12416
12417         /* check player handle */
12418         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12419                                                                 player->pipeline &&
12420                                                                 player->pipeline->mainbin &&
12421                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12422
12423         mainbin = player->pipeline->mainbin;
12424         textbin = player->pipeline->textbin;
12425
12426         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12427
12428         // sync clock with current pipeline
12429         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12430         curr_time = gst_clock_get_time(curr_clock);
12431
12432         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12433         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12434
12435         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12436                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12437
12438         if (current_state > GST_STATE_READY) {
12439                 // sync state with current pipeline
12440                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12441                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12442                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12443
12444                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12445                 if (GST_STATE_CHANGE_FAILURE == ret) {
12446                         LOGE("fail to state change.\n");
12447                         result = MM_ERROR_PLAYER_INTERNAL;
12448                         goto ERROR;
12449                 }
12450         }
12451
12452         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12453         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12454
12455         if (curr_clock) {
12456                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12457                 gst_object_unref(curr_clock);
12458         }
12459
12460         // seek to current position
12461         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12462                 result = MM_ERROR_PLAYER_INVALID_STATE;
12463                 LOGE("gst_element_query_position failed, invalid state\n");
12464                 goto ERROR;
12465         }
12466
12467         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12468         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);
12469         if (event) {
12470                 __gst_send_event_to_sink(player, event);
12471         } else {
12472                 result = MM_ERROR_PLAYER_INTERNAL;
12473                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12474                 goto ERROR;
12475         }
12476
12477         /* sync state with current pipeline */
12478         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12479         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12480         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12481
12482         return MM_ERROR_NONE;
12483
12484 ERROR:
12485         /* release text pipeline resource */
12486         player->textsink_linked = 0;
12487
12488         /* release signal */
12489         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12490
12491         /* release textbin with it's childs */
12492         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12493         MMPLAYER_FREEIF(player->pipeline->textbin);
12494         player->pipeline->textbin = NULL;
12495
12496         /* release subtitle elem */
12497         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12498         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12499
12500         return result;
12501 }
12502
12503 static int
12504 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12505 {
12506         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12507         GstState current_state = GST_STATE_VOID_PENDING;
12508
12509         MMHandleType attrs = 0;
12510         MMPlayerGstElement* mainbin = NULL;
12511         MMPlayerGstElement* textbin = NULL;
12512
12513         gchar* subtitle_uri = NULL;
12514         int result = MM_ERROR_NONE;
12515         const gchar *charset = NULL;
12516
12517         MMPLAYER_FENTER();
12518
12519         /* check player handle */
12520         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12521                                                                 player->pipeline &&
12522                                                                 player->pipeline->mainbin &&
12523                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12524         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12525
12526         mainbin = player->pipeline->mainbin;
12527         textbin = player->pipeline->textbin;
12528
12529         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12530         if (current_state < GST_STATE_READY) {
12531                 result = MM_ERROR_PLAYER_INVALID_STATE;
12532                 LOGE("Pipeline is not in proper state\n");
12533                 goto EXIT;
12534         }
12535
12536         attrs = MMPLAYER_GET_ATTRS(player);
12537         if (!attrs) {
12538                 LOGE("cannot get content attribute\n");
12539                 result = MM_ERROR_PLAYER_INTERNAL;
12540                 goto EXIT;
12541         }
12542
12543         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12544         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12545                 LOGE("subtitle uri is not proper filepath\n");
12546                 result = MM_ERROR_PLAYER_INVALID_URI;
12547                 goto EXIT;
12548         }
12549
12550         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12551                 LOGE("failed to get storage info of subtitle path");
12552                 result = MM_ERROR_PLAYER_INVALID_URI;
12553                 goto EXIT;
12554         }
12555
12556         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12557         LOGD("new subtitle file path is [%s]\n", filepath);
12558
12559         if (!strcmp(filepath, subtitle_uri)) {
12560                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12561                 goto EXIT;
12562         } else {
12563                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12564                 if (mmf_attrs_commit(player->attrs)) {
12565                         LOGE("failed to commit.\n");
12566                         goto EXIT;
12567                 }
12568         }
12569
12570         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12571         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12572         player->subtitle_language_list = NULL;
12573         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12574
12575         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12576         if (ret != GST_STATE_CHANGE_SUCCESS) {
12577                 LOGE("failed to change state of textbin to READY");
12578                 result = MM_ERROR_PLAYER_INTERNAL;
12579                 goto EXIT;
12580         }
12581
12582         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12583         if (ret != GST_STATE_CHANGE_SUCCESS) {
12584                 LOGE("failed to change state of subparse to READY");
12585                 result = MM_ERROR_PLAYER_INTERNAL;
12586                 goto EXIT;
12587         }
12588
12589         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12590         if (ret != GST_STATE_CHANGE_SUCCESS) {
12591                 LOGE("failed to change state of filesrc to READY");
12592                 result = MM_ERROR_PLAYER_INTERNAL;
12593                 goto EXIT;
12594         }
12595
12596         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12597
12598         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12599
12600         charset = util_get_charset(filepath);
12601         if (charset) {
12602                 LOGD("detected charset is %s\n", charset);
12603                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12604         }
12605
12606         result = _mmplayer_sync_subtitle_pipeline(player);
12607
12608 EXIT:
12609         MMPLAYER_FLEAVE();
12610         return result;
12611 }
12612
12613 /* API to switch between external subtitles */
12614 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12615 {
12616         int result = MM_ERROR_NONE;
12617         mm_player_t* player = (mm_player_t*)hplayer;
12618         char *path = NULL;
12619
12620         MMPLAYER_FENTER();
12621
12622         /* check player handle */
12623         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12624
12625         /* filepath can be null in idle state */
12626         if (filepath) {
12627                 /* check file path */
12628                 if ((path = strstr(filepath, "file://")))
12629                         result = util_exist_file_path(path + 7);
12630                 else
12631                         result = util_exist_file_path(filepath);
12632
12633                 if (result != MM_ERROR_NONE) {
12634                         LOGE("invalid subtitle path 0x%X", result);
12635                         return result; /* file not found or permission denied */
12636                 }
12637         }
12638
12639         if (!player->pipeline) {
12640                 /* IDLE state */
12641                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12642                 if (mmf_attrs_commit(player->attrs)) {
12643                         LOGE("failed to commit");       /* subtitle path will not be created */
12644                         return MM_ERROR_PLAYER_INTERNAL;
12645                 }
12646         } else {
12647                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12648                 /* check filepath */
12649                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12650
12651                 if (!__mmplayer_check_subtitle(player)) {
12652                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12653                         if (mmf_attrs_commit(player->attrs)) {
12654                                 LOGE("failed to commit");
12655                                 return MM_ERROR_PLAYER_INTERNAL;
12656                         }
12657
12658                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12659                                 LOGE("fail to create text pipeline");
12660                                 return MM_ERROR_PLAYER_INTERNAL;
12661                         }
12662
12663                         result = _mmplayer_sync_subtitle_pipeline(player);
12664                 } else {
12665                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12666                 }
12667
12668                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12669                 player->is_external_subtitle_added_now = TRUE;
12670
12671                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12672                 if (!player->subtitle_language_list) {
12673                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12674                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12675                                 LOGW("subtitle language list is not updated yet");
12676                 }
12677                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12678         }
12679
12680         MMPLAYER_FLEAVE();
12681         return result;
12682 }
12683
12684 static int
12685 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12686 {
12687         int result = MM_ERROR_NONE;
12688         gchar* change_pad_name = NULL;
12689         GstPad* sinkpad = NULL;
12690         MMPlayerGstElement* mainbin = NULL;
12691         enum MainElementID elemId = MMPLAYER_M_NUM;
12692         GstCaps* caps = NULL;
12693         gint total_track_num = 0;
12694
12695         MMPLAYER_FENTER();
12696
12697         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12698                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12699
12700         LOGD("Change Track(%d) to %d\n", type, index);
12701
12702         mainbin = player->pipeline->mainbin;
12703
12704         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12705                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12706         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12707                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12708         } else {
12709                 /* Changing Video Track is not supported. */
12710                 LOGE("Track Type Error\n");
12711                 goto EXIT;
12712         }
12713
12714         if (mainbin[elemId].gst == NULL) {
12715                 result = MM_ERROR_PLAYER_NO_OP;
12716                 LOGD("Req track doesn't exist\n");
12717                 goto EXIT;
12718         }
12719
12720         total_track_num = player->selector[type].total_track_num;
12721         if (total_track_num <= 0) {
12722                 result = MM_ERROR_PLAYER_NO_OP;
12723                 LOGD("Language list is not available \n");
12724                 goto EXIT;
12725         }
12726
12727         if ((index < 0) || (index >= total_track_num)) {
12728                 result = MM_ERROR_INVALID_ARGUMENT;
12729                 LOGD("Not a proper index : %d \n", index);
12730                 goto EXIT;
12731         }
12732
12733         /*To get the new pad from the selector*/
12734         change_pad_name = g_strdup_printf("sink_%u", index);
12735         if (change_pad_name == NULL) {
12736                 result = MM_ERROR_PLAYER_INTERNAL;
12737                 LOGD("Pad does not exists\n");
12738                 goto EXIT;
12739         }
12740
12741         LOGD("new active pad name: %s\n", change_pad_name);
12742
12743         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12744         if (sinkpad == NULL) {
12745                 LOGD("sinkpad is NULL");
12746                 result = MM_ERROR_PLAYER_INTERNAL;
12747                 goto EXIT;
12748         }
12749
12750         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12751         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12752
12753         caps = gst_pad_get_current_caps(sinkpad);
12754         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12755
12756         if (sinkpad)
12757                 gst_object_unref(sinkpad);
12758
12759         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12760                 __mmplayer_set_audio_attrs(player, caps);
12761
12762 EXIT:
12763
12764         MMPLAYER_FREEIF(change_pad_name);
12765         return result;
12766 }
12767
12768 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12769 {
12770         int result = MM_ERROR_NONE;
12771         mm_player_t* player = NULL;
12772         MMPlayerGstElement* mainbin = NULL;
12773
12774         gint current_active_index = 0;
12775
12776         GstState current_state = GST_STATE_VOID_PENDING;
12777         GstEvent* event = NULL;
12778         gint64 time = 0;
12779
12780         MMPLAYER_FENTER();
12781
12782         player = (mm_player_t*)hplayer;
12783         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12784
12785         if (!player->pipeline) {
12786                 LOGE("Track %d pre setting -> %d\n", type, index);
12787
12788                 player->selector[type].active_pad_index = index;
12789                 goto EXIT;
12790         }
12791
12792         mainbin = player->pipeline->mainbin;
12793
12794         current_active_index = player->selector[type].active_pad_index;
12795
12796         /*If index is same as running index no need to change the pad*/
12797         if (current_active_index == index)
12798                 goto EXIT;
12799
12800         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12801                 result = MM_ERROR_PLAYER_INVALID_STATE;
12802                 goto EXIT;
12803         }
12804
12805         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12806         if (current_state < GST_STATE_PAUSED) {
12807                 result = MM_ERROR_PLAYER_INVALID_STATE;
12808                 LOGW("Pipeline not in porper state\n");
12809                 goto EXIT;
12810         }
12811
12812         result = __mmplayer_change_selector_pad(player, type, index);
12813         if (result != MM_ERROR_NONE) {
12814                 LOGE("change selector pad error\n");
12815                 goto EXIT;
12816         }
12817
12818         player->selector[type].active_pad_index = index;
12819
12820         if (current_state == GST_STATE_PLAYING) {
12821                 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);
12822                 if (event) {
12823                         __gst_send_event_to_sink(player, event);
12824                 } else {
12825                         result = MM_ERROR_PLAYER_INTERNAL;
12826                         goto EXIT;
12827                 }
12828         }
12829
12830 EXIT:
12831         return result;
12832 }
12833
12834 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12835 {
12836         mm_player_t* player = (mm_player_t*) hplayer;
12837
12838         MMPLAYER_FENTER();
12839
12840         /* check player handle */
12841         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12842
12843         *silent = player->set_mode.subtitle_off;
12844
12845         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12846
12847         MMPLAYER_FLEAVE();
12848
12849         return MM_ERROR_NONE;
12850 }
12851
12852 gboolean
12853 __is_ms_buff_src(mm_player_t* player)
12854 {
12855         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12856
12857         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12858 }
12859
12860 gboolean
12861 __has_suffix(mm_player_t* player, const gchar* suffix)
12862 {
12863         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12864         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12865
12866         gboolean ret = FALSE;
12867         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12868         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12869
12870         if (g_str_has_suffix(player->profile.uri, suffix))
12871                 ret = TRUE;
12872
12873         MMPLAYER_FREEIF(t_url);
12874         MMPLAYER_FREEIF(t_suffix);
12875
12876         return ret;
12877 }
12878
12879 int
12880 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12881 {
12882         mm_player_t* player = (mm_player_t*) hplayer;
12883
12884         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12885
12886         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12887                 MMPLAYER_PRINT_STATE(player);
12888                 LOGE("wrong-state : can't set the download mode to parse");
12889                 return MM_ERROR_PLAYER_INVALID_STATE;
12890         }
12891
12892         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12893         player->video_hub_download_mode = mode;
12894
12895         return MM_ERROR_NONE;
12896 }
12897
12898 int
12899 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12900 {
12901         mm_player_t* player = (mm_player_t*) hplayer;
12902
12903         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12904
12905         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12906         player->sync_handler = enable;
12907
12908         return MM_ERROR_NONE;
12909 }
12910
12911 int
12912 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12913                                         long long clock,
12914                                         long long clock_delta,
12915                                         long long video_time,
12916                                         long long media_clock,
12917                                         long long audio_time)
12918 {
12919         mm_player_t* player = (mm_player_t*) hplayer;
12920         MMPlayerGstElement* mainbin = NULL;
12921         GstClockTime start_time_audio = 0, start_time_video = 0;
12922         GstClockTimeDiff base_time = 0, new_base_time = 0;
12923         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12924         gint64 api_delta = 0;
12925         gint64 position = 0, position_delta = 0;
12926         gint64 adj_base_time = 0;
12927         GstClock *curr_clock = NULL;
12928         GstClockTime curr_time = 0;
12929         gboolean query_ret = TRUE;
12930         int result = MM_ERROR_NONE;
12931
12932         MMPLAYER_FENTER();
12933
12934         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12935         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12936         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12937
12938         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12939
12940         if ((video_time < 0) || (player->doing_seek)) {
12941                 LOGD("skip setting master clock.  %lld", video_time);
12942                 goto EXIT;
12943         }
12944
12945         mainbin = player->pipeline->mainbin;
12946
12947         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12948         curr_time = gst_clock_get_time(curr_clock);
12949
12950         current_state = MMPLAYER_CURRENT_STATE(player);
12951
12952         if (current_state == MM_PLAYER_STATE_PLAYING)
12953                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12954
12955         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12956                 (!query_ret)) {
12957                 position = player->last_position;
12958                 LOGD("query fail. %lld", position);
12959         }
12960
12961         clock *= GST_USECOND;
12962         clock_delta *= GST_USECOND;
12963
12964         api_delta = clock - curr_time;
12965         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12966                 player->video_share_api_delta = api_delta;
12967         else
12968                 clock_delta += (api_delta - player->video_share_api_delta);
12969
12970         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12971                 player->video_share_clock_delta = (gint64)clock_delta;
12972
12973                 position_delta = (position/GST_USECOND) - video_time;
12974                 position_delta *= GST_USECOND;
12975
12976                 adj_base_time = position_delta;
12977                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12978
12979         } else {
12980                 gint64 new_play_time = 0;
12981                 gint64 network_delay = 0;
12982
12983                 video_time *= GST_USECOND;
12984
12985                 network_delay = clock_delta - player->video_share_clock_delta;
12986                 new_play_time = video_time + network_delay;
12987
12988                 adj_base_time = position - new_play_time;
12989
12990                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
12991                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
12992         }
12993
12994         /* Adjust Current Stream Time with base_time of sink
12995          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
12996          * 2. Set new base time
12997          *    if adj_base_time is positive value, the stream time will be decreased.
12998          * 3. If seek event is occurred, the start time will be reset. */
12999         if ((player->pipeline->audiobin) &&
13000                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13001                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13002
13003                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13004                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13005                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13006                 }
13007
13008                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13009         }
13010
13011         if ((player->pipeline->videobin) &&
13012                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13013                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13014
13015                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13016                         LOGD("video sink : gst_element_set_start_time -> NONE");
13017                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13018                 }
13019
13020                 // if videobin exist, get base_time from videobin.
13021                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13022         }
13023
13024         new_base_time = base_time + adj_base_time;
13025
13026         if ((player->pipeline->audiobin) &&
13027                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13028                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13029
13030         if ((player->pipeline->videobin) &&
13031                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13032                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13033
13034 EXIT:
13035         MMPLAYER_FLEAVE();
13036
13037         return result;
13038 }
13039
13040 int
13041 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13042                                         long long *video_time,
13043                                         long long *media_clock,
13044                                         long long *audio_time)
13045 {
13046         mm_player_t* player = (mm_player_t*) hplayer;
13047         MMPlayerGstElement* mainbin = NULL;
13048         GstClock *curr_clock = NULL;
13049         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13050         gint64 position = 0;
13051         gboolean query_ret = TRUE;
13052
13053         MMPLAYER_FENTER();
13054
13055         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13056         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13057         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13058
13059         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13060         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13061         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13062
13063         mainbin = player->pipeline->mainbin;
13064
13065         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13066
13067         current_state = MMPLAYER_CURRENT_STATE(player);
13068
13069         if (current_state != MM_PLAYER_STATE_PAUSED)
13070                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13071
13072         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13073                 (!query_ret))
13074                 position = player->last_position;
13075
13076         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13077
13078         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13079
13080         if (curr_clock)
13081                 gst_object_unref(curr_clock);
13082
13083         MMPLAYER_FLEAVE();
13084
13085         return MM_ERROR_NONE;
13086 }
13087
13088 static gboolean
13089 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13090 {
13091         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13092         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13093
13094         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13095         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13096
13097         int idx = 0;
13098
13099         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13100                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13101                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13102                         mm_player_dump_t *dump_s;
13103                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13104
13105                         if (dump_s == NULL) {
13106                                 LOGE("malloc fail");
13107                                 return FALSE;
13108                         }
13109
13110                         dump_s->dump_element_file = NULL;
13111                         dump_s->dump_pad = NULL;
13112                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13113
13114                         if (dump_s->dump_pad) {
13115                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13116                                 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]);
13117                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13118                                 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);
13119                                 /* add list for removed buffer probe and close FILE */
13120                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13121                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13122                                 return TRUE;
13123                         } else {
13124                                 g_free(dump_s);
13125                                 dump_s = NULL;
13126                                 LOGE("failed to get %s sink pad added", factory_name);
13127                         }
13128
13129
13130                 }
13131         }
13132         return FALSE;
13133 }
13134
13135 static GstPadProbeReturn
13136 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13137 {
13138         FILE *dump_data = (FILE *) u_data;
13139 //      int written = 0;
13140         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13141         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13142
13143         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13144
13145         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13146
13147 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13148
13149         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13150
13151         return GST_PAD_PROBE_OK;
13152 }
13153
13154 static void
13155 __mmplayer_release_dump_list(GList *dump_list)
13156 {
13157         if (dump_list) {
13158                 GList *d_list = dump_list;
13159                 for (; d_list; d_list = g_list_next(d_list)) {
13160                         mm_player_dump_t *dump_s = d_list->data;
13161                         if (dump_s->dump_pad) {
13162                                 if (dump_s->probe_handle_id)
13163                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13164                         }
13165                         if (dump_s->dump_element_file) {
13166                                 fclose(dump_s->dump_element_file);
13167                                 dump_s->dump_element_file = NULL;
13168                         }
13169                         MMPLAYER_FREEIF(dump_s);
13170                 }
13171                 g_list_free(dump_list);
13172                 dump_list = NULL;
13173         }
13174 }
13175
13176 int
13177 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13178 {
13179         mm_player_t* player = (mm_player_t*) hplayer;
13180
13181         MMPLAYER_FENTER();
13182
13183         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13184         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13185
13186         *exist = player->has_closed_caption;
13187
13188         MMPLAYER_FLEAVE();
13189
13190         return MM_ERROR_NONE;
13191 }
13192
13193 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13194 {
13195         MMPLAYER_FENTER();
13196         if (buffer) {
13197                 // LOGD("unref internal gst buffer %p", buffer);
13198                 gst_buffer_unref((GstBuffer *)buffer);
13199                 buffer = NULL;
13200         }
13201         MMPLAYER_FLEAVE();
13202 }
13203
13204 void
13205 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13206 {
13207         mm_player_t *player  = (mm_player_t*)user_data;
13208         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13209         guint64 current_level_bytes = 0;
13210
13211         MMPLAYER_RETURN_IF_FAIL(player);
13212
13213         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13214
13215         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13216         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13217
13218         if (player->media_stream_buffer_status_cb[type])
13219                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13220         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13221
13222 }
13223
13224 void
13225 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13226 {
13227         mm_player_t *player  = (mm_player_t*)user_data;
13228         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13229         guint64 current_level_bytes = 0;
13230
13231         MMPLAYER_RETURN_IF_FAIL(player);
13232
13233         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13234
13235         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13236
13237         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13238         if (player->media_stream_buffer_status_cb[type])
13239                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13240         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13241 }
13242
13243 void
13244 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13245 {
13246         mm_player_t *player  = (mm_player_t*)user_data;
13247         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13248         guint64 current_level_bytes = 0;
13249
13250         MMPLAYER_RETURN_IF_FAIL(player);
13251
13252         LOGI("app-src: feed subtitle\n");
13253
13254         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13255
13256         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13257         if (player->media_stream_buffer_status_cb[type])
13258                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13259
13260         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13261 }
13262
13263 void
13264 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13265 {
13266         mm_player_t *player  = (mm_player_t*)user_data;
13267         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13268         guint64 current_level_bytes = 0;
13269
13270         MMPLAYER_RETURN_IF_FAIL(player);
13271
13272         LOGI("app-src: audio buffer is full.\n");
13273
13274         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13275
13276         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13277
13278         if (player->media_stream_buffer_status_cb[type])
13279                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13280
13281         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13282 }
13283
13284 void
13285 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13286 {
13287         mm_player_t *player  = (mm_player_t*)user_data;
13288         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13289         guint64 current_level_bytes = 0;
13290
13291         MMPLAYER_RETURN_IF_FAIL(player);
13292
13293         LOGI("app-src: video buffer is full.\n");
13294
13295         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13296
13297         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13298         if (player->media_stream_buffer_status_cb[type])
13299                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13300
13301         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13302 }
13303
13304 gboolean
13305 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13306 {
13307         mm_player_t *player  = (mm_player_t*)user_data;
13308         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13309
13310         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13311
13312         LOGD("app-src: seek audio data %llu\n", position);
13313         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13314
13315         if (player->media_stream_seek_data_cb[type])
13316                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13317         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13318
13319         return TRUE;
13320 }
13321
13322 gboolean
13323 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13324 {
13325         mm_player_t *player  = (mm_player_t*)user_data;
13326         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13327
13328         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13329
13330         LOGD("app-src: seek video data %llu\n", position);
13331         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13332         if (player->media_stream_seek_data_cb[type])
13333                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13334         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13335
13336         return TRUE;
13337 }
13338
13339 gboolean
13340 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13341 {
13342         mm_player_t *player  = (mm_player_t*)user_data;
13343         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13344
13345         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13346
13347         LOGD("app-src: seek subtitle data\n");
13348         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13349
13350         if (player->media_stream_seek_data_cb[type])
13351                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13352         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13353
13354         return TRUE;
13355 }
13356
13357 int
13358 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13359 {
13360         mm_player_t* player = (mm_player_t*) hplayer;
13361
13362         MMPLAYER_FENTER();
13363
13364         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13365
13366         player->pcm_samplerate = samplerate;
13367         player->pcm_channel = channel;
13368
13369         MMPLAYER_FLEAVE();
13370         return MM_ERROR_NONE;
13371 }
13372
13373 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13374 {
13375         mm_player_t* player = (mm_player_t*) hplayer;
13376
13377         MMPLAYER_FENTER();
13378
13379         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13380         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13381
13382         if (MMPLAYER_IS_STREAMING(player))
13383                 *timeout = player->ini.live_state_change_timeout;
13384         else
13385                 *timeout = player->ini.localplayback_state_change_timeout;
13386
13387         LOGD("timeout = %d\n", *timeout);
13388
13389         MMPLAYER_FLEAVE();
13390         return MM_ERROR_NONE;
13391 }
13392
13393 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13394 {
13395         mm_player_t* player = (mm_player_t*) hplayer;
13396
13397         MMPLAYER_FENTER();
13398
13399         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13400         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13401
13402         *num = player->video_num_buffers;
13403         *extra_num = player->video_extra_num_buffers;
13404
13405         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13406
13407         MMPLAYER_FLEAVE();
13408         return MM_ERROR_NONE;
13409 }
13410
13411 static void
13412 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13413 {
13414         int i = 0;
13415         MMPLAYER_FENTER();
13416         MMPLAYER_RETURN_IF_FAIL(player);
13417
13418         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13419
13420                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13421                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13422                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13423                         player->storage_info[i].id = -1;
13424                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13425
13426                         if (path_type != MMPLAYER_PATH_MAX)
13427                                 break;
13428                 }
13429         }
13430
13431         MMPLAYER_FLEAVE();
13432 }
13433
13434 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13435 {
13436         int ret = MM_ERROR_NONE;
13437         mm_player_t* player = (mm_player_t*)hplayer;
13438         MMMessageParamType msg_param = {0, };
13439
13440         MMPLAYER_FENTER();
13441         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13442
13443         LOGW("state changed storage %d:%d", id, state);
13444
13445         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13446                 return MM_ERROR_NONE;
13447
13448         /* FIXME: text path should be handled seperately. */
13449         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13450                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13451                 LOGW("external storage is removed");
13452
13453                 if (player->msg_posted == FALSE) {
13454                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13455                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13456                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13457                         player->msg_posted = TRUE;
13458                 }
13459
13460                 /* unrealize the player */
13461                 ret = _mmplayer_unrealize(hplayer);
13462                 if (ret != MM_ERROR_NONE)
13463                         LOGE("failed to unrealize");
13464         }
13465
13466         MMPLAYER_FLEAVE();
13467         return ret;
13468 }
13469
13470 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13471 {
13472         int ret = MM_ERROR_NONE;
13473         mm_player_t* player = (mm_player_t*) hplayer;
13474         int idx = 0, total = 0;
13475         gchar *result = NULL, *tmp = NULL;
13476
13477         MMPLAYER_FENTER();
13478         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13479         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13480
13481         total = *num = g_list_length(player->adaptive_info.var_list);
13482         if (total <= 0) {
13483                 LOGW("There is no stream variant info.");
13484                 return ret;
13485         }
13486
13487         result = g_strdup("");
13488         for (idx = 0 ; idx < total ; idx++) {
13489                 VariantData *v_data = NULL;
13490                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13491
13492                 if (v_data) {
13493                         gchar data[64] = {0};
13494                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13495
13496                         tmp = g_strconcat(result, data, NULL);
13497                         g_free(result);
13498                         result = tmp;
13499                 } else {
13500                         LOGW("There is no variant data in %d", idx);
13501                         (*num)--;
13502                 }
13503         }
13504
13505         *var_info = (char *)result;
13506
13507         LOGD("variant info %d:%s", *num, *var_info);
13508         MMPLAYER_FLEAVE();
13509         return ret;
13510 }
13511
13512 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13513 {
13514         int ret = MM_ERROR_NONE;
13515         mm_player_t* player = (mm_player_t*) hplayer;
13516
13517         MMPLAYER_FENTER();
13518         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13519
13520         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13521
13522         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13523         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13524         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13525
13526         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13527                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13528                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13529                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13530
13531                 /* FIXME: seek to current position for applying new variant limitation */
13532         }
13533
13534         MMPLAYER_FLEAVE();
13535         return ret;
13536
13537 }
13538
13539 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13540 {
13541         int ret = MM_ERROR_NONE;
13542         mm_player_t* player = (mm_player_t*) hplayer;
13543
13544         MMPLAYER_FENTER();
13545         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13546         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13547
13548         *bandwidth = player->adaptive_info.limit.bandwidth;
13549         *width = player->adaptive_info.limit.width;
13550         *height = player->adaptive_info.limit.height;
13551
13552         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13553
13554         MMPLAYER_FLEAVE();
13555         return ret;
13556 }
13557
13558 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13559 {
13560         int ret = MM_ERROR_NONE;
13561         mm_player_t* player = (mm_player_t*) hplayer;
13562
13563         MMPLAYER_FENTER();
13564         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13565
13566         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13567                 LOGW("buffer_ms will not be applied.");
13568
13569
13570         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13571
13572         if (player->streamer == NULL) {
13573                 player->streamer = __mm_player_streaming_create();
13574                 __mm_player_streaming_initialize(player->streamer);
13575         }
13576
13577         if (buffer_ms >= 0)
13578                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13579
13580         if (rebuffer_ms >= 0)
13581                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13582
13583         MMPLAYER_FLEAVE();
13584         return ret;
13585
13586 }
13587
13588 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13589 {
13590         int ret = MM_ERROR_NONE;
13591         mm_player_t* player = (mm_player_t*) hplayer;
13592
13593         MMPLAYER_FENTER();
13594         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13595         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13596
13597         if (player->streamer == NULL) {
13598                 player->streamer = __mm_player_streaming_create();
13599                 __mm_player_streaming_initialize(player->streamer);
13600         }
13601
13602         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13603         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13604
13605         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13606
13607         MMPLAYER_FLEAVE();
13608         return ret;
13609 }
13610
13611 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13612 {
13613 #define IDX_FIRST_SW_CODEC 0
13614         mm_player_t* player = (mm_player_t*) hplayer;
13615         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13616         MMHandleType attrs = 0;
13617
13618         MMPLAYER_FENTER();
13619         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13620
13621         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13622                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13623                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13624
13625         switch (stream_type) {
13626         case MM_PLAYER_STREAM_TYPE_AUDIO:
13627                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13628                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13629                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13630                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13631                         LOGE("There is no a codec for codec_type %d", codec_type);
13632                         return MM_ERROR_PLAYER_NO_OP;
13633                 }
13634         break;
13635         case MM_PLAYER_STREAM_TYPE_VIDEO:
13636                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13637                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13638                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13639                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13640                         LOGE("There is no v codec for codec_type %d", codec_type);
13641                         return MM_ERROR_PLAYER_NO_OP;
13642                 }
13643
13644         break;
13645         default:
13646                 LOGE("Invalid stream type %d", stream_type);
13647                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13648         break;
13649         }
13650
13651         LOGD("update %s codec_type to %d", attr_name, codec_type);
13652
13653         attrs = MMPLAYER_GET_ATTRS(player);
13654         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13655
13656         if (mmf_attrs_commit(player->attrs)) {
13657                 LOGE("failed to commit codec_type attributes");
13658                 return MM_ERROR_PLAYER_INTERNAL;
13659         }
13660
13661         MMPLAYER_FLEAVE();
13662         return MM_ERROR_NONE;
13663 }
13664
13665 int
13666 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13667 {
13668         mm_player_t* player = (mm_player_t*) hplayer;
13669         GstElement* rg_vol_element = NULL;
13670
13671         MMPLAYER_FENTER();
13672
13673         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13674
13675         player->sound.rg_enable = enabled;
13676
13677         /* just hold rgvolume enable value if pipeline is not ready */
13678         if (!player->pipeline || !player->pipeline->audiobin) {
13679                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13680                 return MM_ERROR_NONE;
13681         }
13682
13683         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13684
13685         if (!rg_vol_element) {
13686                 LOGD("rgvolume element is not created");
13687                 return MM_ERROR_PLAYER_INTERNAL;
13688         }
13689
13690         if (enabled)
13691                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13692         else
13693                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13694
13695         MMPLAYER_FLEAVE();
13696
13697         return MM_ERROR_NONE;
13698 }
13699
13700 int
13701 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13702 {
13703         mm_player_t* player = (mm_player_t*) hplayer;
13704         GstElement* rg_vol_element = NULL;
13705         gboolean enable = FALSE;
13706
13707         MMPLAYER_FENTER();
13708
13709         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13710         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13711
13712         /* just hold enable_rg value if pipeline is not ready */
13713         if (!player->pipeline || !player->pipeline->audiobin) {
13714                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13715                 *enabled = player->sound.rg_enable;
13716                 return MM_ERROR_NONE;
13717         }
13718
13719         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13720
13721         if (!rg_vol_element) {
13722                 LOGD("rgvolume element is not created");
13723                 return MM_ERROR_PLAYER_INTERNAL;
13724         }
13725
13726         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13727         *enabled = enable;
13728
13729         MMPLAYER_FLEAVE();
13730
13731         return MM_ERROR_NONE;
13732 }