[0.6.119] support force resume during buffering
[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 /* For PD mode */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE             1024 * 1024 * 3
103
104 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
108
109 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
139
140 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
146 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157
158 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
159 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
175
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
189
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
193
194 static int              __gst_realize(mm_player_t* player);
195 static int              __gst_unrealize(mm_player_t* player);
196 static int              __gst_start(mm_player_t* player);
197 static int              __gst_stop(mm_player_t* player);
198 static int              __gst_pause(mm_player_t* player, gboolean async);
199 static int              __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202                                         gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
204
205 static int              __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int              __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
210
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
212
213 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
214 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
215
216 /* util */
217 static gboolean __is_ms_buff_src(mm_player_t* player);
218 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
219
220 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
221 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
222 static int __mmplayer_start_streaming_ext(mm_player_t *player);
223 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
224 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
225
226 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
227 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
228 static void __mmplayer_check_pipeline(mm_player_t* player);
229 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
230 static void __mmplayer_deactivate_old_path(mm_player_t *player);
231
232 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
233 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
234
235 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
236 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
237 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
238 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
239 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
240 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
241 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
242 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
246 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
247 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
248 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
249 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
250 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
251
252 /*===========================================================================================
253 |                                                                                                                                                                                       |
254 |  FUNCTION DEFINITIONS                                                                                                                                         |
255 |                                                                                                                                                                                       |
256 ========================================================================================== */
257
258 #if 0 //debug
259 static void
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
261 {
262         gint i, count;
263
264         count = gst_tag_list_get_tag_size(list, tag);
265
266         LOGD("count = %d", count);
267
268         for (i = 0; i < count; i++) {
269                 gchar *str;
270
271                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
273                                 g_assert_not_reached();
274                 } else
275                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
276
277                 if (i == 0)
278                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
279                 else
280                         g_print("                 : %s\n", str);
281
282                 g_free(str);
283         }
284 }
285 #endif
286
287 /* This function should be called after the pipeline goes PAUSED or higher
288 state. */
289 gboolean
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
291 {
292         static gboolean has_duration = FALSE;
293         static gboolean has_video_attrs = FALSE;
294         static gboolean has_audio_attrs = FALSE;
295         static gboolean has_bitrate = FALSE;
296         gboolean missing_only = FALSE;
297         gboolean all = FALSE;
298         gint64 dur_nsec = 0;
299         GstStructure* p = NULL;
300         MMHandleType attrs = 0;
301         gchar *path = NULL;
302         struct stat sb;
303
304         MMPLAYER_FENTER();
305
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
307
308         /* check player state here */
309         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311                 /* give warning now only */
312                 LOGW("be careful. content attributes may not available in this state ");
313         }
314
315         /* get content attribute first */
316         attrs = MMPLAYER_GET_ATTRS(player);
317         if (!attrs) {
318                 LOGE("cannot get content attribute");
319                 return FALSE;
320         }
321
322         /* get update flag */
323
324         if (flag & ATTR_MISSING_ONLY) {
325                 missing_only = TRUE;
326                 LOGD("updating missed attr only");
327         }
328
329         if (flag & ATTR_ALL) {
330                 all = TRUE;
331                 has_duration = FALSE;
332                 has_video_attrs = FALSE;
333                 has_audio_attrs = FALSE;
334                 has_bitrate = FALSE;
335
336                 LOGD("updating all attrs");
337         }
338
339         if (missing_only && all) {
340                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341                 missing_only = FALSE;
342         }
343
344         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345                 LOGD("try to update duration");
346                 has_duration = FALSE;
347
348                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349                         player->duration = dur_nsec;
350                         LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
351                         has_duration = TRUE;
352                 }
353
354                 if (player->duration < 0) {
355                         LOGW("duration is Non-Initialized !!!");
356                         player->duration = 0;
357                 }
358
359                 /* update streaming service type */
360                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
361
362                 /* check duration is OK */
363                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364                         /* FIXIT : find another way to get duration here. */
365                         LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
366                 }
367         }
368
369         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370                 /* update audio params
371                 NOTE : We need original audio params and it can be only obtained from src pad of audio
372                 decoder. Below code only valid when we are not using 'resampler' just before
373                 'audioconverter'. */
374
375                 LOGD("try to update audio attrs");
376                 has_audio_attrs = FALSE;
377
378                 if (player->pipeline->audiobin &&
379                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380                         GstCaps *caps_a = NULL;
381                         GstPad* pad = NULL;
382                         gint samplerate = 0, channels = 0;
383
384                         pad = gst_element_get_static_pad(
385                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
386
387                         if (pad) {
388                                 caps_a = gst_pad_get_current_caps(pad);
389
390                                 if (caps_a) {
391                                         p = gst_caps_get_structure(caps_a, 0);
392
393                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
394
395                                         gst_structure_get_int(p, "rate", &samplerate);
396                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
397
398                                         gst_structure_get_int(p, "channels", &channels);
399                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
400
401                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
402
403                                         gst_caps_unref(caps_a);
404                                         caps_a = NULL;
405
406                                         has_audio_attrs = TRUE;
407                                 } else
408                                         LOGW("not ready to get audio caps");
409
410                                 gst_object_unref(pad);
411                         } else
412                                 LOGW("failed to get pad from audiosink");
413                 }
414         }
415
416         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417                 LOGD("try to update video attrs");
418                 has_video_attrs = FALSE;
419
420                 if (player->pipeline->videobin &&
421                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422                         GstCaps *caps_v = NULL;
423                         GstPad* pad = NULL;
424                         gint tmpNu, tmpDe;
425                         gint width, height;
426
427                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
428                         if (pad) {
429                                 caps_v = gst_pad_get_current_caps(pad);
430
431                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432                                 if (!caps_v && player->v_stream_caps) {
433                                         caps_v = player->v_stream_caps;
434                                         gst_caps_ref(caps_v);
435                                 }
436
437                                 if (caps_v) {
438                                         p = gst_caps_get_structure(caps_v, 0);
439                                         gst_structure_get_int(p, "width", &width);
440                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
441
442                                         gst_structure_get_int(p, "height", &height);
443                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
444
445                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
446
447                                         SECURE_LOGD("width : %d     height : %d", width, height);
448
449                                         gst_caps_unref(caps_v);
450                                         caps_v = NULL;
451
452                                         if (tmpDe > 0) {
453                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
455                                         }
456
457                                         has_video_attrs = TRUE;
458                                 } else
459                                         LOGD("no negitiated caps from videosink");
460                                 gst_object_unref(pad);
461                                 pad = NULL;
462                         } else {
463                                 LOGD("no videosink sink pad");
464                         }
465                 }
466         }
467
468
469         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
470                 has_bitrate = FALSE;
471
472                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473                 if (player->duration) {
474                         guint64 data_size = 0;
475
476                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
478
479                                 if (stat(path, &sb) == 0)
480                                         data_size = (guint64)sb.st_size;
481                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482                                 data_size = player->http_content_size;
483                         }
484                         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
485
486                         if (data_size) {
487                                 guint64 bitrate = 0;
488                                 guint64 msec_dur = 0;
489
490                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
491                                 if (msec_dur > 0) {
492                                         bitrate = data_size * 8 * 1000 / msec_dur;
493                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
495
496                                         has_bitrate = TRUE;
497                                 } else {
498                                         LOGD("player duration is less than 0");
499                                 }
500                         }
501
502                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503                                 if (player->total_bitrate) {
504                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
505                                         has_bitrate = TRUE;
506                                 }
507                         }
508                 }
509         }
510
511         /* validate all */
512         if (mmf_attrs_commit(attrs)) {
513                 LOGE("failed to update attributes\n");
514                 return FALSE;
515         }
516
517         MMPLAYER_FLEAVE();
518
519         return TRUE;
520 }
521
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
523 {
524         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
525
526         MMPLAYER_FENTER();
527
528         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
529                         player->pipeline &&
530                         player->pipeline->mainbin &&
531                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532                         STREAMING_SERVICE_NONE);
533
534         /* streaming service type if streaming */
535         if (!MMPLAYER_IS_STREAMING(player))
536                 return STREAMING_SERVICE_NONE;
537
538         if (MMPLAYER_IS_HTTP_STREAMING(player))
539                 streaming_type = (player->duration == 0) ?
540                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
541
542         switch (streaming_type) {
543         case STREAMING_SERVICE_LIVE:
544                 LOGD("it's live streaming");
545                 break;
546         case STREAMING_SERVICE_VOD:
547                 LOGD("it's vod streaming");
548                 break;
549         default:
550                 LOGE("should not get here");
551                 break;
552         }
553
554         MMPLAYER_FLEAVE();
555
556         return streaming_type;
557 }
558
559
560 /* this function sets the player state and also report
561  * it to applicaton by calling callback function
562  */
563 int
564 __mmplayer_set_state(mm_player_t* player, int state)
565 {
566         MMMessageParamType msg = {0, };
567         gboolean post_bos = FALSE;
568
569         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
570
571         if (MMPLAYER_CURRENT_STATE(player) == state) {
572                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
574                 return MM_ERROR_NONE;
575         }
576
577         /* update player states */
578         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579         MMPLAYER_CURRENT_STATE(player) = state;
580
581         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
583
584         /* print state */
585         MMPLAYER_PRINT_STATE(player);
586
587         switch (MMPLAYER_CURRENT_STATE(player)) {
588         case MM_PLAYER_STATE_NULL:
589         case MM_PLAYER_STATE_READY:
590                 break;
591
592         case MM_PLAYER_STATE_PAUSED:
593                 {
594                         if (!player->sent_bos) {
595                                 /* rtsp case, get content attrs by GstMessage */
596                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597                                         /* it's first time to update all content attrs. */
598                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
599                                 }
600                         }
601
602                         /* add audio callback probe if condition is satisfied */
603                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604                                 __mmplayer_configure_audio_callback(player);
605
606                         /* FIXIT : handle return value */
607                 }
608                 break;
609
610         case MM_PLAYER_STATE_PLAYING:
611                 {
612                         /* try to get content metadata */
613                         if (!player->sent_bos) {
614                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
616                                  * legacy mmfw-player api */
617                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
618                         }
619
620                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621                                 if (!player->sent_bos)
622                                         __mmplayer_handle_missed_plugin(player);
623                         }
624
625                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626                                 /* initialize because auto resume is done well. */
627                                 player->resumed_by_rewind = FALSE;
628                                 player->playback_rate = 1.0;
629                         }
630
631                         if (!player->sent_bos) {
632                                 /* check audio codec field is set or not
633                                  * we can get it from typefinder or codec's caps.
634                                  */
635                                 gchar *audio_codec = NULL;
636                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
637
638                                 /* The codec format can't be sent for audio only case like amr, mid etc.
639                                  * Because, parser don't make related TAG.
640                                  * So, if it's not set yet, fill it with found data.
641                                  */
642                                 if (!audio_codec) {
643                                         if (g_strrstr(player->type, "audio/midi"))
644                                                 audio_codec = g_strdup("MIDI");
645                                         else if (g_strrstr(player->type, "audio/x-amr"))
646                                                 audio_codec = g_strdup("AMR");
647                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648                                                 audio_codec = g_strdup("AAC");
649                                         else
650                                                 audio_codec = g_strdup("unknown");
651                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
652
653                                         MMPLAYER_FREEIF(audio_codec);
654                                         if (mmf_attrs_commit(player->attrs))
655                                                 LOGE("failed to update attributes\n");
656
657                                         LOGD("set audio codec type with caps\n");
658                                 }
659
660                                 post_bos = TRUE;
661                         }
662                 }
663                 break;
664
665         case MM_PLAYER_STATE_NONE:
666         default:
667                 LOGW("invalid target state, there is nothing to do.\n");
668                 break;
669         }
670
671
672         /* post message to application */
673         if (MMPLAYER_TARGET_STATE(player) == state) {
674                 /* fill the message with state of player */
675                 msg.union_type = MM_MSG_UNION_STATE;
676                 msg.state.previous = MMPLAYER_PREV_STATE(player);
677                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
678
679                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
680
681                 /* state changed by resource callback */
682                 if (player->interrupted_by_resource) {
683                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
684                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
685                 } else { /* state changed by usecase */
686                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
687                 }
688         } else {
689                 LOGD("intermediate state, do nothing.\n");
690                 MMPLAYER_PRINT_STATE(player);
691                 return MM_ERROR_NONE;
692         }
693
694         if (post_bos) {
695                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
696                 player->sent_bos = TRUE;
697         }
698
699         return MM_ERROR_NONE;
700 }
701
702 static gpointer __mmplayer_next_play_thread(gpointer data)
703 {
704         mm_player_t* player = (mm_player_t*) data;
705         MMPlayerGstElement *mainbin = NULL;
706
707         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708
709         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
710         while (!player->next_play_thread_exit) {
711                 LOGD("next play thread started. waiting for signal.\n");
712                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
713
714                 LOGD("reconfigure pipeline for gapless play.\n");
715
716                 if (player->next_play_thread_exit) {
717                         if (player->gapless.reconfigure) {
718                                 player->gapless.reconfigure = false;
719                                 MMPLAYER_PLAYBACK_UNLOCK(player);
720                         }
721                         LOGD("exiting gapless play thread\n");
722                         break;
723                 }
724
725                 mainbin = player->pipeline->mainbin;
726
727                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
728                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
729                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
730                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
731                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732
733                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
734         }
735         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
736
737         return NULL;
738 }
739
740 static void
741 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
742 {
743         MMHandleType attrs = 0;
744         guint64 data_size = 0;
745         gchar* path = NULL;
746         gint64 pos_nsec = 0;
747         struct stat sb;
748
749         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
750
751         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec);       /* to update player->last_position */
752
753         attrs = MMPLAYER_GET_ATTRS(player);
754         if (!attrs) {
755                 LOGE("fail to get attributes.\n");
756                 return;
757         }
758
759         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
760                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
761
762                 if (stat(path, &sb) == 0)
763                         data_size = (guint64)sb.st_size;
764         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
765                 data_size = player->http_content_size;
766
767         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
768         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
769
770         return;
771 }
772
773 static int
774 __mmplayer_handle_buffering_message(mm_player_t* player)
775 {
776         int ret = MM_ERROR_NONE;
777         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
778         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
779         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
780         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
781
782         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
783                 LOGW("do nothing for buffering msg\n");
784                 ret = MM_ERROR_PLAYER_INVALID_STATE;
785                 goto exit;
786         }
787
788         prev_state = MMPLAYER_PREV_STATE(player);
789         current_state = MMPLAYER_CURRENT_STATE(player);
790         target_state = MMPLAYER_TARGET_STATE(player);
791         pending_state = MMPLAYER_PENDING_STATE(player);
792
793         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
794                 MMPLAYER_STATE_GET_NAME(prev_state),
795                 MMPLAYER_STATE_GET_NAME(current_state),
796                 MMPLAYER_STATE_GET_NAME(pending_state),
797                 MMPLAYER_STATE_GET_NAME(target_state),
798                 player->streamer->buffering_state);
799
800         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
801                 /* NOTE : if buffering has done, player has to go to target state. */
802                 switch (target_state) {
803                 case MM_PLAYER_STATE_PAUSED:
804                         {
805                                 switch (pending_state) {
806                                 case MM_PLAYER_STATE_PLAYING:
807                                         __gst_pause(player, TRUE);
808                                         break;
809
810                                 case MM_PLAYER_STATE_PAUSED:
811                                         LOGD("player is already going to paused state, there is nothing to do.\n");
812                                         break;
813
814                                 case MM_PLAYER_STATE_NONE:
815                                 case MM_PLAYER_STATE_NULL:
816                                 case MM_PLAYER_STATE_READY:
817                                 default:
818                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
819                                         break;
820                                 }
821                         }
822                         break;
823
824                 case MM_PLAYER_STATE_PLAYING:
825                         {
826                                 switch (pending_state) {
827                                 case MM_PLAYER_STATE_NONE:
828                                         {
829                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
830                                                         __gst_resume(player, TRUE);
831                                         }
832                                         break;
833
834                                 case MM_PLAYER_STATE_PAUSED:
835                                         /* NOTE: It should be worked as asynchronously.
836                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
837                                          */
838                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
839                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
840                                                  * The current state should be changed to paused purposely to prevent state conflict.
841                                                  */
842                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
843                                         }
844                                         __gst_resume(player, TRUE);
845                                         break;
846
847                                 case MM_PLAYER_STATE_PLAYING:
848                                         LOGD("player is already going to playing state, there is nothing to do.\n");
849                                         break;
850
851                                 case MM_PLAYER_STATE_NULL:
852                                 case MM_PLAYER_STATE_READY:
853                                 default:
854                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
855                                         break;
856                                 }
857                         }
858                         break;
859
860                 case MM_PLAYER_STATE_NULL:
861                 case MM_PLAYER_STATE_READY:
862                 case MM_PLAYER_STATE_NONE:
863                 default:
864                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
865                         break;
866                 }
867         } else {
868                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
869                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
870                  */
871                 switch (pending_state) {
872                 case MM_PLAYER_STATE_NONE:
873                         {
874                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
875                                         /* rtsp streaming pause makes rtsp server stop sending data. */
876                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
877                                                 LOGD("set pause state during buffering\n");
878                                                 __gst_pause(player, TRUE);
879                                         }
880                                 }
881                         }
882                         break;
883
884                 case MM_PLAYER_STATE_PLAYING:
885                         /* rtsp streaming pause makes rtsp server stop sending data. */
886                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
887                                 __gst_pause(player, TRUE);
888                         break;
889
890                 case MM_PLAYER_STATE_PAUSED:
891                         break;
892
893                 case MM_PLAYER_STATE_NULL:
894                 case MM_PLAYER_STATE_READY:
895                 default:
896                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
897                         break;
898                 }
899         }
900
901 exit:
902         return ret;
903 }
904
905 static void
906 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
907 {
908         MMPlayerGstElement *textbin;
909         MMPLAYER_FENTER();
910
911         MMPLAYER_RETURN_IF_FAIL(player &&
912                                         player->pipeline &&
913                                         player->pipeline->textbin);
914
915         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
916
917         textbin = player->pipeline->textbin;
918
919         if (is_drop) {
920                 LOGD("Drop subtitle text after getting EOS\n");
921
922                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
923                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
924
925                 player->is_subtitle_force_drop = TRUE;
926         } else {
927                 if (player->is_subtitle_force_drop == TRUE) {
928                         LOGD("Enable subtitle data path without drop\n");
929
930                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
931                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
932
933                         LOGD("non-connected with external display");
934
935                         player->is_subtitle_force_drop = FALSE;
936                 }
937         }
938 }
939
940 static VariantData *
941 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
942 {
943         VariantData *var_info = NULL;
944         g_return_val_if_fail(self != NULL, NULL);
945
946         var_info = g_new0(VariantData, 1);
947         if (!var_info) return NULL;
948         var_info->bandwidth = self->bandwidth;
949         var_info->width = self->width;
950         var_info->height = self->height;
951         return var_info;
952 }
953
954 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
955 {
956         mm_player_t* player = (mm_player_t*)hplayer;
957         GstMessage *msg = NULL;
958         GQueue *queue = NULL;
959
960         MMPLAYER_FENTER();
961         MMPLAYER_RETURN_IF_FAIL(player);
962
963         /* disconnecting bus watch */
964         if (player->bus_watcher)
965                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
966         player->bus_watcher = 0;
967
968         /* destroy the gst bus msg thread */
969         if (player->bus_msg_thread) {
970                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
971                 player->bus_msg_thread_exit = TRUE;
972                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
973                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
974
975                 LOGD("gst bus msg thread exit.");
976                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
977                 player->bus_msg_thread = NULL;
978
979                 g_mutex_clear(&player->bus_msg_thread_mutex);
980                 g_cond_clear(&player->bus_msg_thread_cond);
981         }
982
983         g_mutex_lock(&player->bus_msg_q_lock);
984         queue = player->bus_msg_q;
985         while (!g_queue_is_empty(queue)) {
986                 msg = (GstMessage *)g_queue_pop_head(queue);
987                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
988                 gst_message_unref(msg);
989         }
990         g_mutex_unlock(&player->bus_msg_q_lock);
991
992         MMPLAYER_FLEAVE();
993 }
994
995 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
996 {
997         mm_player_t *player = (mm_player_t *) data;
998
999         g_return_val_if_fail(player, FALSE);
1000         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1001
1002         gst_message_ref(msg);
1003
1004         g_mutex_lock(&player->bus_msg_q_lock);
1005         g_queue_push_tail(player->bus_msg_q, msg);
1006         g_mutex_unlock(&player->bus_msg_q_lock);
1007
1008         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1009         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1010         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1011         return TRUE;
1012 }
1013
1014 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1015 {
1016         mm_player_t *player = (mm_player_t*)(data);
1017         GstMessage *msg = NULL;
1018         GstBus *bus = NULL;
1019
1020         MMPLAYER_FENTER();
1021         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1022                                                 player->pipeline &&
1023                                                 player->pipeline->mainbin &&
1024                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1025                                                 NULL);
1026
1027         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1028         if (!bus) {
1029                 LOGE("cannot get BUS from the pipeline");
1030                 return NULL;
1031         }
1032
1033         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1034
1035         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1036         while (!player->bus_msg_thread_exit) {
1037                 g_mutex_lock(&player->bus_msg_q_lock);
1038                 msg = g_queue_pop_head(player->bus_msg_q);
1039                 g_mutex_unlock(&player->bus_msg_q_lock);
1040                 if (msg == NULL) {
1041                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1042                         continue;
1043                 }
1044                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1045                 /* handle the gst msg */
1046                 __mmplayer_gst_callback(msg, player);
1047                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1048                 gst_message_unref(msg);
1049         }
1050
1051         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1052         gst_object_unref(GST_OBJECT(bus));
1053
1054         MMPLAYER_FLEAVE();
1055         return NULL;
1056 }
1057
1058 static void
1059 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1060 {
1061         mm_player_t* player = (mm_player_t*)(data);
1062         static gboolean async_done = FALSE;
1063
1064         MMPLAYER_RETURN_IF_FAIL(player);
1065         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1066
1067         switch (GST_MESSAGE_TYPE(msg)) {
1068         case GST_MESSAGE_UNKNOWN:
1069                 LOGD("unknown message received\n");
1070                 break;
1071
1072         case GST_MESSAGE_EOS:
1073                 {
1074                         MMHandleType attrs = 0;
1075                         gint count = 0;
1076
1077                         LOGD("GST_MESSAGE_EOS received\n");
1078
1079                         /* NOTE : EOS event is comming multiple time. watch out it */
1080                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1081                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1082                                 LOGD("EOS received on non-playing state. ignoring it\n");
1083                                 break;
1084                         }
1085
1086                         if (player->pipeline) {
1087                                 if (player->pipeline->textbin)
1088                                         __mmplayer_drop_subtitle(player, TRUE);
1089
1090                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1091                                         GstPad *pad = NULL;
1092
1093                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1094
1095                                         LOGD("release audio callback\n");
1096
1097                                         /* release audio callback */
1098                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1099                                         player->audio_cb_probe_id = 0;
1100                                         /* audio callback should be free because it can be called even though probe remove.*/
1101                                         player->audio_stream_cb = NULL;
1102                                         player->audio_stream_cb_user_param = NULL;
1103
1104                                 }
1105                         }
1106                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1107                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1108
1109                         /* rewind if repeat count is greater then zero */
1110                         /* get play count */
1111                         attrs = MMPLAYER_GET_ATTRS(player);
1112
1113                         if (attrs) {
1114                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1115
1116                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1117
1118                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1119                                         if (player->playback_rate < 0.0) {
1120                                                 player->resumed_by_rewind = TRUE;
1121                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1122                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1123                                         }
1124
1125                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1126
1127                                         /* initialize */
1128                                         player->sent_bos = FALSE;
1129
1130                                         /* not posting eos when repeating */
1131                                         break;
1132                                 }
1133                         }
1134
1135                         if (player->pipeline)
1136                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1137
1138                         /* post eos message to application */
1139                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1140
1141                         /* reset last position */
1142                         player->last_position = 0;
1143                 }
1144                 break;
1145
1146         case GST_MESSAGE_ERROR:
1147                 {
1148                         GError *error = NULL;
1149                         gchar* debug = NULL;
1150
1151                         /* generating debug info before returning error */
1152                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1153
1154                         /* get error code */
1155                         gst_message_parse_error(msg, &error, &debug);
1156
1157                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1158                                 /* Note : the streaming error from the streaming source is handled
1159                                  *   using __mmplayer_handle_streaming_error.
1160                                  */
1161                                 __mmplayer_handle_streaming_error(player, msg);
1162
1163                                 /* dump state of all element */
1164                                 __mmplayer_dump_pipeline_state(player);
1165                         } else {
1166                                 /* traslate gst error code to msl error code. then post it
1167                                  * to application if needed
1168                                  */
1169                                 __mmplayer_handle_gst_error(player, msg, error);
1170
1171                                 if (debug)
1172                                         LOGE("error debug : %s", debug);
1173                         }
1174
1175                         if (MMPLAYER_IS_HTTP_PD(player))
1176                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1177
1178                         MMPLAYER_FREEIF(debug);
1179                         g_error_free(error);
1180                 }
1181                 break;
1182
1183         case GST_MESSAGE_WARNING:
1184                 {
1185                         char* debug = NULL;
1186                         GError* error = NULL;
1187
1188                         gst_message_parse_warning(msg, &error, &debug);
1189
1190                         LOGD("warning : %s\n", error->message);
1191                         LOGD("debug : %s\n", debug);
1192
1193                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1194
1195                         MMPLAYER_FREEIF(debug);
1196                         g_error_free(error);
1197                 }
1198                 break;
1199
1200         case GST_MESSAGE_TAG:
1201                 {
1202                         LOGD("GST_MESSAGE_TAG\n");
1203                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1204                                 LOGW("failed to extract tags from gstmessage\n");
1205                 }
1206                 break;
1207
1208         case GST_MESSAGE_BUFFERING:
1209                 {
1210                         MMMessageParamType msg_param = {0, };
1211                         int bRet = MM_ERROR_NONE;
1212
1213                         if (!(player->pipeline && player->pipeline->mainbin)) {
1214                                 LOGE("Pipeline is not initialized");
1215                                 break;
1216                         }
1217
1218                         if (!MMPLAYER_IS_STREAMING(player))
1219                                 break;
1220
1221                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1222                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1223                                         /* skip the playback control by buffering msg while user request is handled. */
1224                                         gint per = 0;
1225
1226                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1227
1228                                         gst_message_parse_buffering(msg, &per);
1229                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1230
1231                                         msg_param.connection.buffering = per;
1232                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1233                                         break;
1234                                 }
1235                         } else {
1236                                 MMPLAYER_CMD_LOCK(player);
1237                         }
1238
1239                         if (!player->streamer) {
1240                                 LOGW("Pipeline is shutting down");
1241                                 MMPLAYER_CMD_UNLOCK(player);
1242                                 break;
1243                         }
1244
1245                         /* ignore the remained buffering message till getting 100% msg */
1246                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1247                                 gint buffer_percent = 0;
1248
1249                                 gst_message_parse_buffering(msg, &buffer_percent);
1250
1251                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1252                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1253                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1254                                 }
1255                                 MMPLAYER_CMD_UNLOCK(player);
1256                                 break;
1257                         }
1258
1259                         /* ignore the remained buffering message */
1260                         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1261                                 gint buffer_percent = 0;
1262
1263                                 gst_message_parse_buffering(msg, &buffer_percent);
1264
1265                                 LOGD("force resume -last posted %d %%, new per %d %%",
1266                                                         player->streamer->buffering_percent, buffer_percent);
1267
1268                                 if (player->streamer->buffering_percent > buffer_percent) {
1269                                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1270                                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1271
1272                                         LOGD("force resume - need to enter the buffering mode again - %d %%", buffer_percent);
1273                                 } else {
1274                                         LOGD("force resume - ignored the remained buffering msg!");
1275                                         MMPLAYER_CMD_UNLOCK(player);
1276                                         break;
1277                                 }
1278                         }
1279
1280                         __mmplayer_update_buffer_setting(player, msg);
1281
1282                         bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1283
1284                         if (bRet == MM_ERROR_NONE) {
1285                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1286                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1287
1288                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1289                                         player->pending_resume &&
1290                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1291
1292                                         player->is_external_subtitle_added_now = FALSE;
1293                                         player->pending_resume = FALSE;
1294                                         _mmplayer_resume((MMHandleType)player);
1295                                 }
1296
1297                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1298                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1299
1300                                         if (player->doing_seek) {
1301                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1302                                                         player->doing_seek = FALSE;
1303                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1304                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1305                                                         async_done = TRUE;
1306                                                 }
1307                                         }
1308                                 }
1309                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310                                 if (!player->streamer) {
1311                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312                                         MMPLAYER_CMD_UNLOCK(player);
1313                                         break;
1314                                 }
1315
1316                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1317
1318                                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1320
1321                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1323                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1324                                         } else {
1325                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1326                                         }
1327                                 } else {
1328                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1329                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1330                                 }
1331                         }
1332                         MMPLAYER_CMD_UNLOCK(player);
1333                 }
1334                 break;
1335
1336         case GST_MESSAGE_STATE_CHANGED:
1337                 {
1338                         MMPlayerGstElement *mainbin;
1339                         const GValue *voldstate, *vnewstate, *vpending;
1340                         GstState oldstate = GST_STATE_NULL;
1341                         GstState newstate = GST_STATE_NULL;
1342                         GstState pending = GST_STATE_NULL;
1343
1344                         if (!(player->pipeline && player->pipeline->mainbin)) {
1345                                 LOGE("player pipeline handle is null");
1346                                 break;
1347                         }
1348
1349                         mainbin = player->pipeline->mainbin;
1350
1351                         /* we only handle messages from pipeline */
1352                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1353                                 break;
1354
1355                         /* get state info from msg */
1356                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1359
1360                         if (!voldstate || !vnewstate) {
1361                                 LOGE("received msg has wrong format.");
1362                                 break;
1363                         }
1364
1365                         oldstate = (GstState)voldstate->data[0].v_int;
1366                         newstate = (GstState)vnewstate->data[0].v_int;
1367                         if (vpending)
1368                                 pending = (GstState)vpending->data[0].v_int;
1369
1370                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1371                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372                                 gst_element_state_get_name((GstState)oldstate),
1373                                 gst_element_state_get_name((GstState)newstate),
1374                                 gst_element_state_get_name((GstState)pending));
1375
1376                         if (newstate == GST_STATE_PLAYING) {
1377                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1378
1379                                         int retVal = MM_ERROR_NONE;
1380                                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1381
1382                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1383
1384                                         if (MM_ERROR_NONE != retVal)
1385                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1386
1387                                         player->pending_seek.is_pending = FALSE;
1388                                 }
1389                         }
1390
1391                         if (oldstate == newstate) {
1392                                 LOGD("pipeline reports state transition to old state");
1393                                 break;
1394                         }
1395
1396                         switch (newstate) {
1397                         case GST_STATE_VOID_PENDING:
1398                                 break;
1399
1400                         case GST_STATE_NULL:
1401                                 break;
1402
1403                         case GST_STATE_READY:
1404                                 break;
1405
1406                         case GST_STATE_PAUSED:
1407                                 {
1408                                         gboolean prepare_async = FALSE;
1409
1410                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411                                                 __mmplayer_configure_audio_callback(player);
1412
1413                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414                                                 // managed prepare async case
1415                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1417                                         }
1418
1419                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1421
1422                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1424                                                                 player->total_maximum_bitrate, player->total_bitrate);
1425
1426                                                 if (player->pending_seek.is_pending) {
1427                                                         LOGW("trying to do pending seek");
1428                                                         MMPLAYER_CMD_LOCK(player);
1429                                                         __gst_pending_seek(player);
1430                                                         MMPLAYER_CMD_UNLOCK(player);
1431                                                 }
1432                                         }
1433                                 }
1434                                 break;
1435
1436                         case GST_STATE_PLAYING:
1437                                 {
1438                                         if (MMPLAYER_IS_STREAMING(player)) {
1439                                                 // managed prepare async case when buffering is completed
1440                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1444
1445                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1446
1447                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448                                                         if (player->streamer->buffering_percent < 100) {
1449
1450                                                                 MMMessageParamType msg_param = {0, };
1451                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1452
1453                                                                 msg_param.connection.buffering = 100;
1454                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1455                                                         }
1456                                                 }
1457                                         }
1458
1459                                         if (player->gapless.stream_changed) {
1460                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461                                                 player->gapless.stream_changed = FALSE;
1462                                         }
1463
1464                                         if (player->doing_seek && async_done) {
1465                                                 player->doing_seek = FALSE;
1466                                                 async_done = FALSE;
1467                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1468                                         }
1469                                 }
1470                                 break;
1471
1472                         default:
1473                                 break;
1474                         }
1475                 }
1476                 break;
1477
1478         case GST_MESSAGE_CLOCK_LOST:
1479                         {
1480                                 GstClock *clock = NULL;
1481                                 gboolean need_new_clock = FALSE;
1482
1483                                 gst_message_parse_clock_lost(msg, &clock);
1484                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1485
1486                                 if (!player->videodec_linked)
1487                                         need_new_clock = TRUE;
1488                                 else if (!player->ini.use_system_clock)
1489                                         need_new_clock = TRUE;
1490
1491                                 if (need_new_clock) {
1492                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1493                                         __gst_pause(player, FALSE);
1494                                         __gst_resume(player, FALSE);
1495                                 }
1496                         }
1497                         break;
1498
1499         case GST_MESSAGE_NEW_CLOCK:
1500                         {
1501                                 GstClock *clock = NULL;
1502                                 gst_message_parse_new_clock(msg, &clock);
1503                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1504                         }
1505                         break;
1506
1507         case GST_MESSAGE_ELEMENT:
1508                         {
1509                                 const gchar *structure_name;
1510                                 gint count = 0, idx = 0;
1511                                 MMHandleType attrs = 0;
1512
1513                                 attrs = MMPLAYER_GET_ATTRS(player);
1514                                 if (!attrs) {
1515                                         LOGE("cannot get content attribute");
1516                                         break;
1517                                 }
1518
1519                                 if (gst_message_get_structure(msg) == NULL)
1520                                         break;
1521
1522                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1523                                 if (!structure_name)
1524                                         break;
1525
1526                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1527
1528                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1529                                         const GValue *var_info = NULL;
1530
1531                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1532                                         if (var_info != NULL) {
1533                                                 if (player->adaptive_info.var_list)
1534                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1535
1536                                                 /* share addr or copy the list */
1537                                                 player->adaptive_info.var_list =
1538                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1539
1540                                                 count = g_list_length(player->adaptive_info.var_list);
1541                                                 if (count > 0) {
1542                                                         VariantData *temp = NULL;
1543
1544                                                         /* print out for debug */
1545                                                         LOGD("num of variant_info %d", count);
1546                                                         for (idx = 0; idx < count; idx++) {
1547                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1548                                                                 if (temp)
1549                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1550                                                         }
1551                                                 }
1552                                         }
1553                                 }
1554
1555                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1556                                         gint num_buffers = 0;
1557                                         gint extra_num_buffers = 0;
1558
1559                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1560                                                 player->video_num_buffers = num_buffers;
1561                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1562                                         }
1563
1564                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1565                                                 player->video_extra_num_buffers = extra_num_buffers;
1566                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1567                                         }
1568                                         break;
1569                                 }
1570
1571                                 if (!strcmp(structure_name, "Language_list")) {
1572                                         const GValue *lang_list = NULL;
1573                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1574                                         if (lang_list != NULL) {
1575                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1576                                                 if (count > 1)
1577                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1578                                         }
1579                                 }
1580
1581                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1582                                         const GValue *lang_list = NULL;
1583                                         MMPlayerLangStruct *temp = NULL;
1584
1585                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1586                                         if (lang_list != NULL) {
1587                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1588                                                 if (count) {
1589                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1590                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1591                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1592                                                         if (mmf_attrs_commit(attrs))
1593                                                                 LOGE("failed to commit.\n");
1594                                                         LOGD("Total subtitle tracks = %d \n", count);
1595
1596                                                         while (count) {
1597                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1598                                                                 if (temp)
1599                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1600                                                                                                 temp->language_key, temp->language_code);
1601                                                                 count--;
1602                                                         }
1603                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1604                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1605                                                 }
1606                                         }
1607                                 }
1608
1609                                 /* custom message */
1610                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1611                                         MMMessageParamType msg_param = {0,};
1612                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1613                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1614                                 }
1615
1616                                 /* custom message for RTSP attribute :
1617                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1618                                     sdp which has contents info is received when rtsp connection is opened.
1619                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1620                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1621
1622                                         gchar *audio_codec = NULL;
1623                                         gchar *video_codec = NULL;
1624                                         gchar *video_frame_size = NULL;
1625
1626                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1627                                         LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1628                                         player->streaming_type = __mmplayer_get_stream_service_type(player);
1629
1630                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1631                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1632                                         if (audio_codec)
1633                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1634
1635                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1636                                         LOGD("rtsp_video_codec : %s", video_codec);
1637                                         if (video_codec)
1638                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1639
1640                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1641                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1642                                         if (video_frame_size) {
1643
1644                                                 char *seperator = strchr(video_frame_size, '-');
1645                                                 if (seperator) {
1646
1647                                                         char video_width[10] = {0,};
1648                                                         int frame_size_len = strlen(video_frame_size);
1649                                                         int separtor_len = strlen(seperator);
1650
1651                                                         strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1652                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1653
1654                                                         seperator++;
1655                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1656                                                 }
1657                                         }
1658
1659                                         if (mmf_attrs_commit(attrs))
1660                                                 LOGE("failed to commit.\n");
1661                                 }
1662                         }
1663                         break;
1664
1665         case GST_MESSAGE_DURATION_CHANGED:
1666                 {
1667                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1668                         if (!__mmplayer_gst_handle_duration(player, msg))
1669                                 LOGW("failed to update duration");
1670                 }
1671
1672                 break;
1673
1674         case GST_MESSAGE_ASYNC_START:
1675                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1676                 break;
1677
1678         case GST_MESSAGE_ASYNC_DONE:
1679                 {
1680                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1681
1682                         /* we only handle messages from pipeline */
1683                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1684                                 break;
1685
1686                         if (player->doing_seek) {
1687                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1688                                         player->doing_seek = FALSE;
1689                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1690                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1691                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1692                                                 (player->streamer) &&
1693                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1694                                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1695                                                 GstQuery *query = NULL;
1696                                                 gboolean busy = FALSE;
1697                                                 gint percent = 0;
1698
1699                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1700                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1701                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1702                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1703                                                         gst_query_unref(query);
1704
1705                                                         LOGD("buffered percent(%s): %d\n",
1706                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1707                                                 }
1708
1709                                                 if (percent >= 100)
1710                                                         __mmplayer_handle_buffering_message(player);
1711                                         }
1712
1713                                         async_done = TRUE;
1714                                 }
1715                         }
1716                 }
1717                 break;
1718
1719         #if 0 /* delete unnecessary logs */
1720         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1721         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1722         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1723         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1724         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1725         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1726         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1727         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1728         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1729         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1730         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1731         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1732         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1733         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1734         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1735         #endif
1736
1737         default:
1738                 break;
1739         }
1740
1741         /* should not call 'gst_message_unref(msg)' */
1742         return;
1743 }
1744
1745 static gboolean
1746 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1747 {
1748         gint64 bytes = 0;
1749
1750         MMPLAYER_FENTER();
1751
1752         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1753         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1754
1755         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1756                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1757                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1758
1759                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1760                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1761                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1762                 }
1763         } else {
1764                 /* handling audio clip which has vbr. means duration is keep changing */
1765                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1766         }
1767
1768         MMPLAYER_FLEAVE();
1769
1770         return TRUE;
1771 }
1772
1773 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1774                 mm_player_spherical_metadata_t *metadata) {
1775         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1776         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1777         gst_tag_list_get_string(tags, "stitching_software",
1778                         &metadata->stitching_software);
1779         gst_tag_list_get_string(tags, "projection_type",
1780                         &metadata->projection_type_string);
1781         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1782         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1783         gst_tag_list_get_int(tags, "init_view_heading",
1784                         &metadata->init_view_heading);
1785         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1786         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1787         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1788         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1789                         &metadata->full_pano_width_pixels);
1790         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1791                         &metadata->full_pano_height_pixels);
1792         gst_tag_list_get_int(tags, "cropped_area_image_width",
1793                         &metadata->cropped_area_image_width);
1794         gst_tag_list_get_int(tags, "cropped_area_image_height",
1795                         &metadata->cropped_area_image_height);
1796         gst_tag_list_get_int(tags, "cropped_area_left",
1797                         &metadata->cropped_area_left);
1798         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1799         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1800         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1801         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1802 }
1803
1804 static gboolean
1805 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1806 {
1807
1808 /* macro for better code readability */
1809 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1810 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1811         if (string != NULL) { \
1812                 SECURE_LOGD("update tag string : %s\n", string); \
1813                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1814                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1815                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1816                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1817                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1818                         g_free(new_string); \
1819                         new_string = NULL; \
1820                 } else { \
1821                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1822                 } \
1823                 g_free(string); \
1824                 string = NULL; \
1825         } \
1826 }
1827
1828 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1829 do {    \
1830         GstSample *sample = NULL;\
1831         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1832                 GstMapInfo info = GST_MAP_INFO_INIT;\
1833                 buffer = gst_sample_get_buffer(sample);\
1834                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1835                         LOGD("failed to get image data from tag");\
1836                         gst_sample_unref(sample);\
1837                         return FALSE;\
1838                 } \
1839                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1840                 MMPLAYER_FREEIF(player->album_art);\
1841                 player->album_art = (gchar *)g_malloc(info.size);\
1842                 if (player->album_art) {\
1843                         memcpy(player->album_art, info.data, info.size);\
1844                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1845                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1846                                 msg_param.data = (void *)player->album_art;\
1847                                 msg_param.size = info.size;\
1848                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1849                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1850                         } \
1851                 } \
1852                 gst_buffer_unmap(buffer, &info);\
1853                 gst_sample_unref(sample);\
1854         }       \
1855 } while (0)
1856
1857 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1858 do {    \
1859         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1860                 if (v_uint) { \
1861                         int i = 0; \
1862                         gchar *tag_list_str = NULL; \
1863                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1864                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1865                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1866                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1867                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1868                         else \
1869                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1870                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1871                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1872                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1873                                 player->bitrate[track_type] = v_uint; \
1874                                 player->total_bitrate = 0; \
1875                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1876                                         player->total_bitrate += player->bitrate[i]; \
1877                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1878                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1879                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1880                                 player->maximum_bitrate[track_type] = v_uint; \
1881                                 player->total_maximum_bitrate = 0; \
1882                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1883                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1884                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1885                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1886                         } else { \
1887                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1888                         } \
1889                         v_uint = 0;\
1890                         g_free(tag_list_str); \
1891                 } \
1892         } \
1893 } while (0)
1894
1895 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1896 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1897         if (date != NULL) {\
1898                 string = g_strdup_printf("%d", g_date_get_year(date));\
1899                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1900                 SECURE_LOGD("metainfo year : %s\n", string);\
1901                 MMPLAYER_FREEIF(string);\
1902                 g_date_free(date);\
1903         } \
1904 }
1905
1906 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1907 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1908         if (datetime != NULL) {\
1909                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1910                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1911                 SECURE_LOGD("metainfo year : %s\n", string);\
1912                 MMPLAYER_FREEIF(string);\
1913                 gst_date_time_unref(datetime);\
1914         } \
1915 }
1916
1917 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1918 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1919         if (v_uint64) {\
1920                 /* FIXIT : don't know how to store date */\
1921                 g_assert(1);\
1922                 v_uint64 = 0;\
1923         } \
1924 }
1925
1926 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1927 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1928         if (v_double) {\
1929                 /* FIXIT : don't know how to store date */\
1930                 g_assert(1);\
1931                 v_double = 0;\
1932         } \
1933 }
1934
1935         /* function start */
1936         GstTagList* tag_list = NULL;
1937
1938         MMHandleType attrs = 0;
1939
1940         char *string = NULL;
1941         guint v_uint = 0;
1942         GDate *date = NULL;
1943         GstDateTime *datetime = NULL;
1944         /* album cover */
1945         GstBuffer *buffer = NULL;
1946         gint index = 0;
1947         MMMessageParamType msg_param = {0, };
1948
1949         /* currently not used. but those are needed for above macro */
1950         //guint64 v_uint64 = 0;
1951         //gdouble v_double = 0;
1952
1953         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1954
1955         attrs = MMPLAYER_GET_ATTRS(player);
1956
1957         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1958
1959         /* get tag list from gst message */
1960         gst_message_parse_tag(msg, &tag_list);
1961
1962         /* store tags to player attributes */
1963         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1964         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1965         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1966         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1967         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1968         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1969         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1970         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1971         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1972         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1973         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1974         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1975         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1976         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1977         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1978         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1979         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1980         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1981         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1982         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1983         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1984         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1985         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1986         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1987         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1988         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1989         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1990         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1991         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1992         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1993         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1994         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1995         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1996         MMPLAYER_UPDATE_TAG_LOCK(player);
1997         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1998         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1999         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2000         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2001         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2002         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2003         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2004         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2005         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2006         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2007         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2008         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2009         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2010         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2011         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2012
2013         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2014                 if (player->video360_metadata.is_spherical == -1) {
2015                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2016                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2017                                         player->video360_metadata.is_spherical);
2018                         if (player->video360_metadata.is_spherical == 1) {
2019                                 LOGD("This is spherical content for 360 playback.");
2020                                 player->is_content_spherical = TRUE;
2021                         } else {
2022                                 LOGD("This is not spherical content");
2023                                 player->is_content_spherical = FALSE;
2024                         }
2025
2026                         if (player->video360_metadata.projection_type_string) {
2027                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2028                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2029                                 } else {
2030                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2031                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2032                                 }
2033                         }
2034
2035                         if (player->video360_metadata.stereo_mode_string) {
2036                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2037                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2038                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2039                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2040                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2041                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2042                                 } else {
2043                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2044                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2045                                 }
2046                         }
2047                 }
2048         }
2049
2050         if (mmf_attrs_commit(attrs))
2051                 LOGE("failed to commit.\n");
2052
2053         gst_tag_list_free(tag_list);
2054
2055         return TRUE;
2056 }
2057
2058 static void
2059 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2060 {
2061         mm_player_t* player = (mm_player_t*) data;
2062
2063         MMPLAYER_FENTER();
2064
2065         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2066           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2067           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2068           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2069
2070           * [1] audio and video will be dumped with filesink.
2071           * [2] autoplugging is done by just using pad caps.
2072           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2073           * and the video will be dumped via filesink.
2074           */
2075         if (player->num_dynamic_pad == 0) {
2076                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2077
2078                 if (!__mmplayer_gst_remove_fakesink(player,
2079                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2080                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2081                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2082                          * source element are not same. To overcome this situation, this function will called
2083                          * several places and several times. Therefore, this is not an error case.
2084                          */
2085                         return;
2086         }
2087
2088         /* create dot before error-return. for debugging */
2089         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2090
2091         player->no_more_pad = TRUE;
2092
2093         MMPLAYER_FLEAVE();
2094 }
2095
2096 static gboolean
2097 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2098 {
2099         GstElement* parent = NULL;
2100
2101         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2102
2103         /* if we have no fakesink. this meas we are using decodebin which doesn'
2104         t need to add extra fakesink */
2105         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2106
2107         /* lock */
2108         MMPLAYER_FSINK_LOCK(player);
2109
2110         if (!fakesink->gst)
2111                 goto ERROR;
2112
2113         /* get parent of fakesink */
2114         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2115         if (!parent) {
2116                 LOGD("fakesink already removed\n");
2117                 goto ERROR;
2118         }
2119
2120         gst_element_set_locked_state(fakesink->gst, TRUE);
2121
2122         /* setting the state to NULL never returns async
2123          * so no need to wait for completion of state transiton
2124          */
2125         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2126                 LOGE("fakesink state change failure!\n");
2127                 /* FIXIT : should I return here? or try to proceed to next? */
2128                 /* return FALSE; */
2129
2130         /* remove fakesink from it's parent */
2131         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2132                 LOGE("failed to remove fakesink\n");
2133
2134                 gst_object_unref(parent);
2135
2136                 goto ERROR;
2137         }
2138
2139         gst_object_unref(parent);
2140
2141         LOGD("state-holder removed\n");
2142
2143         gst_element_set_locked_state(fakesink->gst, FALSE);
2144
2145         MMPLAYER_FSINK_UNLOCK(player);
2146         return TRUE;
2147
2148 ERROR:
2149         if (fakesink->gst)
2150                 gst_element_set_locked_state(fakesink->gst, FALSE);
2151
2152         MMPLAYER_FSINK_UNLOCK(player);
2153         return FALSE;
2154 }
2155
2156
2157 static void
2158 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2159 {
2160         GstPad *sinkpad = NULL;
2161         GstCaps* caps = NULL;
2162         GstElement* new_element = NULL;
2163         GstStructure* str = NULL;
2164         const gchar* name = NULL;
2165
2166         mm_player_t* player = (mm_player_t*) data;
2167
2168         MMPLAYER_FENTER();
2169
2170         MMPLAYER_RETURN_IF_FAIL(element && pad);
2171         MMPLAYER_RETURN_IF_FAIL(player &&
2172                                         player->pipeline &&
2173                                         player->pipeline->mainbin);
2174
2175
2176         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2177          * num_dynamic_pad will decreased after creating a sinkbin.
2178          */
2179         player->num_dynamic_pad++;
2180         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2181
2182         caps = gst_pad_query_caps(pad, NULL);
2183
2184         MMPLAYER_CHECK_NULL(caps);
2185
2186         /* clear  previous result*/
2187         player->have_dynamic_pad = FALSE;
2188
2189         str = gst_caps_get_structure(caps, 0);
2190
2191         if (!str) {
2192                 LOGE("cannot get structure from caps.\n");
2193                 goto ERROR;
2194         }
2195
2196         name = gst_structure_get_name(str);
2197         if (!name) {
2198                 LOGE("cannot get mimetype from structure.\n");
2199                 goto ERROR;
2200         }
2201
2202         if (strstr(name, "video")) {
2203                 gint stype = 0;
2204                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2205
2206                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2207                         if (player->v_stream_caps) {
2208                                 gst_caps_unref(player->v_stream_caps);
2209                                 player->v_stream_caps = NULL;
2210                         }
2211
2212                         new_element = gst_element_factory_make("fakesink", NULL);
2213                         player->num_dynamic_pad--;
2214                         goto NEW_ELEMENT;
2215                 }
2216         }
2217
2218         /* clear  previous result*/
2219         player->have_dynamic_pad = FALSE;
2220
2221         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2222                 LOGE("failed to autoplug for caps");
2223                 goto ERROR;
2224         }
2225
2226         /* check if there's dynamic pad*/
2227         if (player->have_dynamic_pad) {
2228                 LOGE("using pad caps assums there's no dynamic pad !\n");
2229                 goto ERROR;
2230         }
2231
2232         gst_caps_unref(caps);
2233         caps = NULL;
2234
2235 NEW_ELEMENT:
2236
2237         /* excute new_element if created*/
2238         if (new_element) {
2239                 LOGD("adding new element to pipeline\n");
2240
2241                 /* set state to READY before add to bin */
2242                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2243
2244                 /* add new element to the pipeline */
2245                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2246                         LOGE("failed to add autoplug element to bin\n");
2247                         goto ERROR;
2248                 }
2249
2250                 /* get pad from element */
2251                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2252                 if (!sinkpad) {
2253                         LOGE("failed to get sinkpad from autoplug element\n");
2254                         goto ERROR;
2255                 }
2256
2257                 /* link it */
2258                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2259                         LOGE("failed to link autoplug element\n");
2260                         goto ERROR;
2261                 }
2262
2263                 gst_object_unref(sinkpad);
2264                 sinkpad = NULL;
2265
2266                 /* run. setting PLAYING here since streamming source is live source */
2267                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2268         }
2269
2270         if (caps)
2271                 gst_caps_unref(caps);
2272
2273         MMPLAYER_FLEAVE();
2274
2275         return;
2276
2277 STATE_CHANGE_FAILED:
2278 ERROR:
2279         /* FIXIT : take care if new_element has already added to pipeline */
2280         if (new_element)
2281                 gst_object_unref(GST_OBJECT(new_element));
2282
2283         if (sinkpad)
2284                 gst_object_unref(GST_OBJECT(sinkpad));
2285
2286         if (caps)
2287                 gst_caps_unref(caps);
2288
2289         /* FIXIT : how to inform this error to MSL ????? */
2290         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2291          * then post an error to application
2292          */
2293 }
2294
2295 static GstPadProbeReturn
2296 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2297 {
2298         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2299         return GST_PAD_PROBE_OK;
2300 }
2301
2302 static GstPadProbeReturn
2303 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2304 {
2305         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2306         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2307         mm_player_t* player = (mm_player_t*)data;
2308         GstCaps* caps = NULL;
2309         GstStructure* str = NULL;
2310         const gchar* name = NULL;
2311         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2312
2313
2314         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2315                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2316                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2317                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2318                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2319                         return ret;
2320         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2321                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2322                         return ret;
2323         }
2324
2325         caps = gst_pad_query_caps(pad, NULL);
2326         if (!caps) {
2327                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2328                 return ret;
2329         }
2330
2331         str = gst_caps_get_structure(caps, 0);
2332         if (!str) {
2333                 LOGE("failed to get structure from caps");
2334                 goto ERROR;
2335         }
2336
2337         name = gst_structure_get_name(str);
2338         if (!name) {
2339                 LOGE("failed to get name from str");
2340                 goto ERROR;
2341         }
2342
2343         if (strstr(name, "audio")) {
2344                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2345         } else if (strstr(name, "video")) {
2346                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2347         } else {
2348                 /* text track is not supportable */
2349                 LOGE("invalid name %s", name);
2350                 goto ERROR;
2351         }
2352
2353         switch (GST_EVENT_TYPE(event)) {
2354         case GST_EVENT_EOS:
2355                 {
2356                         /* in case of gapless, drop eos event not to send it to sink */
2357                         if (player->gapless.reconfigure && !player->msg_posted) {
2358                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2359                                 ret = GST_PAD_PROBE_DROP;
2360                         }
2361                         break;
2362                 }
2363         case GST_EVENT_STREAM_START:
2364                 {
2365                         gint64 stop_running_time = 0;
2366                         gint64 position_running_time = 0;
2367                         gint64 position = 0;
2368                         gint idx = 0;
2369
2370                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2371                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2372                                         !(player->selector[idx].event_probe_id)) {
2373                                         /* LOGW("[%d] skip", idx); */
2374                                         continue;
2375                                 }
2376
2377                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2378                                         stop_running_time =
2379                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2380                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2381                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2382                                         stop_running_time =
2383                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2384                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2385                                 } else {
2386                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2387                                         stop_running_time =
2388                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2389                                                                 GST_FORMAT_TIME, player->duration);
2390                                 }
2391
2392                                 position_running_time =
2393                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2394                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2395
2396                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2397                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2398                                         idx,
2399                                         GST_TIME_ARGS(stop_running_time),
2400                                         GST_TIME_ARGS(position_running_time),
2401                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2402                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2403
2404                                 position_running_time = MAX(position_running_time, stop_running_time);
2405                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2406                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2407                                 position_running_time = MAX(0, position_running_time);
2408                                 position = MAX(position, position_running_time);
2409                         }
2410
2411                         if (position != 0) {
2412                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2413                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2414                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2415
2416                                 player->gapless.start_time[stream_type] += position;
2417                         }
2418                         break;
2419                 }
2420         case GST_EVENT_FLUSH_STOP:
2421                 {
2422                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2423                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2424                         player->gapless.start_time[stream_type] = 0;
2425                         break;
2426                 }
2427         case GST_EVENT_SEGMENT:
2428                 {
2429                         GstSegment segment;
2430                         GstEvent *tmpev;
2431
2432                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2433                         gst_event_copy_segment(event, &segment);
2434
2435                         if (segment.format == GST_FORMAT_TIME) {
2436                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2437                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2438                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2439                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2440                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2441                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2442
2443                                 /* keep the all the segment ev to cover the seeking */
2444                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2445                                 player->gapless.update_segment[stream_type] = TRUE;
2446
2447                                 if (!player->gapless.running)
2448                                         break;
2449
2450                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2451
2452                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2453
2454                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2455                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2456                                 gst_event_unref(event);
2457                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2458                         }
2459                         break;
2460                 }
2461         case GST_EVENT_QOS:
2462                 {
2463                         gdouble proportion = 0.0;
2464                         GstClockTimeDiff diff = 0;
2465                         GstClockTime timestamp = 0;
2466                         gint64 running_time_diff = -1;
2467                         GstQOSType type = 0;
2468                         GstEvent *tmpev = NULL;
2469
2470                         running_time_diff = player->gapless.segment[stream_type].base;
2471
2472                         if (running_time_diff <= 0) /* don't need to adjust */
2473                                 break;
2474
2475                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2476                         gst_event_unref(event);
2477
2478                         if (timestamp < running_time_diff) {
2479                                 LOGW("QOS event from previous group");
2480                                 ret = GST_PAD_PROBE_DROP;
2481                                 break;
2482                         }
2483
2484                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2485                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2486                                                 stream_type, GST_TIME_ARGS(timestamp),
2487                                                 GST_TIME_ARGS(running_time_diff),
2488                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2489
2490                         timestamp -= running_time_diff;
2491
2492                         /* That case is invalid for QoS events */
2493                         if (diff < 0 && -diff > timestamp) {
2494                                 LOGW("QOS event from previous group");
2495                                 ret = GST_PAD_PROBE_DROP;
2496                                 break;
2497                         }
2498
2499                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2500                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2501
2502                         break;
2503                 }
2504         default:
2505                 break;
2506         }
2507
2508 ERROR:
2509         if (caps)
2510                 gst_caps_unref(caps);
2511         return ret;
2512 }
2513
2514 static void
2515 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2516 {
2517         mm_player_t* player = NULL;
2518         GstElement* pipeline = NULL;
2519         GstElement* selector = NULL;
2520         GstElement* fakesink = NULL;
2521         GstCaps* caps = NULL;
2522         GstStructure* str = NULL;
2523         const gchar* name = NULL;
2524         GstPad* sinkpad = NULL;
2525         GstPad* srcpad = NULL;
2526         gboolean first_track = FALSE;
2527
2528         enum MainElementID elemId = MMPLAYER_M_NUM;
2529         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2530
2531         /* check handles */
2532         player = (mm_player_t*)data;
2533
2534         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2535         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2536
2537         //LOGD("pad-added signal handling\n");
2538
2539         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2540
2541         /* get mimetype from caps */
2542         caps = gst_pad_query_caps(pad, NULL);
2543         if (!caps) {
2544                 LOGE("cannot get caps from pad.\n");
2545                 goto ERROR;
2546         }
2547
2548         str = gst_caps_get_structure(caps, 0);
2549         if (!str) {
2550                 LOGE("cannot get structure from caps.\n");
2551                 goto ERROR;
2552         }
2553
2554         name = gst_structure_get_name(str);
2555         if (!name) {
2556                 LOGE("cannot get mimetype from structure.\n");
2557                 goto ERROR;
2558         }
2559
2560         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2561         //LOGD("detected mimetype : %s\n", name);
2562
2563         if (strstr(name, "video")) {
2564                 gint stype = 0;
2565
2566                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2567                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2568
2569                 /* don't make video because of not required, and not support multiple track */
2570                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2571                         LOGD("no video sink by null surface");
2572
2573                         gchar *caps_str = gst_caps_to_string(caps);
2574                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2575                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2576                                 player->set_mode.video_zc = TRUE;
2577
2578                         MMPLAYER_FREEIF(caps_str);
2579
2580                         if (player->v_stream_caps) {
2581                                 gst_caps_unref(player->v_stream_caps);
2582                                 player->v_stream_caps = NULL;
2583                         }
2584
2585                         LOGD("create fakesink instead of videobin");
2586
2587                         /* fake sink */
2588                         fakesink = gst_element_factory_make("fakesink", NULL);
2589                         if (fakesink == NULL) {
2590                                 LOGE("ERROR : fakesink create error\n");
2591                                 goto ERROR;
2592                         }
2593
2594                         if (player->ini.set_dump_element_flag)
2595                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2596
2597                         player->video_fakesink = fakesink;
2598
2599                         /* store it as it's sink element */
2600                         __mmplayer_add_sink(player, player->video_fakesink);
2601
2602                         gst_bin_add(GST_BIN(pipeline), fakesink);
2603
2604                         // link
2605                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2606
2607                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2608                                 LOGW("failed to link fakesink\n");
2609                                 gst_object_unref(GST_OBJECT(fakesink));
2610                                 goto ERROR;
2611                         }
2612
2613                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2614                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2615                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2616                         }
2617
2618                         if (player->set_mode.media_packet_video_stream) {
2619                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2620
2621                                 MMPLAYER_SIGNAL_CONNECT(player,
2622                                                                                 G_OBJECT(fakesink),
2623                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2624                                                                                 "handoff",
2625                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2626                                                                                 (gpointer)player);
2627
2628                                 MMPLAYER_SIGNAL_CONNECT(player,
2629                                                                                 G_OBJECT(fakesink),
2630                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2631                                                                                 "preroll-handoff",
2632                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2633                                                                                 (gpointer)player);
2634                         }
2635
2636                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2637                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2638                         goto DONE;
2639                 }
2640
2641                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2642                         __mmplayer_gst_decode_callback(elem, pad, player);
2643                         goto DONE;
2644                 }
2645
2646                 LOGD("video selector \n");
2647                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2648                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2649         } else {
2650                 if (strstr(name, "audio")) {
2651                         gint samplerate = 0;
2652                         gint channels = 0;
2653
2654                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2655                                 __mmplayer_gst_decode_callback(elem, pad, player);
2656                                 goto DONE;
2657                         }
2658
2659                         LOGD("audio selector \n");
2660                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2661                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2662
2663                         gst_structure_get_int(str, "rate", &samplerate);
2664                         gst_structure_get_int(str, "channels", &channels);
2665
2666                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2667                                 /* fake sink */
2668                                 fakesink = gst_element_factory_make("fakesink", NULL);
2669                                 if (fakesink == NULL) {
2670                                         LOGE("ERROR : fakesink create error\n");
2671                                         goto ERROR;
2672                                 }
2673
2674                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2675
2676                                 /* link */
2677                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2678
2679                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2680                                         LOGW("failed to link fakesink\n");
2681                                         gst_object_unref(GST_OBJECT(fakesink));
2682                                         goto ERROR;
2683                                 }
2684
2685                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2686                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2687                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2688
2689                                 goto DONE;
2690                         }
2691                 } else if (strstr(name, "text")) {
2692                         LOGD("text selector \n");
2693                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2694                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2695                 } else {
2696                         LOGE("wrong elem id \n");
2697                         goto ERROR;
2698                 }
2699         }
2700
2701         selector = player->pipeline->mainbin[elemId].gst;
2702         if (selector == NULL) {
2703                 selector = gst_element_factory_make("input-selector", NULL);
2704                 LOGD("Creating input-selector\n");
2705                 if (selector == NULL) {
2706                         LOGE("ERROR : input-selector create error\n");
2707                         goto ERROR;
2708                 }
2709                 g_object_set(selector, "sync-streams", TRUE, NULL);
2710
2711                 player->pipeline->mainbin[elemId].id = elemId;
2712                 player->pipeline->mainbin[elemId].gst = selector;
2713
2714                 first_track = TRUE;
2715                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2716
2717                 srcpad = gst_element_get_static_pad(selector, "src");
2718
2719                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2720                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2721                         __mmplayer_gst_selector_blocked, NULL, NULL);
2722                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2723                         __mmplayer_gst_selector_event_probe, player, NULL);
2724
2725                 gst_element_set_state(selector, GST_STATE_PAUSED);
2726                 gst_bin_add(GST_BIN(pipeline), selector);
2727         } else
2728                 LOGD("input-selector is already created.\n");
2729
2730         // link
2731         LOGD("Calling request pad with selector %p \n", selector);
2732         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2733
2734         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2735
2736         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2737                 LOGW("failed to link selector\n");
2738                 gst_object_unref(GST_OBJECT(selector));
2739                 goto ERROR;
2740         }
2741
2742         if (first_track) {
2743                 LOGD("this is first track --> active track \n");
2744                 g_object_set(selector, "active-pad", sinkpad, NULL);
2745         }
2746
2747         _mmplayer_track_update_info(player, stream_type, sinkpad);
2748
2749
2750 DONE:
2751 ERROR:
2752
2753         if (caps)
2754                 gst_caps_unref(caps);
2755
2756         if (sinkpad) {
2757                 gst_object_unref(GST_OBJECT(sinkpad));
2758                 sinkpad = NULL;
2759         }
2760
2761         if (srcpad) {
2762                 gst_object_unref(GST_OBJECT(srcpad));
2763                 srcpad = NULL;
2764         }
2765
2766         return;
2767 }
2768
2769 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2770 {
2771         GstPad* srcpad = NULL;
2772         MMHandleType attrs = 0;
2773         gint active_index = 0;
2774
2775         // [link] input-selector :: textbin
2776         srcpad = gst_element_get_static_pad(text_selector, "src");
2777         if (!srcpad) {
2778                 LOGE("failed to get srcpad from selector\n");
2779                 return;
2780         }
2781
2782         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2783
2784         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2785         if ((active_index != DEFAULT_TRACK) &&
2786                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2787                 LOGW("failed to change text track\n");
2788                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2789         }
2790
2791         player->no_more_pad = TRUE;
2792         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2793
2794         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2795         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2796                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2797                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2798         }
2799
2800         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2801
2802         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2803                 player->has_closed_caption = TRUE;
2804
2805         attrs = MMPLAYER_GET_ATTRS(player);
2806         if (attrs) {
2807                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2808                 if (mmf_attrs_commit(attrs))
2809                         LOGE("failed to commit.\n");
2810         } else
2811                 LOGE("cannot get content attribute");
2812
2813         if (srcpad) {
2814                 gst_object_unref(GST_OBJECT(srcpad));
2815                 srcpad = NULL;
2816         }
2817 }
2818
2819 static void
2820 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2821 {
2822         mm_player_t* player = (mm_player_t*)data;
2823         GstElement* selector = NULL;
2824         GstElement* queue = NULL;
2825
2826         GstPad* srcpad = NULL;
2827         GstPad* sinkpad = NULL;
2828         GstCaps* caps = NULL;
2829         gchar* caps_str = NULL;
2830
2831         MMPLAYER_FENTER();
2832         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2833
2834         caps = gst_pad_get_current_caps(pad);
2835         caps_str = gst_caps_to_string(caps);
2836         LOGD("deinterleave new caps : %s\n", caps_str);
2837         MMPLAYER_FREEIF(caps_str);
2838         gst_caps_unref(caps);
2839
2840         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2841                 LOGE("ERROR : queue create error\n");
2842                 goto ERROR;
2843         }
2844
2845         g_object_set(G_OBJECT(queue),
2846                                 "max-size-buffers", 10,
2847                                 "max-size-bytes", 0,
2848                                 "max-size-time", (guint64)0,
2849                                 NULL);
2850
2851         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2852
2853         if (!selector) {
2854                 LOGE("there is no audio channel selector.\n");
2855                 goto ERROR;
2856         }
2857
2858         srcpad = gst_element_get_static_pad(queue, "src");
2859         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2860
2861         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2862
2863         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2864                 LOGW("failed to link deinterleave - selector\n");
2865                 goto ERROR;
2866         }
2867
2868         gst_element_set_state(queue, GST_STATE_PAUSED);
2869         player->audio_mode.total_track_num++;
2870
2871 ERROR:
2872
2873         if (srcpad) {
2874                 gst_object_unref(GST_OBJECT(srcpad));
2875                 srcpad = NULL;
2876         }
2877
2878         if (sinkpad) {
2879                 gst_object_unref(GST_OBJECT(sinkpad));
2880                 sinkpad = NULL;
2881         }
2882
2883         MMPLAYER_FLEAVE();
2884         return;
2885 }
2886
2887 static void
2888 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2889 {
2890         mm_player_t* player = NULL;
2891         GstElement* selector = NULL;
2892         GstPad* sinkpad = NULL;
2893         gint active_index = 0;
2894         gchar* change_pad_name = NULL;
2895         GstCaps* caps = NULL;   // no need to unref
2896         gint default_audio_ch = 0;
2897
2898         MMPLAYER_FENTER();
2899         player = (mm_player_t*) data;
2900
2901         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2902
2903         if (!selector) {
2904                 LOGE("there is no audio channel selector.\n");
2905                 goto ERROR;
2906         }
2907
2908         active_index = player->audio_mode.active_pad_index;
2909
2910         if (active_index != default_audio_ch) {
2911                 gint audio_ch = default_audio_ch;
2912
2913                 /*To get the new pad from the selector*/
2914                 change_pad_name = g_strdup_printf("sink%d", active_index);
2915                 if (change_pad_name != NULL) {
2916                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2917                         if (sinkpad != NULL) {
2918                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2919                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2920
2921                                 audio_ch = active_index;
2922
2923                                 caps = gst_pad_get_current_caps(sinkpad);
2924                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2925
2926                                 __mmplayer_set_audio_attrs(player, caps);
2927                                 gst_caps_unref(caps);
2928                         }
2929                         MMPLAYER_FREEIF(change_pad_name);
2930                 }
2931
2932                 player->audio_mode.active_pad_index = audio_ch;
2933                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2934         }
2935
2936 ERROR:
2937
2938         if (sinkpad)
2939                 gst_object_unref(sinkpad);
2940
2941         MMPLAYER_FLEAVE();
2942         return;
2943 }
2944
2945 static void
2946 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2947 {
2948         mm_player_t* player = NULL;
2949         MMPlayerGstElement *mainbin = NULL;
2950
2951         GstElement* tee = NULL;
2952         GstElement* stereo_queue = NULL;
2953         GstElement* mono_queue = NULL;
2954         GstElement* conv = NULL;
2955         GstElement* filter = NULL;
2956         GstElement* deinterleave = NULL;
2957         GstElement* selector = NULL;
2958
2959         GstPad* srcpad = NULL;
2960         GstPad* selector_srcpad = NULL;
2961         GstPad* sinkpad = NULL;
2962         GstCaps* caps = NULL;
2963         gulong block_id = 0;
2964
2965         MMPLAYER_FENTER();
2966
2967         /* check handles */
2968         player = (mm_player_t*) data;
2969
2970         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2971         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2972
2973         mainbin = player->pipeline->mainbin;
2974
2975         /* tee */
2976         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2977                 LOGE("ERROR : tee create error\n");
2978                 goto ERROR;
2979         }
2980
2981         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2982         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2983
2984         gst_element_set_state(tee, GST_STATE_PAUSED);
2985
2986         /* queue */
2987         srcpad = gst_element_get_request_pad(tee, "src_%u");
2988         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2989                 LOGE("ERROR : stereo queue create error\n");
2990                 goto ERROR;
2991         }
2992
2993         g_object_set(G_OBJECT(stereo_queue),
2994                                 "max-size-buffers", 10,
2995                                 "max-size-bytes", 0,
2996                                 "max-size-time", (guint64)0,
2997                                 NULL);
2998
2999         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3000         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3001
3002         if (srcpad) {
3003                 gst_object_unref(GST_OBJECT(srcpad));
3004                 srcpad = NULL;
3005         }
3006
3007         srcpad = gst_element_get_request_pad(tee, "src_%u");
3008
3009         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3010                 LOGE("ERROR : mono queue create error\n");
3011                 goto ERROR;
3012         }
3013
3014         g_object_set(G_OBJECT(mono_queue),
3015                                 "max-size-buffers", 10,
3016                                 "max-size-bytes", 0,
3017                                 "max-size-time", (guint64)0,
3018                                 NULL);
3019
3020         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3021         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3022
3023         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3024         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3025
3026         /* audioconvert */
3027         srcpad = gst_element_get_static_pad(mono_queue, "src");
3028         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3029                 LOGE("ERROR : audioconvert create error\n");
3030                 goto ERROR;
3031         }
3032
3033         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3034         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3035
3036         /* caps filter */
3037         if (srcpad) {
3038                 gst_object_unref(GST_OBJECT(srcpad));
3039                 srcpad = NULL;
3040         }
3041         srcpad = gst_element_get_static_pad(conv, "src");
3042
3043         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3044                 LOGE("ERROR : capsfilter create error\n");
3045                 goto ERROR;
3046         }
3047
3048         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3049         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3050
3051         caps = gst_caps_from_string("audio/x-raw-int, "
3052                                 "width = (int) 16, "
3053                                 "depth = (int) 16, "
3054                                 "channels = (int) 2");
3055
3056         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3057         gst_caps_unref(caps);
3058
3059         gst_element_set_state(conv, GST_STATE_PAUSED);
3060         gst_element_set_state(filter, GST_STATE_PAUSED);
3061
3062         /* deinterleave */
3063         if (srcpad) {
3064                 gst_object_unref(GST_OBJECT(srcpad));
3065                 srcpad = NULL;
3066         }
3067         srcpad = gst_element_get_static_pad(filter, "src");
3068
3069         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3070                 LOGE("ERROR : deinterleave create error\n");
3071                 goto ERROR;
3072         }
3073
3074         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3075
3076         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3077                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3078
3079         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3080                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3081
3082         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3083         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3084
3085         /* selector */
3086         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3087         if (selector == NULL) {
3088                 LOGE("ERROR : audio-selector create error\n");
3089                 goto ERROR;
3090         }
3091
3092         g_object_set(selector, "sync-streams", TRUE, NULL);
3093         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3094
3095         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3096         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3097
3098         selector_srcpad = gst_element_get_static_pad(selector, "src");
3099
3100         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3101         block_id =
3102                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3103                         __mmplayer_gst_selector_blocked, NULL, NULL);
3104
3105         if (srcpad) {
3106                 gst_object_unref(GST_OBJECT(srcpad));
3107                 srcpad = NULL;
3108         }
3109
3110         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3111         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3112
3113         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3114                 LOGW("failed to link queue_stereo - selector\n");
3115                 goto ERROR;
3116         }
3117
3118         player->audio_mode.total_track_num++;
3119
3120         g_object_set(selector, "active-pad", sinkpad, NULL);
3121         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3122         gst_element_set_state(selector, GST_STATE_PAUSED);
3123
3124         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3125
3126 ERROR:
3127
3128         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3129         if (block_id != 0) {
3130                 gst_pad_remove_probe(selector_srcpad, block_id);
3131                 block_id = 0;
3132         }
3133
3134         if (sinkpad) {
3135                 gst_object_unref(GST_OBJECT(sinkpad));
3136                 sinkpad = NULL;
3137         }
3138
3139         if (srcpad) {
3140                 gst_object_unref(GST_OBJECT(srcpad));
3141                 srcpad = NULL;
3142         }
3143
3144         if (selector_srcpad) {
3145                 gst_object_unref(GST_OBJECT(selector_srcpad));
3146                 selector_srcpad = NULL;
3147         }
3148
3149         MMPLAYER_FLEAVE();
3150         return;
3151 }
3152
3153 static void
3154 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3155 {
3156         mm_player_t* player = NULL;
3157         GstPad* srcpad = NULL;
3158         GstElement* video_selector = NULL;
3159         GstElement* audio_selector = NULL;
3160         GstElement* text_selector = NULL;
3161         MMHandleType attrs = 0;
3162         gint active_index = 0;
3163         gint64 dur_bytes = 0L;
3164
3165         player = (mm_player_t*) data;
3166
3167         LOGD("no-more-pad signal handling\n");
3168
3169         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3170                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3171                 LOGW("no need to go more");
3172
3173                 if (player->gapless.reconfigure) {
3174                         player->gapless.reconfigure = FALSE;
3175                         MMPLAYER_PLAYBACK_UNLOCK(player);
3176                 }
3177
3178                 return;
3179         }
3180
3181         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3182                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3183                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3184                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3185                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3186
3187                 if (NULL == player->streamer) {
3188                         LOGW("invalid state for buffering");
3189                         goto ERROR;
3190                 }
3191
3192                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3193                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3194
3195                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3196                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3197
3198                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3199
3200                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3201                         LOGE("fail to get duration.\n");
3202
3203                 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3204                  * use file information was already set on Q2 when it was created. */
3205                 __mm_player_streaming_set_queue2(player->streamer,
3206                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3207                                                 TRUE,                               /* use_buffering */
3208                                                 buffer_bytes,
3209                                                 init_buffering_time,
3210                                                 1.0,                                /* low percent */
3211                                                 player->ini.http_buffering_limit,   /* high percent */
3212                                                 MUXED_BUFFER_TYPE_MAX,              /* use previous buffer type setting */
3213                                                 NULL,
3214                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3215         }
3216
3217         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3218         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3219         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3220         if (video_selector) {
3221                 // [link] input-selector :: videobin
3222                 srcpad = gst_element_get_static_pad(video_selector, "src");
3223                 if (!srcpad) {
3224                         LOGE("failed to get srcpad from video selector\n");
3225                         goto ERROR;
3226                 }
3227
3228                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3229                 if (!text_selector && !audio_selector)
3230                         player->no_more_pad = TRUE;
3231
3232                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3233
3234                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3235                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3236                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3237                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3238                 }
3239         }
3240
3241         if (audio_selector) {
3242                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3243                 if ((active_index != DEFAULT_TRACK) &&
3244                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3245                         LOGW("failed to change audio track\n");
3246                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3247                 }
3248
3249                 // [link] input-selector :: audiobin
3250                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3251                 if (!srcpad) {
3252                         LOGE("failed to get srcpad from selector\n");
3253                         goto ERROR;
3254                 }
3255
3256                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3257                 if (!text_selector)
3258                         player->no_more_pad = TRUE;
3259
3260                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3261                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3262                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3263                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3264                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3265                         }
3266
3267                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3268                 } else {
3269                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3270
3271                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3272                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3273                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3274                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3275                         }
3276                 }
3277
3278                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3279
3280                 attrs = MMPLAYER_GET_ATTRS(player);
3281                 if (attrs) {
3282                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3283                         if (mmf_attrs_commit(attrs))
3284                                 LOGE("failed to commit.\n");
3285                 } else
3286                         LOGE("cannot get content attribute");
3287         } else {
3288                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3289                         LOGD("There is no audio track : remove audiobin");
3290
3291                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3292                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3293
3294                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3295                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3296                 }
3297
3298                 if (player->num_dynamic_pad == 0)
3299                         __mmplayer_pipeline_complete(NULL, player);
3300         }
3301
3302         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3303                 if (text_selector)
3304                         __mmplayer_handle_text_decode_path(player, text_selector);
3305         }
3306
3307         MMPLAYER_FLEAVE();
3308
3309 ERROR:
3310         if (srcpad) {
3311                 gst_object_unref(GST_OBJECT(srcpad));
3312                 srcpad = NULL;
3313         }
3314
3315         if (player->gapless.reconfigure) {
3316                 player->gapless.reconfigure = FALSE;
3317                 MMPLAYER_PLAYBACK_UNLOCK(player);
3318         }
3319 }
3320
3321 static void
3322 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3323 {
3324         mm_player_t* player = NULL;
3325         MMHandleType attrs = 0;
3326         GstElement* pipeline = NULL;
3327         GstCaps* caps = NULL;
3328         gchar* caps_str = NULL;
3329         GstStructure* str = NULL;
3330         const gchar* name = NULL;
3331         GstPad* sinkpad = NULL;
3332         GstElement* sinkbin = NULL;
3333         gboolean reusing = FALSE;
3334         GstElement *text_selector = NULL;
3335
3336         /* check handles */
3337         player = (mm_player_t*) data;
3338
3339         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3340         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3341
3342         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3343
3344         attrs = MMPLAYER_GET_ATTRS(player);
3345         if (!attrs) {
3346                 LOGE("cannot get content attribute\n");
3347                 goto ERROR;
3348         }
3349
3350         /* get mimetype from caps */
3351         caps = gst_pad_query_caps(pad, NULL);
3352         if (!caps) {
3353                 LOGE("cannot get caps from pad.\n");
3354                 goto ERROR;
3355         }
3356         caps_str = gst_caps_to_string(caps);
3357
3358         str = gst_caps_get_structure(caps, 0);
3359         if (!str) {
3360                 LOGE("cannot get structure from caps.\n");
3361                 goto ERROR;
3362         }
3363
3364         name = gst_structure_get_name(str);
3365         if (!name) {
3366                 LOGE("cannot get mimetype from structure.\n");
3367                 goto ERROR;
3368         }
3369
3370         //LOGD("detected mimetype : %s\n", name);
3371
3372         if (strstr(name, "audio")) {
3373                 if (player->pipeline->audiobin == NULL) {
3374                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3375                                 LOGE("failed to create audiobin. continuing without audio\n");
3376                                 goto ERROR;
3377                         }
3378
3379                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3380                         LOGD("creating audiosink bin success\n");
3381                 } else {
3382                         reusing = TRUE;
3383                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3384                         LOGD("reusing audiobin\n");
3385                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3386                 }
3387
3388                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3389                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3390
3391                 player->audiosink_linked  = 1;
3392
3393                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3394                 if (!sinkpad) {
3395                         LOGE("failed to get pad from sinkbin\n");
3396                         goto ERROR;
3397                 }
3398         } else if (strstr(name, "video")) {
3399                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3400                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3401                         player->set_mode.video_zc = TRUE;
3402
3403                 if (player->pipeline->videobin == NULL) {
3404                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3405                         /* get video surface type */
3406                         int surface_type = 0;
3407                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3408                         LOGD("display_surface_type(%d)\n", surface_type);
3409
3410                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3411                                 LOGD("not make videobin because it dose not want\n");
3412                                 goto ERROR;
3413                         }
3414
3415                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3416                                 /* mark video overlay for acquire */
3417                                 if (player->video_overlay_resource == NULL) {
3418                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3419                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3420                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3421                                                         &player->video_overlay_resource)
3422                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3423                                                 LOGE("could not mark video_overlay resource for acquire\n");
3424                                                 goto ERROR;
3425                                         }
3426                                 }
3427                         }
3428
3429                         player->interrupted_by_resource = FALSE;
3430                         /* acquire resources for video overlay */
3431                         if (mm_resource_manager_commit(player->resource_manager) !=
3432                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3433                                 LOGE("could not acquire resources for video playing\n");
3434                                 goto ERROR;
3435                         }
3436
3437                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3438                                 LOGE("failed to create videobin. continuing without video\n");
3439                                 goto ERROR;
3440                         }
3441
3442                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3443                         LOGD("creating videosink bin success\n");
3444                 } else {
3445                         reusing = TRUE;
3446                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3447                         LOGD("re-using videobin\n");
3448                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3449                 }
3450
3451                 player->videosink_linked  = 1;
3452
3453                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3454                 if (!sinkpad) {
3455                         LOGE("failed to get pad from sinkbin\n");
3456                         goto ERROR;
3457                 }
3458         } else if (strstr(name, "text")) {
3459                 if (player->pipeline->textbin == NULL) {
3460                         MMPlayerGstElement* mainbin = NULL;
3461
3462                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3463                                 LOGE("failed to create text sink bin. continuing without text\n");
3464                                 goto ERROR;
3465                         }
3466
3467                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3468                         LOGD("creating textsink bin success\n");
3469
3470                         /* FIXIT : track number shouldn't be hardcoded */
3471                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3472
3473                         player->textsink_linked  = 1;
3474                         LOGI("player->textsink_linked set to 1\n");
3475
3476                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3477                         if (!sinkpad) {
3478                                 LOGE("failed to get pad from sinkbin\n");
3479                                 goto ERROR;
3480                         }
3481
3482                         mainbin = player->pipeline->mainbin;
3483
3484                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3485                                 /* input selector */
3486                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3487                                 if (!text_selector) {
3488                                         LOGE("failed to create subtitle input selector element\n");
3489                                         goto ERROR;
3490                                 }
3491                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3492
3493                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3494                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3495
3496                                 /* warm up */
3497                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3498                                         LOGE("failed to set state(READY) to sinkbin\n");
3499                                         goto ERROR;
3500                                 }
3501
3502                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3503                                         LOGW("failed to add subtitle input selector\n");
3504                                         goto ERROR;
3505                                 }
3506
3507                                 LOGD("created element input-selector");
3508
3509                         } else {
3510                                 LOGD("already having subtitle input selector");
3511                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3512                         }
3513                 } else {
3514                         if (!player->textsink_linked) {
3515                                 LOGD("re-using textbin\n");
3516
3517                                 reusing = TRUE;
3518                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3519
3520                                 player->textsink_linked  = 1;
3521                                 LOGI("player->textsink_linked set to 1\n");
3522                         } else
3523                                 LOGD("ignoring internal subtutle since external subtitle is available");
3524                 }
3525         } else {
3526                 LOGW("unknown type of elementary stream!ignoring it...\n");
3527                 goto ERROR;
3528         }
3529
3530         if (sinkbin) {
3531                 if (!reusing) {
3532                         /* warm up */
3533                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3534                                 LOGE("failed to set state(READY) to sinkbin\n");
3535                                 goto ERROR;
3536                         }
3537
3538                         /* Added for multi audio support to avoid adding audio bin again*/
3539                         /* add */
3540                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3541                                 LOGE("failed to add sinkbin to pipeline\n");
3542                                 goto ERROR;
3543                         }
3544                 }
3545
3546                 /* link */
3547                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3548                         LOGE("failed to get pad from sinkbin\n");
3549                         goto ERROR;
3550                 }
3551
3552                 if (!reusing) {
3553                         /* run */
3554                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3555                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3556                                 goto ERROR;
3557                         }
3558
3559                         if (text_selector) {
3560                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3561                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3562                                         goto ERROR;
3563                                 }
3564                         }
3565                 }
3566
3567                 gst_object_unref(sinkpad);
3568                 sinkpad = NULL;
3569         }
3570
3571         LOGD("[handle: %p] linking sink bin success", player);
3572
3573         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3574          * streaming task. if the task blocked, then buffer will not flow to the next element
3575          *(autoplugging element). so this is special hack for streaming. please try to remove it
3576          */
3577         /* dec stream count. we can remove fakesink if it's zero */
3578         if (player->num_dynamic_pad)
3579                 player->num_dynamic_pad--;
3580
3581         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3582
3583         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3584                 __mmplayer_pipeline_complete(NULL, player);
3585
3586 ERROR:
3587
3588         MMPLAYER_FREEIF(caps_str);
3589
3590         if (caps)
3591                 gst_caps_unref(caps);
3592
3593         if (sinkpad)
3594                 gst_object_unref(GST_OBJECT(sinkpad));
3595
3596         /* flusing out new attributes */
3597         if (mmf_attrs_commit(attrs))
3598                 LOGE("failed to comit attributes\n");
3599
3600         return;
3601 }
3602
3603 static gboolean
3604 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3605 {
3606         int pro_value = 0; // in the case of expection, default will be returned.
3607         int dest_angle = rotation_angle;
3608         int rotation_type = -1;
3609
3610         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3611         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3612         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3613
3614         if (rotation_angle >= 360)
3615                 dest_angle = rotation_angle - 360;
3616
3617         /* chech if supported or not */
3618         if (dest_angle % 90) {
3619                 LOGD("not supported rotation angle = %d", rotation_angle);
3620                 return FALSE;
3621         }
3622
3623         /*
3624           * tizenwlsink (A)
3625           * custom_convert - none (B)
3626           * videoflip - none (C)
3627           */
3628         if (player->set_mode.video_zc) {
3629                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3630                         rotation_type = ROTATION_USING_CUSTOM;
3631                 else // A
3632                         rotation_type = ROTATION_USING_SINK;
3633         } else {
3634                 int surface_type = 0;
3635                 rotation_type = ROTATION_USING_FLIP;
3636
3637                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3638                 LOGD("check display surface type attribute: %d", surface_type);
3639
3640                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3641                         rotation_type = ROTATION_USING_SINK;
3642                 else
3643                         rotation_type = ROTATION_USING_FLIP; //C
3644
3645                 LOGD("using %d type for rotation", rotation_type);
3646         }
3647
3648         /* get property value for setting */
3649         switch (rotation_type) {
3650         case ROTATION_USING_SINK: // tizenwlsink
3651                 {
3652                         switch (dest_angle) {
3653                         case 0:
3654                                 break;
3655                         case 90:
3656                                 pro_value = 3; // clockwise 90
3657                                 break;
3658                         case 180:
3659                                 pro_value = 2;
3660                                 break;
3661                         case 270:
3662                                 pro_value = 1; // counter-clockwise 90
3663                                 break;
3664                         }
3665                 }
3666                 break;
3667         case ROTATION_USING_CUSTOM:
3668                 {
3669                         gchar *ename = NULL;
3670                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3671
3672                         if (g_strrstr(ename, "fimcconvert")) {
3673                                 switch (dest_angle) {
3674                                 case 0:
3675                                         break;
3676                                 case 90:
3677                                         pro_value = 90; // clockwise 90
3678                                         break;
3679                                 case 180:
3680                                         pro_value = 180;
3681                                         break;
3682                                 case 270:
3683                                         pro_value = 270; // counter-clockwise 90
3684                                         break;
3685                                 }
3686                         }
3687                 }
3688                 break;
3689         case ROTATION_USING_FLIP: // videoflip
3690                 {
3691                                 switch (dest_angle) {
3692                                 case 0:
3693                                         break;
3694                                 case 90:
3695                                         pro_value = 1; // clockwise 90
3696                                         break;
3697                                 case 180:
3698                                         pro_value = 2;
3699                                         break;
3700                                 case 270:
3701                                         pro_value = 3; // counter-clockwise 90
3702                                         break;
3703                                 }
3704                 }
3705                 break;
3706         }
3707
3708         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3709
3710         *value = pro_value;
3711
3712         return TRUE;
3713 }
3714
3715 int
3716 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3717 {
3718         /* check video sinkbin is created */
3719         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3720                 player->pipeline &&
3721                 player->pipeline->videobin &&
3722                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3723                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3724                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3725
3726         return MM_ERROR_NONE;
3727 }
3728
3729 void
3730 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3731 {
3732         int rotation_value = 0;
3733         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3734         int user_angle = 0;
3735         MMPLAYER_FENTER();
3736
3737         /* check video sinkbin is created */
3738         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3739                 return;
3740
3741         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3742
3743         /* get rotation value to set */
3744         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3745         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3746         LOGD("set video param : rotate %d", rotation_value);
3747 }
3748
3749 void
3750 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3751 {
3752         MMHandleType attrs = 0;
3753         int visible = 0;
3754         MMPLAYER_FENTER();
3755
3756         /* check video sinkbin is created */
3757         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3758                 return;
3759
3760         attrs = MMPLAYER_GET_ATTRS(player);
3761         MMPLAYER_RETURN_IF_FAIL(attrs);
3762
3763         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3764         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3765         LOGD("set video param : visible %d", visible);
3766 }
3767
3768 void
3769 __mmplayer_video_param_set_display_method(mm_player_t* player)
3770 {
3771         MMHandleType attrs = 0;
3772         int display_method = 0;
3773         MMPLAYER_FENTER();
3774
3775         /* check video sinkbin is created */
3776         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3777                 return;
3778
3779         attrs = MMPLAYER_GET_ATTRS(player);
3780         MMPLAYER_RETURN_IF_FAIL(attrs);
3781
3782         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3783         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3784         LOGD("set video param : method %d", display_method);
3785 }
3786
3787 void
3788 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3789 {
3790         MMHandleType attrs = 0;
3791         void *handle = NULL;
3792         /*set wl_display*/
3793         int wl_window_x = 0;
3794         int wl_window_y = 0;
3795         int wl_window_width = 0;
3796         int wl_window_height = 0;
3797         MMPLAYER_FENTER();
3798
3799         /* check video sinkbin is created */
3800         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3801                 return;
3802
3803         attrs = MMPLAYER_GET_ATTRS(player);
3804         MMPLAYER_RETURN_IF_FAIL(attrs);
3805
3806         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3807
3808         if (handle) {
3809                 /*It should be set after setting window*/
3810                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3811                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3812                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3813                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3814
3815                 /* After setting window handle, set render      rectangle */
3816                 gst_video_overlay_set_render_rectangle(
3817                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3818                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3819                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3820                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3821
3822         }
3823 }
3824 void
3825 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3826 {
3827         MMHandleType attrs = 0;
3828         void *handle = NULL;
3829
3830         /* check video sinkbin is created */
3831         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3832                 return;
3833
3834         attrs = MMPLAYER_GET_ATTRS(player);
3835         MMPLAYER_RETURN_IF_FAIL(attrs);
3836
3837         /* common case if using overlay surface */
3838         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3839
3840         if (handle) {
3841                 /* default is using wl_surface_id */
3842                 unsigned int wl_surface_id      = 0;
3843                 wl_surface_id = *(int*)handle;
3844                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3845                 gst_video_overlay_set_wl_window_wl_surface_id(
3846                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3847                                 *(int*)handle);
3848         } else
3849                 /* FIXIT : is it error case? */
3850                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3851 }
3852
3853
3854 int
3855 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3856 {
3857         bool update_all_param = FALSE;
3858         MMPLAYER_FENTER();
3859
3860         /* check video sinkbin is created */
3861         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3862                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3863
3864         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3865                 LOGE("can not find tizenwlsink");
3866                 return MM_ERROR_PLAYER_INTERNAL;
3867         }
3868
3869         LOGD("param_name : %s", param_name);
3870         if (!g_strcmp0(param_name, "update_all_param"))
3871                 update_all_param = TRUE;
3872
3873         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3874                 __mmplayer_video_param_set_display_overlay(player);
3875         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3876                 __mmplayer_video_param_set_display_method(player);
3877         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3878                 __mmplayer_video_param_set_render_rectangle(player);
3879         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3880                 __mmplayer_video_param_set_display_visible(player);
3881         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3882                 __mmplayer_video_param_set_display_rotation(player);
3883
3884         return MM_ERROR_NONE;
3885 }
3886
3887 int
3888 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3889 {
3890         MMHandleType attrs = 0;
3891         int surface_type = 0;
3892         int ret = MM_ERROR_NONE;
3893
3894         MMPLAYER_FENTER();
3895
3896         /* check video sinkbin is created */
3897         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3898                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3899
3900         attrs = MMPLAYER_GET_ATTRS(player);
3901         if (!attrs) {
3902                 LOGE("cannot get content attribute");
3903                 return MM_ERROR_PLAYER_INTERNAL;
3904         }
3905         LOGD("param_name : %s", param_name);
3906
3907         /* update display surface */
3908         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3909         LOGD("check display surface type attribute: %d", surface_type);
3910
3911         /* configuring display */
3912         switch (surface_type) {
3913         case MM_DISPLAY_SURFACE_OVERLAY:
3914                 {
3915                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3916                         if (ret != MM_ERROR_NONE)
3917                                 return ret;
3918                 }
3919                 break;
3920         }
3921
3922         MMPLAYER_FLEAVE();
3923
3924         return MM_ERROR_NONE;
3925 }
3926
3927 int
3928 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3929 {
3930         gboolean disable_overlay = FALSE;
3931         mm_player_t* player = (mm_player_t*) hplayer;
3932         int ret = MM_ERROR_NONE;
3933
3934         MMPLAYER_FENTER();
3935         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3937                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3938                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3939
3940         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3941                 LOGW("Display control is not supported");
3942                 return MM_ERROR_PLAYER_INTERNAL;
3943         }
3944
3945         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3946
3947         if (audio_only == (bool)disable_overlay) {
3948                 LOGE("It's the same with current setting: (%d)", audio_only);
3949                 return MM_ERROR_NONE;
3950         }
3951
3952         if (audio_only) {
3953                 LOGE("disable overlay");
3954                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3955
3956                 /* release overlay resource */
3957                 if (player->video_overlay_resource != NULL) {
3958                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3959                                         player->video_overlay_resource);
3960                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3961                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3962                                 goto ERROR;
3963                         }
3964                         player->video_overlay_resource = NULL;
3965                 }
3966
3967                 ret = mm_resource_manager_commit(player->resource_manager);
3968                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3969                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3970                         goto ERROR;
3971                 }
3972         } else {
3973                 /* mark video overlay for acquire */
3974                 if (player->video_overlay_resource == NULL) {
3975                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3976                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3977                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3978                                         &player->video_overlay_resource);
3979                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3980                                 LOGE("could not prepare for video_overlay resource\n");
3981                                 goto ERROR;
3982                         }
3983                 }
3984
3985                 player->interrupted_by_resource = FALSE;
3986                 /* acquire resources for video overlay */
3987                 ret = mm_resource_manager_commit(player->resource_manager);
3988                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989                         LOGE("could not acquire resources for video playing\n");
3990                         goto ERROR;
3991                 }
3992
3993                 LOGD("enable overlay");
3994                 __mmplayer_video_param_set_display_overlay(player);
3995                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3996         }
3997
3998 ERROR:
3999         MMPLAYER_FLEAVE();
4000         return MM_ERROR_NONE;
4001 }
4002
4003 int
4004 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4005 {
4006         mm_player_t* player = (mm_player_t*) hplayer;
4007         gboolean disable_overlay = FALSE;
4008
4009         MMPLAYER_FENTER();
4010
4011         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4012         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4013         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4014                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4015                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4016
4017         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4018                 LOGW("Display control is not supported");
4019                 return MM_ERROR_PLAYER_INTERNAL;
4020         }
4021
4022         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4023
4024         *paudio_only = (bool)(disable_overlay);
4025
4026         LOGD("audio_only : %d", *paudio_only);
4027
4028         MMPLAYER_FLEAVE();
4029
4030         return MM_ERROR_NONE;
4031 }
4032
4033 static int
4034 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4035 {
4036         GList* bucket = element_bucket;
4037         MMPlayerGstElement* element = NULL;
4038         MMPlayerGstElement* prv_element = NULL;
4039         gint successful_link_count = 0;
4040
4041         MMPLAYER_FENTER();
4042
4043         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4044
4045         prv_element = (MMPlayerGstElement*)bucket->data;
4046         bucket = bucket->next;
4047
4048         for (; bucket; bucket = bucket->next) {
4049                 element = (MMPlayerGstElement*)bucket->data;
4050
4051                 if (element && element->gst) {
4052                         /* If next element is audio appsrc then make a separate audio pipeline */
4053                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4054                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4055                                 prv_element = element;
4056                                 continue;
4057                         }
4058
4059                         if (prv_element && prv_element->gst) {
4060                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4061                                         LOGD("linking [%s] to [%s] success\n",
4062                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4063                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4064                                         successful_link_count++;
4065                                 } else {
4066                                         LOGD("linking [%s] to [%s] failed\n",
4067                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4068                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4069                                         return -1;
4070                                 }
4071                         }
4072                 }
4073
4074                 prv_element = element;
4075         }
4076
4077         MMPLAYER_FLEAVE();
4078
4079         return successful_link_count;
4080 }
4081
4082 static int
4083 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4084 {
4085         GList* bucket = element_bucket;
4086         MMPlayerGstElement* element = NULL;
4087         int successful_add_count = 0;
4088
4089         MMPLAYER_FENTER();
4090
4091         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4092         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4093
4094         for (; bucket; bucket = bucket->next) {
4095                 element = (MMPlayerGstElement*)bucket->data;
4096
4097                 if (element && element->gst) {
4098                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4099                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4100                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4101                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4102                                 return 0;
4103                         }
4104                         successful_add_count++;
4105                 }
4106         }
4107
4108         MMPLAYER_FLEAVE();
4109
4110         return successful_add_count;
4111 }
4112
4113 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4114 {
4115         mm_player_t* player = (mm_player_t*) data;
4116         GstCaps *caps = NULL;
4117         GstStructure *str = NULL;
4118         const char *name;
4119
4120         MMPLAYER_FENTER();
4121
4122         MMPLAYER_RETURN_IF_FAIL(pad)
4123         MMPLAYER_RETURN_IF_FAIL(unused)
4124         MMPLAYER_RETURN_IF_FAIL(data)
4125
4126         caps = gst_pad_get_current_caps(pad);
4127         if (!caps)
4128                 return;
4129
4130         str = gst_caps_get_structure(caps, 0);
4131         if (!str)
4132                 goto ERROR;
4133
4134         name = gst_structure_get_name(str);
4135         if (!name)
4136                 goto ERROR;
4137
4138         LOGD("name = %s\n", name);
4139
4140         if (strstr(name, "audio")) {
4141                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4142
4143                 if (player->audio_stream_changed_cb) {
4144                         LOGE("call the audio stream changed cb\n");
4145                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4146                 }
4147         } else if (strstr(name, "video")) {
4148                 if ((name = gst_structure_get_string(str, "format")))
4149                         player->set_mode.video_zc = name[0] == 'S';
4150
4151                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4152
4153                 if (player->video_stream_changed_cb) {
4154                         LOGE("call the video stream changed cb\n");
4155                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4156                 }
4157         } else
4158                 goto ERROR;
4159
4160 ERROR:
4161
4162         gst_caps_unref(caps);
4163
4164         MMPLAYER_FLEAVE();
4165
4166         return;
4167 }
4168
4169
4170
4171 /**
4172  * This function is to create audio pipeline for playing.
4173  *
4174  * @param       player          [in]    handle of player
4175  *
4176  * @return      This function returns zero on success.
4177  * @remark
4178  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4179  */
4180 /* macro for code readability. just for sinkbin-creation functions */
4181 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4182 do {\
4183         x_bin[x_id].id = x_id;\
4184         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4185         if (!x_bin[x_id].gst) {\
4186                 LOGE("failed to create %s \n", x_factory);\
4187                 goto ERROR;\
4188         } else {\
4189                 if (x_player->ini.set_dump_element_flag)\
4190                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4191         } \
4192         if (x_add_bucket)\
4193                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4194 } while (0);
4195
4196 static void
4197 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4198 {
4199         GList *l = NULL;
4200
4201         MMPLAYER_FENTER();
4202         MMPLAYER_RETURN_IF_FAIL(player);
4203
4204         if (player->audio_stream_buff_list) {
4205                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4206                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4207                         if (tmp) {
4208                                 if (send_all) {
4209                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4210                                         __mmplayer_audio_stream_send_data(player, tmp);
4211                                 }
4212                                 if (tmp->pcm_data)
4213                                         g_free(tmp->pcm_data);
4214                                 g_free(tmp);
4215                         }
4216                 }
4217                 g_list_free(player->audio_stream_buff_list);
4218                 player->audio_stream_buff_list = NULL;
4219         }
4220
4221         MMPLAYER_FLEAVE();
4222 }
4223
4224 static void
4225 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4226 {
4227         MMPlayerAudioStreamDataType audio_stream = { 0, };
4228
4229         MMPLAYER_FENTER();
4230         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4231
4232         audio_stream.bitrate = a_buffer->bitrate;
4233         audio_stream.channel = a_buffer->channel;
4234         audio_stream.depth = a_buffer->depth;
4235         audio_stream.is_little_endian = a_buffer->is_little_endian;
4236         audio_stream.channel_mask = a_buffer->channel_mask;
4237         audio_stream.data_size = a_buffer->data_size;
4238         audio_stream.data = a_buffer->pcm_data;
4239
4240         /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4241         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4242
4243         MMPLAYER_FLEAVE();
4244 }
4245
4246 static void
4247 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4248 {
4249         mm_player_t* player = (mm_player_t*) data;
4250
4251         gint channel = 0;
4252         gint rate = 0;
4253         gint depth = 0;
4254         gint endianness = 0;
4255         guint64 channel_mask = 0;
4256         void *a_data = NULL;
4257         gint a_size = 0;
4258         mm_player_audio_stream_buff_t *a_buffer = NULL;
4259         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4260         GList *l = NULL;
4261
4262         MMPLAYER_FENTER();
4263         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4264
4265         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4266         a_data = mapinfo.data;
4267         a_size = mapinfo.size;
4268
4269         GstCaps *caps = gst_pad_get_current_caps(pad);
4270         GstStructure *structure = gst_caps_get_structure(caps, 0);
4271
4272         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4273         gst_structure_get_int(structure, "rate", &rate);
4274         gst_structure_get_int(structure, "channels", &channel);
4275         gst_structure_get_int(structure, "depth", &depth);
4276         gst_structure_get_int(structure, "endianness", &endianness);
4277         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4278         gst_caps_unref(GST_CAPS(caps));
4279
4280         /* In case of the sync is false, use buffer list.              *
4281          * The num of buffer list depends on the num of audio channels */
4282         if (player->audio_stream_buff_list) {
4283                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4284                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4285                         if (tmp) {
4286                                 if (channel_mask == tmp->channel_mask) {
4287                                         /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4288                                         if (tmp->data_size + a_size < tmp->buff_size) {
4289                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4290                                                 tmp->data_size += a_size;
4291                                         } else {
4292                                                 /* send data to client */
4293                                                 __mmplayer_audio_stream_send_data(player, tmp);
4294
4295                                                 if (a_size > tmp->buff_size) {
4296                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4297                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4298                                                         if (tmp->pcm_data == NULL) {
4299                                                                 LOGE("failed to realloc data.");
4300                                                                 goto DONE;
4301                                                         }
4302                                                         tmp->buff_size = a_size;
4303                                                 }
4304                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4305                                                 memcpy(tmp->pcm_data, a_data, a_size);
4306                                                 tmp->data_size = a_size;
4307                                         }
4308                                         goto DONE;
4309                                 }
4310                         } else {
4311                                 LOGE("data is empty in list.");
4312                                 goto DONE;
4313                         }
4314                 }
4315         }
4316
4317         /* create new audio stream data */
4318         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4319         if (a_buffer == NULL) {
4320                 LOGE("failed to alloc data.");
4321                 goto DONE;
4322         }
4323         a_buffer->bitrate = rate;
4324         a_buffer->channel = channel;
4325         a_buffer->depth = depth;
4326         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4327         a_buffer->channel_mask = channel_mask;
4328         a_buffer->data_size = a_size;
4329
4330         if (!player->audio_stream_sink_sync) {
4331                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4332                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4333                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4334                 if (a_buffer->pcm_data == NULL) {
4335                         LOGE("failed to alloc data.");
4336                         g_free(a_buffer);
4337                         goto DONE;
4338                 }
4339                 memcpy(a_buffer->pcm_data, a_data, a_size);
4340                 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4341                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4342         } else {
4343                 /* If sync is TRUE, send data directly. */
4344                 a_buffer->pcm_data = a_data;
4345                 __mmplayer_audio_stream_send_data(player, a_buffer);
4346                 g_free(a_buffer);
4347         }
4348
4349 DONE:
4350         gst_buffer_unmap(buffer, &mapinfo);
4351         MMPLAYER_FLEAVE();
4352 }
4353
4354 static void
4355 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4356 {
4357         mm_player_t* player = (mm_player_t*)data;
4358         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4359         GstPad* sinkpad = NULL;
4360         GstElement *queue = NULL, *sink = NULL;
4361
4362         MMPLAYER_FENTER();
4363         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4364
4365         queue = gst_element_factory_make("queue", NULL);
4366         if (queue == NULL) {
4367                 LOGD("fail make queue\n");
4368                 goto ERROR;
4369         }
4370
4371         sink = gst_element_factory_make("fakesink", NULL);
4372         if (sink == NULL) {
4373                 LOGD("fail make fakesink\n");
4374                 goto ERROR;
4375         }
4376
4377         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4378
4379         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4380                 LOGW("failed to link queue & sink\n");
4381                 goto ERROR;
4382         }
4383
4384         sinkpad = gst_element_get_static_pad(queue, "sink");
4385
4386         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4387                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4388                 goto ERROR;
4389         }
4390
4391         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4392
4393         gst_object_unref(sinkpad);
4394         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4395         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4396
4397         gst_element_set_state(sink, GST_STATE_PAUSED);
4398         gst_element_set_state(queue, GST_STATE_PAUSED);
4399
4400         MMPLAYER_SIGNAL_CONNECT(player,
4401                 G_OBJECT(sink),
4402                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4403                 "handoff",
4404                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4405                 (gpointer)player);
4406
4407         MMPLAYER_FLEAVE();
4408         return;
4409
4410 ERROR:
4411         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4412         if (queue) {
4413                 gst_object_unref(GST_OBJECT(queue));
4414                 queue = NULL;
4415         }
4416         if (sink) {
4417                 gst_object_unref(GST_OBJECT(sink));
4418                 sink = NULL;
4419         }
4420         if (sinkpad) {
4421                 gst_object_unref(GST_OBJECT(sinkpad));
4422                 sinkpad = NULL;
4423         }
4424
4425         return;
4426 }
4427
4428 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4429 {
4430         #define MAX_PROPS_LEN 128
4431         gint latency_mode = 0;
4432         gchar *stream_type = NULL;
4433         gchar *latency = NULL;
4434         gint stream_id = 0;
4435         gchar stream_props[MAX_PROPS_LEN] = {0,};
4436         GstStructure *props = NULL;
4437
4438         /* set volume table
4439          * It should be set after player creation through attribute.
4440          * But, it can not be changed during playing.
4441          */
4442         MMPLAYER_FENTER();
4443         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4444         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4445
4446         if (!stream_type) {
4447                 LOGE("stream_type is null.\n");
4448         } else {
4449                 if (player->sound.focus_id)
4450                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4451                                         stream_type, stream_id, player->sound.focus_id);
4452                 else
4453                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4454                                         stream_type, stream_id);
4455                 props = gst_structure_from_string(stream_props, NULL);
4456                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4457                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4458                         stream_type, stream_id, player->sound.focus_id, stream_props);
4459                 gst_structure_free(props);
4460         }
4461
4462         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4463
4464         switch (latency_mode) {
4465         case AUDIO_LATENCY_MODE_LOW:
4466                 latency = g_strndup("low", 3);
4467                 break;
4468         case AUDIO_LATENCY_MODE_MID:
4469                 latency = g_strndup("mid", 3);
4470                 break;
4471         case AUDIO_LATENCY_MODE_HIGH:
4472                 latency = g_strndup("high", 4);
4473                 break;
4474         };
4475
4476         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4477                         "latency", latency,
4478                         NULL);
4479
4480         LOGD("audiosink property - latency=%s \n", latency);
4481
4482         g_free(latency);
4483
4484         MMPLAYER_FLEAVE();
4485 }
4486
4487 static int
4488 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4489 {
4490         MMPlayerGstElement* first_element = NULL;
4491         MMPlayerGstElement* audiobin = NULL;
4492         MMHandleType attrs = 0;
4493         GstPad *pad = NULL;
4494         GstPad *ghostpad = NULL;
4495         GList* element_bucket = NULL;
4496         gboolean link_audio_sink_now = TRUE;
4497         int i = 0;
4498         GstCaps *acaps;
4499
4500         MMPLAYER_FENTER();
4501
4502         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4503
4504         /* alloc handles */
4505         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4506         if (!audiobin) {
4507                 LOGE("failed to allocate memory for audiobin\n");
4508                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4509         }
4510
4511         attrs = MMPLAYER_GET_ATTRS(player);
4512
4513         /* create bin */
4514         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4515         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4516         if (!audiobin[MMPLAYER_A_BIN].gst) {
4517                 LOGE("failed to create audiobin\n");
4518                 goto ERROR;
4519         }
4520
4521         /* take it */
4522         player->pipeline->audiobin = audiobin;
4523
4524         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4525
4526         /* Adding audiotp plugin for reverse trickplay feature */
4527 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4528
4529         /* converter */
4530         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4531
4532         /* replaygain volume */
4533         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4534         if (player->sound.rg_enable)
4535                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4536         else
4537                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4538
4539         /* resampler */
4540         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4541
4542         if (player->set_mode.pcm_extraction) {
4543                 // pcm extraction only and no sound output
4544                 if (player->audio_stream_render_cb_ex) {
4545                         char *caps_str = NULL;
4546                         GstCaps* caps = NULL;
4547                         gchar *format = NULL;
4548
4549                         /* capsfilter */
4550                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4551
4552                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4553
4554                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4555
4556                         caps = gst_caps_new_simple("audio/x-raw",
4557                                         "format", G_TYPE_STRING, format,
4558                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4559                                         "channels", G_TYPE_INT, player->pcm_channel,
4560                                         NULL);
4561                         caps_str = gst_caps_to_string(caps);
4562                         LOGD("new caps : %s\n", caps_str);
4563
4564                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4565
4566                         /* clean */
4567                         gst_caps_unref(caps);
4568                         MMPLAYER_FREEIF(caps_str);
4569
4570                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4571
4572                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4573                         /* raw pad handling signal */
4574                         MMPLAYER_SIGNAL_CONNECT(player,
4575                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4576                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4577                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4578                 } else {
4579                         int dst_samplerate = 0;
4580                         int dst_channels = 0;
4581                         int dst_depth = 0;
4582                         char *caps_str = NULL;
4583                         GstCaps* caps = NULL;
4584
4585                         /* get conf. values */
4586                         mm_attrs_multiple_get(player->attrs,
4587                                                 NULL,
4588                                                 "pcm_extraction_samplerate", &dst_samplerate,
4589                                                 "pcm_extraction_channels", &dst_channels,
4590                                                 "pcm_extraction_depth", &dst_depth,
4591                                                 NULL);
4592
4593                         /* capsfilter */
4594                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4595                         caps = gst_caps_new_simple("audio/x-raw",
4596                                         "rate", G_TYPE_INT, dst_samplerate,
4597                                         "channels", G_TYPE_INT, dst_channels,
4598                                         "depth", G_TYPE_INT, dst_depth,
4599                                         NULL);
4600                         caps_str = gst_caps_to_string(caps);
4601                         LOGD("new caps : %s\n", caps_str);
4602
4603                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4604
4605                         /* clean */
4606                         gst_caps_unref(caps);
4607                         MMPLAYER_FREEIF(caps_str);
4608
4609                         /* fake sink */
4610                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4611
4612                         /* set sync */
4613                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4614                 }
4615         } else {
4616                 // normal playback
4617                 //GstCaps* caps = NULL;
4618                 gint channels = 0;
4619
4620                 /* for logical volume control */
4621                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4622                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4623
4624                 if (player->sound.mute) {
4625                         LOGD("mute enabled\n");
4626                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4627                 }
4628
4629 #if 0
4630                 /*capsfilter */
4631                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4632                 caps = gst_caps_from_string("audio/x-raw-int, "
4633                                         "endianness = (int) LITTLE_ENDIAN, "
4634                                         "signed = (boolean) true, "
4635                                         "width = (int) 16, "
4636                                         "depth = (int) 16");
4637                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4638                 gst_caps_unref(caps);
4639 #endif
4640
4641                 /* check if multi-channels */
4642                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4643                         GstPad *srcpad = NULL;
4644                         GstCaps *caps = NULL;
4645
4646                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4647                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4648                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4649                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4650                                         if (str)
4651                                                 gst_structure_get_int(str, "channels", &channels);
4652                                         gst_caps_unref(caps);
4653                                 }
4654                                 gst_object_unref(srcpad);
4655                         }
4656                 }
4657
4658                 /* audio effect element. if audio effect is enabled */
4659                 if ((strcmp(player->ini.audioeffect_element, ""))
4660                         && (channels <= 2)
4661                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4662                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4663
4664                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4665
4666                         if ((!player->bypass_audio_effect)
4667                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4668                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4669                                         if (!_mmplayer_audio_effect_custom_apply(player))
4670                                                 LOGI("apply audio effect(custom) setting success\n");
4671                                 }
4672                         }
4673
4674                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4675                                 && (player->set_mode.rich_audio))
4676                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4677                 }
4678
4679                 /* create audio sink */
4680                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4681                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4682                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4683
4684                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4685                 if (player->is_360_feature_enabled &&
4686                         player->is_content_spherical &&
4687                         channels == 4 &&
4688                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4689                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4690                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4691
4692                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4693
4694                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4695
4696                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4697                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4698                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4699                         gst_caps_unref(acaps);
4700
4701                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4702                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4703                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4704                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4705
4706                         player->is_openal_plugin_used = TRUE;
4707
4708                         if (player->video360_yaw_radians <= M_PI &&
4709                                         player->video360_yaw_radians >= -M_PI &&
4710                                         player->video360_pitch_radians <= M_PI_2 &&
4711                                         player->video360_pitch_radians >= -M_PI_2) {
4712                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4713                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4714                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4715                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4716                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4717                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4718                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4719                         }
4720                 } else {
4721                         if (player->is_360_feature_enabled && player->is_content_spherical)
4722                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4723                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4724                 }
4725
4726                 /* qos on */
4727                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4728                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4729
4730
4731                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4732                         (player->videodec_linked && player->ini.use_system_clock)) {
4733                         LOGD("system clock will be used.\n");
4734                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4735                 }
4736
4737                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4738                         __mmplayer_gst_set_audiosink_property(player, attrs);
4739         }
4740
4741         if (audiobin[MMPLAYER_A_SINK].gst) {
4742                 GstPad *sink_pad = NULL;
4743                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4744                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4745                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4746                 gst_object_unref(GST_OBJECT(sink_pad));
4747         }
4748
4749         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4750
4751         /* adding created elements to bin */
4752         LOGD("adding created elements to bin\n");
4753         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4754                 LOGE("failed to add elements\n");
4755                 goto ERROR;
4756         }
4757
4758         /* linking elements in the bucket by added order. */
4759         LOGD("Linking elements in the bucket by added order.\n");
4760         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4761                 LOGE("failed to link elements\n");
4762                 goto ERROR;
4763         }
4764
4765         /* get first element's sinkpad for creating ghostpad */
4766         first_element = (MMPlayerGstElement *)element_bucket->data;
4767         if (!first_element) {
4768                 LOGE("failed to get first elem\n");
4769                 goto ERROR;
4770         }
4771
4772         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4773         if (!pad) {
4774                 LOGE("failed to get pad from first element of audiobin\n");
4775                 goto ERROR;
4776         }
4777
4778         ghostpad = gst_ghost_pad_new("sink", pad);
4779         if (!ghostpad) {
4780                 LOGE("failed to create ghostpad\n");
4781                 goto ERROR;
4782         }
4783
4784         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4785                 LOGE("failed to add ghostpad to audiobin\n");
4786                 goto ERROR;
4787         }
4788
4789         gst_object_unref(pad);
4790
4791         g_list_free(element_bucket);
4792         MMPLAYER_FLEAVE();
4793
4794         return MM_ERROR_NONE;
4795
4796 ERROR:
4797
4798         LOGD("ERROR : releasing audiobin\n");
4799
4800         if (pad)
4801                 gst_object_unref(GST_OBJECT(pad));
4802
4803         if (ghostpad)
4804                 gst_object_unref(GST_OBJECT(ghostpad));
4805
4806         if (element_bucket)
4807                 g_list_free(element_bucket);
4808
4809         /* release element which are not added to bin */
4810         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4811                 /* NOTE : skip bin */
4812                 if (audiobin[i].gst) {
4813                         GstObject* parent = NULL;
4814                         parent = gst_element_get_parent(audiobin[i].gst);
4815
4816                         if (!parent) {
4817                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4818                                 audiobin[i].gst = NULL;
4819                         } else
4820                                 gst_object_unref(GST_OBJECT(parent));
4821                 }
4822         }
4823
4824         /* release audiobin with it's childs */
4825         if (audiobin[MMPLAYER_A_BIN].gst)
4826                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4827
4828         MMPLAYER_FREEIF(audiobin);
4829
4830         player->pipeline->audiobin = NULL;
4831
4832         return MM_ERROR_PLAYER_INTERNAL;
4833 }
4834
4835 static GstPadProbeReturn
4836 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4837 {
4838         mm_player_t* player = (mm_player_t*) u_data;
4839         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4840         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4841
4842         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4843
4844         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4845                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4846
4847         return GST_PAD_PROBE_OK;
4848 }
4849
4850 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4851 {
4852         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4853 }
4854
4855 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4856 {
4857         int ret = MM_ERROR_NONE;
4858         GList *l = NULL;
4859         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4860         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4861
4862         MMPLAYER_VIDEO_BO_LOCK(player);
4863
4864         if (player->video_bo_list) {
4865                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4866                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4867                         if (tmp && tmp->bo == bo) {
4868                                 tmp->using = FALSE;
4869                                 LOGD("release bo %p", bo);
4870                                 tbm_bo_unref(tmp->bo);
4871                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4872                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4873                                 return ret;
4874                         }
4875                 }
4876         } else {
4877                 /* hw codec is running or the list was reset for DRC. */
4878                 LOGW("there is no bo list.");
4879         }
4880         MMPLAYER_VIDEO_BO_UNLOCK(player);
4881
4882         LOGW("failed to find bo %p", bo);
4883         return ret;
4884 }
4885
4886 static void
4887 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4888 {
4889         GList *l = NULL;
4890
4891         MMPLAYER_FENTER();
4892         MMPLAYER_RETURN_IF_FAIL(player);
4893
4894         MMPLAYER_VIDEO_BO_LOCK(player);
4895         if (player->video_bo_list) {
4896                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4897                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4898                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4899                         if (tmp) {
4900                                 if (tmp->bo)
4901                                         tbm_bo_unref(tmp->bo);
4902                                 g_free(tmp);
4903                         }
4904                 }
4905                 g_list_free(player->video_bo_list);
4906                 player->video_bo_list = NULL;
4907         }
4908         player->video_bo_size = 0;
4909         MMPLAYER_VIDEO_BO_UNLOCK(player);
4910
4911         MMPLAYER_FLEAVE();
4912         return;
4913 }
4914
4915 static void*
4916 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4917 {
4918         GList *l = NULL;
4919         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4920         gboolean ret = TRUE;
4921
4922         /* check DRC, if it is, destroy the prev bo list to create again */
4923         if (player->video_bo_size != size) {
4924                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4925                 __mmplayer_video_stream_destroy_bo_list(player);
4926                 player->video_bo_size = size;
4927         }
4928
4929         MMPLAYER_VIDEO_BO_LOCK(player);
4930
4931         if ((!player->video_bo_list) ||
4932                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4933
4934                 /* create bo list */
4935                 int idx = 0;
4936                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4937
4938                 if (player->video_bo_list) {
4939                         /* if bo list did not created all, try it again. */
4940                         idx = g_list_length(player->video_bo_list);
4941                         LOGD("bo list exist(len: %d)", idx);
4942                 }
4943
4944                 for (; idx < player->ini.num_of_video_bo; idx++) {
4945                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4946                         if (!bo_info) {
4947                                 LOGE("Fail to alloc bo_info.");
4948                                 break;
4949                         }
4950                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4951                         if (!bo_info->bo) {
4952                                 LOGE("Fail to tbm_bo_alloc.");
4953                                 g_free(bo_info);
4954                                 break;
4955                         }
4956                         bo_info->using = FALSE;
4957                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4958                 }
4959
4960                 /* update video num buffers */
4961                 player->video_num_buffers = idx;
4962                 if (idx == player->ini.num_of_video_bo)
4963                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4964
4965                 if (idx == 0) {
4966                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4967                         return NULL;
4968                 }
4969
4970                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4971         }
4972
4973         while (TRUE) {
4974                 /* get bo from list*/
4975                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4976                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4977                         if (tmp && (tmp->using == FALSE)) {
4978                                 LOGD("found bo %p to use", tmp->bo);
4979                                 tmp->using = TRUE;
4980                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4981                                 return tbm_bo_ref(tmp->bo);
4982                         }
4983                 }
4984                 if (!ret) {
4985                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4986                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4987                         return NULL;
4988                 }
4989
4990                 if (player->ini.video_bo_timeout <= 0) {
4991                         MMPLAYER_VIDEO_BO_WAIT(player);
4992                 } else {
4993                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4994                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4995                 }
4996                 continue;
4997         }
4998 }
4999
5000 static void
5001 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5002 {
5003         mm_player_t* player = (mm_player_t*)data;
5004         MMPLAYER_FENTER();
5005         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5006
5007         /* send prerolled pkt */
5008         player->video_stream_prerolled = FALSE;
5009
5010         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5011
5012         /* not to send prerolled pkt again */
5013         player->video_stream_prerolled = TRUE;
5014 }
5015
5016 static void
5017 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5018 {
5019         mm_player_t* player = (mm_player_t*)data;
5020         GstCaps *caps = NULL;
5021         MMPlayerVideoStreamDataType *stream = NULL;
5022         MMVideoBuffer *video_buffer = NULL;
5023         GstMemory *dataBlock = NULL;
5024         GstMemory *metaBlock = NULL;
5025         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5026         GstStructure *structure = NULL;
5027         const gchar *string_format = NULL;
5028         unsigned int fourcc = 0;
5029
5030         MMPLAYER_FENTER();
5031         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5032
5033         if (player->video_stream_prerolled) {
5034                 player->video_stream_prerolled = FALSE;
5035                 LOGD("skip the prerolled pkt not to send it again");
5036                 return;
5037         }
5038
5039         caps = gst_pad_get_current_caps(pad);
5040         if (caps == NULL) {
5041                 LOGE("Caps is NULL.");
5042                 return;
5043         }
5044
5045         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5046
5047         /* clear stream data structure */
5048         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5049         if (!stream) {
5050                 LOGE("failed to alloc mem for video data");
5051                 return;
5052         }
5053
5054         structure = gst_caps_get_structure(caps, 0);
5055         gst_structure_get_int(structure, "width", &(stream->width));
5056         gst_structure_get_int(structure, "height", &(stream->height));
5057         string_format = gst_structure_get_string(structure, "format");
5058         if (string_format)
5059                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5060         stream->format = util_get_pixtype(fourcc);
5061         gst_caps_unref(caps);
5062         caps = NULL;
5063
5064         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5065
5066     /*
5067         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5068                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5069     */
5070
5071         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5072                 LOGE("Wrong condition!!");
5073                 goto ERROR;
5074         }
5075
5076         /* set size and timestamp */
5077         dataBlock = gst_buffer_peek_memory(buffer, 0);
5078         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5079         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5080
5081         /* check zero-copy */
5082         if (player->set_mode.video_zc &&
5083                 player->set_mode.media_packet_video_stream &&
5084                 gst_buffer_n_memory(buffer) > 1) {
5085                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5086                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5087                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5088         }
5089
5090         if (video_buffer) { /* hw codec */
5091                 /* set tbm bo */
5092                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5093                         int i = 0;
5094
5095                         /* copy pointer of tbm bo, stride, elevation */
5096                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5097                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5098                                 i++;
5099                         }
5100                 } else {
5101                         LOGE("Not support video buffer format");
5102                         goto ERROR;
5103                 }
5104                 memcpy(stream->stride, video_buffer->stride_width,
5105                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5106                 memcpy(stream->elevation, video_buffer->stride_height,
5107                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5108
5109                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5110                 stream->internal_buffer = gst_buffer_ref(buffer);
5111         } else { /* sw codec */
5112                 int i = 0;
5113                 int j = 0;
5114                 int k = 0;
5115                 int ret = TBM_SURFACE_ERROR_NONE;
5116                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5117                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5118                 int size = 0;
5119                 unsigned char *src = NULL;
5120                 unsigned char *dest = NULL;
5121                 tbm_bo_handle thandle;
5122                 tbm_surface_h surface;
5123                 tbm_surface_info_s info;
5124                 gboolean gst_ret;
5125
5126                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5127                 if (!gst_ret) {
5128                         LOGE("fail to gst_memory_map");
5129                         goto ERROR;
5130                 }
5131
5132
5133                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5134                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5135
5136                         ret = tbm_surface_get_info(surface, &info);
5137
5138                         if (ret != TBM_SURFACE_ERROR_NONE) {
5139                                 tbm_surface_destroy(surface);
5140                                 goto ERROR;
5141                         }
5142                         tbm_surface_destroy(surface);
5143
5144                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5145                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5146                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5147                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5148                         stream->stride[0] = info.planes[0].stride;
5149                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5150                         stream->stride[1] = info.planes[1].stride;
5151                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5152                         stream->stride[2] = info.planes[2].stride;
5153                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5154                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5155                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5156                         stream->stride[0] = stream->width * 4;
5157                         stream->elevation[0] = stream->height;
5158                         size = stream->stride[0] * stream->height;
5159                 } else {
5160                         LOGE("Not support format %d", stream->format);
5161                         goto ERROR;
5162                 }
5163
5164                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5165                 if (!stream->bo[0]) {
5166                         LOGE("Fail to tbm_bo_alloc!!");
5167                         goto ERROR;
5168                 }
5169
5170                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5171                 if (thandle.ptr && mapinfo.data) {
5172                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5173                                 for (i = 0; i < 3; i++) {
5174                                         src = mapinfo.data + src_offset[i];
5175                                         dest = thandle.ptr + info.planes[i].offset;
5176
5177                                         if (i > 0) k = 1;
5178                                         for (j = 0; j < stream->height>>k; j++) {
5179                                                 memcpy(dest, src, stream->width>>k);
5180                                                 src += src_stride[i];
5181                                                 dest += stream->stride[i];
5182                                         }
5183                                 }
5184                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5185                                 memcpy(thandle.ptr, mapinfo.data, size);
5186                         } else {
5187                                 LOGE("Not support format %d", stream->format);
5188                                 goto ERROR;
5189                         }
5190                 } else {
5191                         LOGE("data pointer is wrong. dest : %p, src : %p",
5192                                         thandle.ptr, mapinfo.data);
5193                         goto ERROR;
5194                 }
5195                 tbm_bo_unmap(stream->bo[0]);
5196         }
5197
5198         if (player->video_stream_cb) { /* This has been already checked at the entry */
5199                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5200                         LOGE("failed to send video stream data.");
5201                         goto ERROR;
5202                 }
5203         }
5204
5205         if (metaBlock)
5206                 gst_memory_unmap(metaBlock, &mapinfo);
5207         else
5208                 gst_memory_unmap(dataBlock, &mapinfo);
5209
5210         return;
5211
5212 ERROR:
5213         LOGE("release video stream resource.");
5214         if (metaBlock) {
5215                 int i = 0;
5216                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5217                         if (stream->bo[i])
5218                                 tbm_bo_unref(stream->bo[i]);
5219                 }
5220                 gst_memory_unmap(metaBlock, &mapinfo);
5221
5222                 /* unref gst buffer */
5223                 if (stream->internal_buffer)
5224                         gst_buffer_unref(stream->internal_buffer);
5225         } else if (dataBlock) {
5226                 if (stream->bo[0])
5227                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5228                 gst_memory_unmap(dataBlock, &mapinfo);
5229         }
5230
5231         g_free(stream);
5232         return;
5233 }
5234
5235 static int
5236 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5237 {
5238         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5239         GList* element_bucket = NULL;
5240
5241         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5242
5243         MMPLAYER_FENTER();
5244
5245         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5246                 LOGD("do not need to add video filters.");
5247                 return MM_ERROR_NONE;
5248         }
5249
5250         /* in case of sw codec except 360 playback,
5251          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5252         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5253         LOGD("using video converter: %s", video_csc);
5254
5255         /* set video rotator */
5256         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5257
5258         *bucket = element_bucket;
5259         MMPLAYER_FLEAVE();
5260         return MM_ERROR_NONE;
5261
5262 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5263         g_list_free(element_bucket);
5264
5265         *bucket = NULL;
5266         MMPLAYER_FLEAVE();
5267         return MM_ERROR_PLAYER_INTERNAL;
5268 }
5269
5270 /**
5271  * This function is to create video pipeline.
5272  *
5273  * @param       player          [in]    handle of player
5274  *              caps            [in]    src caps of decoder
5275  *              surface_type    [in]    surface type for video rendering
5276  *
5277  * @return      This function returns zero on success.
5278  * @remark
5279  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5280  */
5281 /**
5282   * VIDEO PIPELINE
5283   * - video overlay surface(arm/x86) : tizenwlsink
5284   */
5285 static int
5286 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5287 {
5288         GstPad *pad = NULL;
5289         MMHandleType attrs;
5290         GList*element_bucket = NULL;
5291         MMPlayerGstElement* first_element = NULL;
5292         MMPlayerGstElement* videobin = NULL;
5293         gchar *videosink_element = NULL;
5294
5295         MMPLAYER_FENTER();
5296
5297         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5298
5299         /* alloc handles */
5300         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5301         if (!videobin)
5302                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5303
5304         player->pipeline->videobin = videobin;
5305
5306         attrs = MMPLAYER_GET_ATTRS(player);
5307         if (!attrs) {
5308                 LOGE("cannot get content attribute");
5309                 return MM_ERROR_PLAYER_INTERNAL;
5310         }
5311
5312         /* create bin */
5313         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5314         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5315         if (!videobin[MMPLAYER_V_BIN].gst) {
5316                 LOGE("failed to create videobin");
5317                 goto ERROR;
5318         }
5319
5320         int enable_video_decoded_cb = 0;
5321         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5322
5323         if (player->is_360_feature_enabled && player->is_content_spherical) {
5324                 LOGD("video360 elem will be added.");
5325
5326                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5327                                 "video-360", TRUE, player);
5328
5329                 /* Set spatial media metadata and/or user settings to the element.
5330                  * */
5331                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5332                                 "projection-type", player->video360_metadata.projection_type, NULL);
5333
5334                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5335                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5336
5337                 if (player->video360_metadata.full_pano_width_pixels &&
5338                                 player->video360_metadata.full_pano_height_pixels &&
5339                                 player->video360_metadata.cropped_area_image_width &&
5340                                 player->video360_metadata.cropped_area_image_height) {
5341                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5342                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5343                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5344                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5345                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5346                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5347                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5348                                         NULL);
5349                 }
5350
5351                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5352                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5353                                         "horizontal-fov", player->video360_horizontal_fov,
5354                                         "vertical-fov", player->video360_vertical_fov, NULL);
5355                 }
5356
5357                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5358                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5359                                         "zoom", 1.0f / player->video360_zoom, NULL);
5360                 }
5361
5362                 if (player->video360_yaw_radians <= M_PI &&
5363                                 player->video360_yaw_radians >= -M_PI &&
5364                                 player->video360_pitch_radians <= M_PI_2 &&
5365                                 player->video360_pitch_radians >= -M_PI_2) {
5366                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5367                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5368                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5369                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5370                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5371                                         "pose-yaw", player->video360_metadata.init_view_heading,
5372                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5373                 }
5374
5375                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5376                                 "passthrough", !player->is_video360_enabled, NULL);
5377         }
5378
5379         /* set video sink */
5380         switch (surface_type) {
5381         case MM_DISPLAY_SURFACE_OVERLAY:
5382                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5383                         goto ERROR;
5384                 if (strlen(player->ini.videosink_element_overlay) > 0)
5385                         videosink_element = player->ini.videosink_element_overlay;
5386                 else
5387                         goto ERROR;
5388                 break;
5389         case MM_DISPLAY_SURFACE_NULL:
5390                 if (strlen(player->ini.videosink_element_fake) > 0)
5391                         videosink_element = player->ini.videosink_element_fake;
5392                 else
5393                         goto ERROR;
5394                 break;
5395         case MM_DISPLAY_SURFACE_REMOTE:
5396                 if (strlen(player->ini.videosink_element_fake) > 0)
5397                         videosink_element = player->ini.videosink_element_fake;
5398                 else
5399                         goto ERROR;
5400                 break;
5401         default:
5402                 LOGE("unidentified surface type");
5403                 goto ERROR;
5404         }
5405         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5406
5407         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5408
5409         /* additional setting for sink plug-in */
5410         switch (surface_type) {
5411         case MM_DISPLAY_SURFACE_OVERLAY:
5412         {
5413                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5414                 if (!use_tbm) {
5415                         LOGD("selected videosink name: %s", videosink_element);
5416
5417                         /* support shard memory with S/W codec on HawkP */
5418                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5419                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5420                                         "use-tbm", use_tbm, NULL);
5421                         }
5422                 } else {
5423                         if (attrs) {
5424                                 int gapless = 0;
5425
5426                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5427
5428                                 if (gapless > 0) {
5429                                         LOGD("disable last-sample");
5430                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5431                                 }
5432                         }
5433                 }
5434                 if (player->set_mode.media_packet_video_stream) {
5435                         int enable = 0;
5436                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5437                         if (enable)
5438                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5439
5440                         MMPLAYER_SIGNAL_CONNECT(player,
5441                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5442                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5443                                                                         "handoff",
5444                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5445                                                                         (gpointer)player);
5446
5447                         MMPLAYER_SIGNAL_CONNECT(player,
5448                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5449                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5450                                                                         "preroll-handoff",
5451                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5452                                                                         (gpointer)player);
5453                 }
5454                 break;
5455         }
5456         case MM_DISPLAY_SURFACE_REMOTE:
5457         {
5458                 if (player->set_mode.media_packet_video_stream) {
5459                         LOGE("add data probe at videosink");
5460                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5461                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5462
5463                         MMPLAYER_SIGNAL_CONNECT(player,
5464                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5465                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5466                                                                         "handoff",
5467                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5468                                                                         (gpointer)player);
5469
5470                         MMPLAYER_SIGNAL_CONNECT(player,
5471                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5472                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5473                                                                         "preroll-handoff",
5474                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5475                                                                         (gpointer)player);
5476                         if (attrs) {
5477                                 int gapless = 0;
5478
5479                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5480
5481                                 if (gapless > 0) {
5482                                         LOGD("disable last-sample");
5483                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5484                                 }
5485                         }
5486                 }
5487                 break;
5488         }
5489         default:
5490                 break;
5491         }
5492
5493         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5494                 goto ERROR;
5495
5496         if (videobin[MMPLAYER_V_SINK].gst) {
5497                 GstPad *sink_pad = NULL;
5498                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5499                 if (sink_pad) {
5500                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5501                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5502                         gst_object_unref(GST_OBJECT(sink_pad));
5503                 } else
5504                         LOGW("failed to get sink pad from videosink\n");
5505         }
5506
5507         /* store it as it's sink element */
5508         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5509
5510         /* adding created elements to bin */
5511         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5512                 LOGE("failed to add elements\n");
5513                 goto ERROR;
5514         }
5515
5516         /* Linking elements in the bucket by added order */
5517         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5518                 LOGE("failed to link elements\n");
5519                 goto ERROR;
5520         }
5521
5522         /* get first element's sinkpad for creating ghostpad */
5523         if (element_bucket)
5524                 first_element = (MMPlayerGstElement *)element_bucket->data;
5525         if (!first_element) {
5526                 LOGE("failed to get first element from bucket\n");
5527                 goto ERROR;
5528         }
5529
5530         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5531         if (!pad) {
5532                 LOGE("failed to get pad from first element\n");
5533                 goto ERROR;
5534         }
5535
5536         /* create ghostpad */
5537         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5538         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5539                 LOGE("failed to add ghostpad to videobin\n");
5540                 goto ERROR;
5541         }
5542         gst_object_unref(pad);
5543
5544         /* done. free allocated variables */
5545         if (element_bucket)
5546                 g_list_free(element_bucket);
5547
5548         MMPLAYER_FLEAVE();
5549
5550         return MM_ERROR_NONE;
5551
5552 ERROR:
5553         LOGE("ERROR : releasing videobin\n");
5554
5555         g_list_free(element_bucket);
5556
5557         if (pad)
5558                 gst_object_unref(GST_OBJECT(pad));
5559
5560         /* release videobin with it's childs */
5561         if (videobin[MMPLAYER_V_BIN].gst)
5562                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5563
5564
5565         MMPLAYER_FREEIF(videobin);
5566
5567         player->pipeline->videobin = NULL;
5568
5569         return MM_ERROR_PLAYER_INTERNAL;
5570 }
5571
5572 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5573 {
5574         GList *element_bucket = NULL;
5575         MMPlayerGstElement *textbin = player->pipeline->textbin;
5576
5577         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5578         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5579         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5580                                                         "signal-handoffs", FALSE,
5581                                                         NULL);
5582
5583         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5584         MMPLAYER_SIGNAL_CONNECT(player,
5585                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5586                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5587                                                         "handoff",
5588                                                         G_CALLBACK(__mmplayer_update_subtitle),
5589                                                         (gpointer)player);
5590
5591         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5592         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5593         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5594
5595         if (!player->play_subtitle) {
5596                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5597                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5598         }
5599
5600         /* adding created elements to bin */
5601         LOGD("adding created elements to bin\n");
5602         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5603                 LOGE("failed to add elements\n");
5604                 goto ERROR;
5605         }
5606
5607         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5608         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5609         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5610
5611         /* linking elements in the bucket by added order. */
5612         LOGD("Linking elements in the bucket by added order.\n");
5613         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5614                 LOGE("failed to link elements\n");
5615                 goto ERROR;
5616         }
5617
5618         /* done. free allocated variables */
5619         g_list_free(element_bucket);
5620
5621         if (textbin[MMPLAYER_T_QUEUE].gst) {
5622                 GstPad *pad = NULL;
5623                 GstPad *ghostpad = NULL;
5624
5625                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5626                 if (!pad) {
5627                         LOGE("failed to get sink pad of text queue");
5628                         goto ERROR;
5629                 }
5630
5631                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5632                 gst_object_unref(pad);
5633
5634                 if (!ghostpad) {
5635                         LOGE("failed to create ghostpad of textbin\n");
5636                         goto ERROR;
5637                 }
5638
5639                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5640                         LOGE("failed to add ghostpad to textbin\n");
5641                         gst_object_unref(ghostpad);
5642                         goto ERROR;
5643                 }
5644         }
5645
5646         return MM_ERROR_NONE;
5647
5648 ERROR:
5649         g_list_free(element_bucket);
5650
5651         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5652                 LOGE("remove textbin sink from sink list");
5653                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5654         }
5655
5656         /* release element at __mmplayer_gst_create_text_sink_bin */
5657         return MM_ERROR_PLAYER_INTERNAL;
5658 }
5659
5660 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5661 {
5662         MMPlayerGstElement *textbin = NULL;
5663         GList *element_bucket = NULL;
5664         int surface_type = 0;
5665         gint i = 0;
5666
5667         MMPLAYER_FENTER();
5668
5669         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5670
5671         /* alloc handles */
5672         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5673         if (!textbin) {
5674                 LOGE("failed to allocate memory for textbin\n");
5675                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5676         }
5677
5678         /* create bin */
5679         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5680         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5681         if (!textbin[MMPLAYER_T_BIN].gst) {
5682                 LOGE("failed to create textbin\n");
5683                 goto ERROR;
5684         }
5685
5686         /* take it */
5687         player->pipeline->textbin = textbin;
5688
5689         /* fakesink */
5690         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5691         LOGD("surface type for subtitle : %d", surface_type);
5692         switch (surface_type) {
5693         case MM_DISPLAY_SURFACE_OVERLAY:
5694         case MM_DISPLAY_SURFACE_NULL:
5695         case MM_DISPLAY_SURFACE_REMOTE:
5696                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5697                         LOGE("failed to make plain text elements\n");
5698                         goto ERROR;
5699                 }
5700                 break;
5701         default:
5702                 goto ERROR;
5703                 break;
5704         }
5705
5706         MMPLAYER_FLEAVE();
5707
5708         return MM_ERROR_NONE;
5709
5710 ERROR:
5711
5712         LOGD("ERROR : releasing textbin\n");
5713
5714         g_list_free(element_bucket);
5715
5716         /* release signal */
5717         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5718
5719         /* release element which are not added to bin */
5720         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5721                 /* NOTE : skip bin */
5722                 if (textbin[i].gst) {
5723                         GstObject* parent = NULL;
5724                         parent = gst_element_get_parent(textbin[i].gst);
5725
5726                         if (!parent) {
5727                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5728                                 textbin[i].gst = NULL;
5729                         } else {
5730                                 gst_object_unref(GST_OBJECT(parent));
5731                         }
5732                 }
5733         }
5734
5735         /* release textbin with it's childs */
5736         if (textbin[MMPLAYER_T_BIN].gst)
5737                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5738
5739         MMPLAYER_FREEIF(player->pipeline->textbin);
5740         player->pipeline->textbin = NULL;
5741
5742         MMPLAYER_FLEAVE();
5743         return MM_ERROR_PLAYER_INTERNAL;
5744 }
5745
5746
5747 static int
5748 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5749 {
5750         MMPlayerGstElement* mainbin = NULL;
5751         MMPlayerGstElement* textbin = NULL;
5752         MMHandleType attrs = 0;
5753         GstElement *subsrc = NULL;
5754         GstElement *subparse = NULL;
5755         gchar *subtitle_uri = NULL;
5756         const gchar *charset = NULL;
5757         GstPad *pad = NULL;
5758
5759         MMPLAYER_FENTER();
5760
5761         /* get mainbin */
5762         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5763                                                                 player->pipeline &&
5764                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5765
5766         mainbin = player->pipeline->mainbin;
5767
5768         attrs = MMPLAYER_GET_ATTRS(player);
5769         if (!attrs) {
5770                 LOGE("cannot get content attribute\n");
5771                 return MM_ERROR_PLAYER_INTERNAL;
5772         }
5773
5774         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5775         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5776                 LOGE("subtitle uri is not proper filepath.\n");
5777                 return MM_ERROR_PLAYER_INVALID_URI;
5778         }
5779
5780         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5781                 LOGE("failed to get storage info of subtitle path");
5782                 return MM_ERROR_PLAYER_INVALID_URI;
5783         }
5784
5785         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5786
5787         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5788         player->subtitle_language_list = NULL;
5789         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5790
5791         /* create the subtitle source */
5792         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5793         if (!subsrc) {
5794                 LOGE("failed to create filesrc element\n");
5795                 goto ERROR;
5796         }
5797         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5798
5799         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5800         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5801
5802         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5803                 LOGW("failed to add queue\n");
5804                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5805                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5806                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5807                 goto ERROR;
5808         }
5809
5810         /* subparse */
5811         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5812         if (!subparse) {
5813                 LOGE("failed to create subparse element\n");
5814                 goto ERROR;
5815         }
5816
5817         charset = util_get_charset(subtitle_uri);
5818         if (charset) {
5819                 LOGD("detected charset is %s\n", charset);
5820                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5821         }
5822
5823         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5824         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5825
5826         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5827                 LOGW("failed to add subparse\n");
5828                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5829                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5830                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5831                 goto ERROR;
5832         }
5833
5834         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5835                 LOGW("failed to link subsrc and subparse\n");
5836                 goto ERROR;
5837         }
5838
5839         player->play_subtitle = TRUE;
5840         player->adjust_subtitle_pos = 0;
5841
5842         LOGD("play subtitle using subtitle file\n");
5843
5844         if (player->pipeline->textbin == NULL) {
5845                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5846                         LOGE("failed to create text sink bin. continuing without text\n");
5847                         goto ERROR;
5848                 }
5849
5850                 textbin = player->pipeline->textbin;
5851
5852                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5853                         LOGW("failed to add textbin\n");
5854
5855                         /* release signal */
5856                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5857
5858                         /* release textbin with it's childs */
5859                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5860                         MMPLAYER_FREEIF(player->pipeline->textbin);
5861                         player->pipeline->textbin = textbin = NULL;
5862                         goto ERROR;
5863                 }
5864
5865                 LOGD("link text input selector and textbin ghost pad");
5866
5867                 player->textsink_linked = 1;
5868                 player->external_text_idx = 0;
5869                 LOGI("player->textsink_linked set to 1\n");
5870         } else {
5871                 textbin = player->pipeline->textbin;
5872                 LOGD("text bin has been created. reuse it.");
5873                 player->external_text_idx = 1;
5874         }
5875
5876         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5877                 LOGW("failed to link subparse and textbin\n");
5878                 goto ERROR;
5879         }
5880
5881         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5882         if (!pad) {
5883                 LOGE("failed to get sink pad from textsink to probe data");
5884                 goto ERROR;
5885         }
5886
5887         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5888                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5889
5890         gst_object_unref(pad);
5891         pad = NULL;
5892
5893         /* create dot. for debugging */
5894         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5895         MMPLAYER_FLEAVE();
5896
5897         return MM_ERROR_NONE;
5898
5899 ERROR:
5900         /* release text pipeline resource */
5901         player->textsink_linked = 0;
5902
5903         /* release signal */
5904         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5905
5906         if (player->pipeline->textbin) {
5907                 LOGE("remove textbin");
5908
5909                 /* release textbin with it's childs */
5910                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5911                 MMPLAYER_FREEIF(player->pipeline->textbin);
5912                 player->pipeline->textbin = NULL;
5913
5914         }
5915
5916         /* release subtitle elem */
5917         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5918         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5919
5920         return MM_ERROR_PLAYER_INTERNAL;
5921 }
5922
5923 gboolean
5924 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5925 {
5926         mm_player_t* player = (mm_player_t*) data;
5927         MMMessageParamType msg = {0, };
5928         GstClockTime duration = 0;
5929         gpointer text = NULL;
5930         guint text_size = 0;
5931         gboolean ret = TRUE;
5932         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5933
5934         MMPLAYER_FENTER();
5935
5936         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5937         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5938
5939         if (player->is_subtitle_force_drop) {
5940                 LOGW("subtitle is dropped forcedly.");
5941                 return ret;
5942         }
5943
5944         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5945         text = mapinfo.data;
5946         text_size = mapinfo.size;
5947         duration = GST_BUFFER_DURATION(buffer);
5948
5949         if (player->set_mode.subtitle_off) {
5950                 LOGD("subtitle is OFF.\n");
5951                 return TRUE;
5952         }
5953
5954         if (!text || (text_size == 0)) {
5955                 LOGD("There is no subtitle to be displayed.\n");
5956                 return TRUE;
5957         }
5958
5959         msg.data = (void *) text;
5960         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5961
5962         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5963
5964         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5965         gst_buffer_unmap(buffer, &mapinfo);
5966
5967         MMPLAYER_FLEAVE();
5968
5969         return ret;
5970 }
5971
5972 static GstPadProbeReturn
5973 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5974 {
5975         mm_player_t *player = (mm_player_t *) u_data;
5976         GstClockTime cur_timestamp = 0;
5977         gint64 adjusted_timestamp = 0;
5978         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5979
5980         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5981
5982         if (player->set_mode.subtitle_off) {
5983                 LOGD("subtitle is OFF.\n");
5984                 return TRUE;
5985         }
5986
5987         if (player->adjust_subtitle_pos == 0) {
5988                 LOGD("nothing to do");
5989                 return TRUE;
5990         }
5991
5992         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5993         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5994
5995         if (adjusted_timestamp < 0) {
5996                 LOGD("adjusted_timestamp under zero");
5997                 MMPLAYER_FLEAVE();
5998                 return FALSE;
5999         }
6000
6001         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6002         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6003                                 GST_TIME_ARGS(cur_timestamp),
6004                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6005
6006         return GST_PAD_PROBE_OK;
6007 }
6008 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6009 {
6010         MMPLAYER_FENTER();
6011
6012         /* check player and subtitlebin are created */
6013         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6014         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6015
6016         if (position == 0) {
6017                 LOGD("nothing to do\n");
6018                 MMPLAYER_FLEAVE();
6019                 return MM_ERROR_NONE;
6020         }
6021
6022         switch (format) {
6023         case MM_PLAYER_POS_FORMAT_TIME:
6024                 {
6025                         /* check current postion */
6026                         player->adjust_subtitle_pos = position;
6027
6028                         LOGD("save adjust_subtitle_pos in player") ;
6029                 }
6030                 break;
6031
6032         default:
6033                 {
6034                         LOGW("invalid format.\n");
6035                         MMPLAYER_FLEAVE();
6036                         return MM_ERROR_INVALID_ARGUMENT;
6037                 }
6038         }
6039
6040         MMPLAYER_FLEAVE();
6041
6042         return MM_ERROR_NONE;
6043 }
6044
6045 static void
6046 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6047 {
6048         GstElement *appsrc = element;
6049         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6050         GstBuffer *buffer = NULL;
6051         GstFlowReturn ret = GST_FLOW_OK;
6052         gint len = size;
6053
6054         MMPLAYER_RETURN_IF_FAIL(element);
6055         MMPLAYER_RETURN_IF_FAIL(buf);
6056
6057         buffer = gst_buffer_new();
6058
6059         if (buf->offset >= buf->len) {
6060                 LOGD("call eos appsrc\n");
6061                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6062                 return;
6063         }
6064
6065         if (buf->len - buf->offset < size)
6066                 len = buf->len - buf->offset;
6067
6068         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6069         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6070         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6071
6072         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6073         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6074
6075         buf->offset += len;
6076 }
6077
6078 static gboolean
6079 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6080 {
6081         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6082
6083         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6084
6085         buf->offset  = (int)size;
6086
6087         return TRUE;
6088 }
6089
6090 static GstBusSyncReply
6091 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6092 {
6093         mm_player_t *player = (mm_player_t *)data;
6094         GstBusSyncReply reply = GST_BUS_DROP;
6095
6096         if (!(player->pipeline && player->pipeline->mainbin)) {
6097                 LOGE("player pipeline handle is null");
6098                 return GST_BUS_PASS;
6099         }
6100
6101         if (!__mmplayer_check_useful_message(player, message)) {
6102                 gst_message_unref(message);
6103                 return GST_BUS_DROP;
6104         }
6105
6106         switch (GST_MESSAGE_TYPE(message)) {
6107         case GST_MESSAGE_STATE_CHANGED:
6108                 /* post directly for fast launch */
6109                 if (player->sync_handler) {
6110                         __mmplayer_gst_callback(message, player);
6111                         reply = GST_BUS_DROP;
6112                 } else
6113                         reply = GST_BUS_PASS;
6114                 break;
6115         case GST_MESSAGE_TAG:
6116                 __mmplayer_gst_extract_tag_from_msg(player, message);
6117
6118                 #if 0 // debug
6119                 {
6120                         GstTagList *tags = NULL;
6121
6122                         gst_message_parse_tag(message, &tags);
6123                         if (tags) {
6124                                 LOGE("TAGS received from element \"%s\".\n",
6125                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6126
6127                                 gst_tag_list_foreach(tags, print_tag, NULL);
6128                                 gst_tag_list_free(tags);
6129                                 tags = NULL;
6130                         }
6131                         break;
6132                 }
6133                 #endif
6134                 break;
6135
6136         case GST_MESSAGE_DURATION_CHANGED:
6137                 __mmplayer_gst_handle_duration(player, message);
6138                 break;
6139         case GST_MESSAGE_ASYNC_DONE:
6140                 /* NOTE:Don't call gst_callback directly
6141                  * because previous frame can be showed even though this message is received for seek.
6142                  */
6143         default:
6144                 reply = GST_BUS_PASS;
6145                 break;
6146         }
6147
6148         if (reply == GST_BUS_DROP)
6149                 gst_message_unref(message);
6150
6151         return reply;
6152 }
6153
6154 static gboolean
6155 __mmplayer_gst_create_decoder(mm_player_t *player,
6156                                                                 MMPlayerTrackType track,
6157                                                                 GstPad* srcpad,
6158                                                                 enum MainElementID elemId,
6159                                                                 const gchar* name)
6160 {
6161         gboolean ret = TRUE;
6162         GstPad *sinkpad = NULL;
6163
6164         MMPLAYER_FENTER();
6165
6166         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6167                                                 player->pipeline &&
6168                                                 player->pipeline->mainbin, FALSE);
6169         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6170         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6171         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6172
6173         GstElement *decodebin = NULL;
6174         GstCaps *dec_caps = NULL;
6175
6176         /* create decodebin */
6177         decodebin = gst_element_factory_make("decodebin", name);
6178
6179         if (!decodebin) {
6180                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6181                 ret = FALSE;
6182                 goto ERROR;
6183         }
6184
6185         /* raw pad handling signal */
6186         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6187                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6188
6189         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6190         before looking for any elements that can handle that stream.*/
6191         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6192                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6193
6194         /* This signal is emitted when a element is added to the bin.*/
6195         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6196                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6197
6198         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6199                 LOGE("failed to add new decodebin\n");
6200                 ret = FALSE;
6201                 goto ERROR;
6202         }
6203
6204         dec_caps = gst_pad_query_caps(srcpad, NULL);
6205         if (dec_caps) {
6206                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6207                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6208                 gst_caps_unref(dec_caps);
6209         }
6210
6211         player->pipeline->mainbin[elemId].id = elemId;
6212         player->pipeline->mainbin[elemId].gst = decodebin;
6213
6214         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6215
6216         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6217                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6218                 gst_object_unref(GST_OBJECT(decodebin));
6219         }
6220
6221         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6222                 LOGE("failed to sync second level decodebin state with parent\n");
6223
6224         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6225
6226 ERROR:
6227         if (sinkpad) {
6228                 gst_object_unref(GST_OBJECT(sinkpad));
6229                 sinkpad = NULL;
6230         }
6231         MMPLAYER_FLEAVE();
6232
6233         return ret;
6234 }
6235
6236 /**
6237  * This function is to create  audio or video pipeline for playing.
6238  *
6239  * @param       player          [in]    handle of player
6240  *
6241  * @return      This function returns zero on success.
6242  * @remark
6243  * @see
6244  */
6245 static int
6246 __mmplayer_gst_create_pipeline(mm_player_t* player)
6247 {
6248         GstBus  *bus = NULL;
6249         MMPlayerGstElement *mainbin = NULL;
6250         MMHandleType attrs = 0;
6251         GstElement* element = NULL;
6252         GstElement* elem_src_audio = NULL;
6253         GstElement* elem_src_subtitle = NULL;
6254         GstElement* es_video_queue = NULL;
6255         GstElement* es_audio_queue = NULL;
6256         GstElement* es_subtitle_queue = NULL;
6257         GList* element_bucket = NULL;
6258         gboolean need_state_holder = TRUE;
6259         gint i = 0;
6260 #ifdef SW_CODEC_ONLY
6261         int surface_type = 0;
6262 #endif
6263         MMPLAYER_FENTER();
6264
6265         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6266
6267         /* get profile attribute */
6268         attrs = MMPLAYER_GET_ATTRS(player);
6269         if (!attrs) {
6270                 LOGE("cannot get content attribute\n");
6271                 goto INIT_ERROR;
6272         }
6273
6274         /* create pipeline handles */
6275         if (player->pipeline) {
6276                 LOGW("pipeline should be released before create new one\n");
6277                 goto INIT_ERROR;
6278         }
6279
6280         player->video360_metadata.is_spherical = -1;
6281         player->is_openal_plugin_used = FALSE;
6282
6283         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6284         if (player->pipeline == NULL)
6285                 goto INIT_ERROR;
6286
6287         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6288
6289         /* create mainbin */
6290         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6291         if (mainbin == NULL)
6292                 goto INIT_ERROR;
6293
6294         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6295
6296         /* create pipeline */
6297         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6298         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6299         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6300                 LOGE("failed to create pipeline\n");
6301                 goto INIT_ERROR;
6302         }
6303         player->demux_pad_index = 0;
6304         player->subtitle_language_list = NULL;
6305
6306         player->is_subtitle_force_drop = FALSE;
6307         player->last_multiwin_status = FALSE;
6308
6309         _mmplayer_track_initialize(player);
6310         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6311
6312         /* create source element */
6313         switch (player->profile.uri_type) {
6314         /* rtsp streamming */
6315         case MM_PLAYER_URI_TYPE_URL_RTSP:
6316                 {
6317                         gchar *user_agent;
6318
6319                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6320
6321                         if (!element) {
6322                                 LOGE("failed to create streaming source element\n");
6323                                 break;
6324                         }
6325
6326                         /* make it zero */
6327                         user_agent = NULL;
6328
6329                         /* get attribute */
6330                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6331
6332                         SECURE_LOGD("user_agent : %s\n", user_agent);
6333
6334                         /* setting property to streaming source */
6335                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6336                         if (user_agent)
6337                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6338
6339                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6340                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6341                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6342                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6343                 }
6344                 break;
6345
6346         /* http streaming*/
6347         case MM_PLAYER_URI_TYPE_URL_HTTP:
6348                 {
6349                         gchar *user_agent, *cookies, **cookie_list;
6350                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6351                         user_agent = cookies = NULL;
6352                         cookie_list = NULL;
6353                         gint mode = MM_PLAYER_PD_MODE_NONE;
6354
6355                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6356
6357                         player->pd_mode = mode;
6358
6359                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6360
6361                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6362                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6363                                 if (!element) {
6364                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6365                                         break;
6366                                 }
6367                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6368
6369                                 /* get attribute */
6370                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6371                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6372
6373                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6374                                         LOGD("get timeout from ini\n");
6375                                         http_timeout = player->ini.http_timeout;
6376                                 }
6377
6378                                 /* get attribute */
6379                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6380                                 SECURE_LOGD("cookies : %s\n", cookies);
6381                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6382                                 LOGD("timeout : %d\n",  http_timeout);
6383
6384                                 /* setting property to streaming source */
6385                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6386                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6387                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6388
6389                                 /* parsing cookies */
6390                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6391                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6392                                         g_strfreev(cookie_list);
6393                                 }
6394                                 if (user_agent)
6395                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6396
6397                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6398                                         LOGW("it's dash. and it's still experimental feature.");
6399                         } else {
6400                                 // progressive download
6401                                 gchar* location = NULL;
6402
6403                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6404                                         gchar *path = NULL;
6405
6406                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6407
6408                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6409
6410                                         LOGD("PD Location : %s\n", path);
6411
6412                                         if (path) {
6413                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6414                                                         LOGE("failed to get storage info");
6415                                                         break;
6416                                                 }
6417                                                 player->pd_file_save_path = g_strdup(path);
6418                                         } else {
6419                                                 LOGE("can't find pd location so, it should be set \n");
6420                                                 break;
6421                                         }
6422                                 }
6423
6424                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6425                                 if (!element) {
6426                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6427                                         break;
6428                                 }
6429
6430                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6431                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6432                                 else
6433                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6434                                 g_object_get(element, "location", &location, NULL);
6435                                 LOGD("PD_LOCATION [%s].\n", location);
6436                                 if (location)
6437                                         g_free(location);
6438                         }
6439                 }
6440                 break;
6441
6442         /* file source */
6443         case MM_PLAYER_URI_TYPE_FILE:
6444                 {
6445                         LOGD("using filesrc for 'file://' handler.\n");
6446                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6447                                 LOGE("failed to get storage info");
6448                                 break;
6449                         }
6450
6451                         element = gst_element_factory_make("filesrc", "source");
6452                         if (!element) {
6453                                 LOGE("failed to create filesrc\n");
6454                                 break;
6455                         }
6456
6457                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6458                 }
6459                 break;
6460
6461         case MM_PLAYER_URI_TYPE_SS:
6462                 {
6463                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6464                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6465                         if (!element) {
6466                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6467                                 break;
6468                         }
6469
6470                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6471                                 LOGD("get timeout from ini\n");
6472                                 http_timeout = player->ini.http_timeout;
6473                         }
6474
6475                         /* setting property to streaming source */
6476                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6477                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6478                 }
6479                 break;
6480         case MM_PLAYER_URI_TYPE_MS_BUFF:
6481                 {
6482                         LOGD("MS buff src is selected\n");
6483
6484                         if (player->v_stream_caps) {
6485                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6486                                 if (!element) {
6487                                         LOGF("failed to create video app source element[appsrc].\n");
6488                                         break;
6489                                 }
6490
6491                                 if (player->a_stream_caps) {
6492                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6493                                         if (!elem_src_audio) {
6494                                                 LOGF("failed to create audio app source element[appsrc].\n");
6495                                                 break;
6496                                         }
6497                                 }
6498                         } else if (player->a_stream_caps) {
6499                                 /* no video, only audio pipeline*/
6500                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6501                                 if (!element) {
6502                                         LOGF("failed to create audio app source element[appsrc].\n");
6503                                         break;
6504                                 }
6505                         }
6506
6507                         if (player->s_stream_caps) {
6508                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6509                                 if (!elem_src_subtitle) {
6510                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6511                                         break;
6512                                 }
6513                         }
6514
6515                         LOGD("setting app sources properties.\n");
6516                         LOGD("location : %s\n", player->profile.uri);
6517
6518                         if (player->v_stream_caps && element) {
6519                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6520                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6521                                                                                                 "caps", player->v_stream_caps, NULL);
6522
6523                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6524                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6525                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6526                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6527
6528                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6529                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6530                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6531                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6532
6533                                 if (player->a_stream_caps && elem_src_audio) {
6534                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6535                                                                                                                         "caps", player->a_stream_caps, NULL);
6536
6537                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6538                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6539                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6540                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6541
6542                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6543                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6544                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6545                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6546                                 }
6547                         } else if (player->a_stream_caps && element) {
6548                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6549                                                                                                 "caps", player->a_stream_caps, NULL);
6550
6551                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6552                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6553                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6554                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6555
6556                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6557                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6558                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6559                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6560                         }
6561
6562                         if (player->s_stream_caps && elem_src_subtitle) {
6563                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6564                                                                                                                  "caps", player->s_stream_caps, NULL);
6565
6566                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6567                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6568                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6569                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6570
6571                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6572
6573                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6574                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6575                         }
6576
6577                         if (player->v_stream_caps && element) {
6578                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6579                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6580                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6581                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6582
6583                                 if (player->a_stream_caps && elem_src_audio) {
6584                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6585                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6586                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6587                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6588                                 }
6589                         } else if (player->a_stream_caps && element) {
6590                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6591                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6592                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6593                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6594                         }
6595
6596                         if (player->s_stream_caps && elem_src_subtitle)
6597                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6599
6600                         need_state_holder = FALSE;
6601
6602                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6603                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6604                                 LOGE("failed to commit\n");
6605                 }
6606                 break;
6607         /* appsrc */
6608         case MM_PLAYER_URI_TYPE_MEM:
6609                 {
6610                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6611
6612                         LOGD("mem src is selected\n");
6613
6614                         element = gst_element_factory_make("appsrc", "mem-source");
6615                         if (!element) {
6616                                 LOGE("failed to create appsrc element\n");
6617                                 break;
6618                         }
6619
6620                         g_object_set(element, "stream-type", stream_type, NULL);
6621                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6622                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6623
6624                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6625                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6626                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6627                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6628                 }
6629                 break;
6630         case MM_PLAYER_URI_TYPE_URL:
6631                 break;
6632
6633         case MM_PLAYER_URI_TYPE_TEMP:
6634                 break;
6635
6636         case MM_PLAYER_URI_TYPE_NONE:
6637         default:
6638                 break;
6639         }
6640
6641         /* check source element is OK */
6642         if (!element) {
6643                 LOGE("no source element was created.\n");
6644                 goto INIT_ERROR;
6645         }
6646
6647         /* take source element */
6648         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6649         mainbin[MMPLAYER_M_SRC].gst = element;
6650         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6651
6652         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6653                 player->streamer = __mm_player_streaming_create();
6654                 __mm_player_streaming_initialize(player->streamer);
6655         }
6656
6657         if (MMPLAYER_IS_HTTP_PD(player)) {
6658                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6659
6660                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6661                 element = gst_element_factory_make("queue2", "queue2");
6662                 if (!element) {
6663                         LOGE("failed to create http streaming buffer element\n");
6664                         goto INIT_ERROR;
6665                 }
6666
6667                 /* take it */
6668                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6669                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6670                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6671
6672                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6673
6674                 player->streamer->is_pd_mode = TRUE;
6675
6676                 __mm_player_streaming_set_queue2(player->streamer,
6677                                 element,
6678                                 TRUE,
6679                                 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6680                                 pre_buffering_time,
6681                                 1.0,
6682                                 player->ini.http_buffering_limit,
6683                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6684                                 NULL,
6685                                 0);
6686         }
6687         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6688                 if (player->v_stream_caps) {
6689                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6690                         if (!es_video_queue) {
6691                                 LOGE("create es_video_queue for es player failed\n");
6692                                 goto INIT_ERROR;
6693                         }
6694                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6695                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6696                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6697                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6698
6699                         /* Adding audio appsrc to bucket */
6700                         if (player->a_stream_caps && elem_src_audio) {
6701                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6702                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6703                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6704
6705                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6706                                 if (!es_audio_queue) {
6707                                         LOGE("create es_audio_queue for es player failed\n");
6708                                         goto INIT_ERROR;
6709                                 }
6710                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6711
6712                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6713                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6714                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6715                         }
6716                 } else if (player->a_stream_caps) {
6717                         /* Only audio stream, no video */
6718                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6719                         if (!es_audio_queue) {
6720                                 LOGE("create es_audio_queue for es player failed\n");
6721                                 goto INIT_ERROR;
6722                         }
6723                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6724                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6725                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6726                 }
6727
6728                 if (player->s_stream_caps && elem_src_subtitle) {
6729                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6730                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6731                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6732
6733                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6734                         if (!es_subtitle_queue) {
6735                                 LOGE("create es_subtitle_queue for es player failed\n");
6736                                 goto INIT_ERROR;
6737                         }
6738                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6739                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6740                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6741                 }
6742         }
6743
6744         /* create autoplugging element if src element is not a rtsp src */
6745         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6746                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6747                 element = NULL;
6748                 enum MainElementID elemId = MMPLAYER_M_NUM;
6749
6750                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6751                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6752                         elemId = MMPLAYER_M_AUTOPLUG;
6753                         element = __mmplayer_create_decodebin(player);
6754                         if (element) {
6755                                 /* default size of mq in decodebin is 2M
6756                                  * but it can cause blocking issue during seeking depends on content. */
6757                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6758                         }
6759                         need_state_holder = FALSE;
6760                 } else {
6761                         elemId = MMPLAYER_M_TYPEFIND;
6762                         element = gst_element_factory_make("typefind", "typefinder");
6763                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6764                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6765                 }
6766
6767
6768                 /* check autoplug element is OK */
6769                 if (!element) {
6770                         LOGE("can not create element(%d)\n", elemId);
6771                         goto INIT_ERROR;
6772                 }
6773
6774                 mainbin[elemId].id = elemId;
6775                 mainbin[elemId].gst = element;
6776
6777                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6778         }
6779
6780         /* add elements to pipeline */
6781         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6782                 LOGE("Failed to add elements to pipeline\n");
6783                 goto INIT_ERROR;
6784         }
6785
6786
6787         /* linking elements in the bucket by added order. */
6788         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6789                 LOGE("Failed to link some elements\n");
6790                 goto INIT_ERROR;
6791         }
6792
6793
6794         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6795         if (need_state_holder) {
6796                 /* create */
6797                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6798                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6799
6800                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6801                         LOGE("fakesink element could not be created\n");
6802                         goto INIT_ERROR;
6803                 }
6804                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6805
6806                 /* take ownership of fakesink. we are reusing it */
6807                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6808
6809                 /* add */
6810                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6811                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6812                         LOGE("failed to add fakesink to bin\n");
6813                         goto INIT_ERROR;
6814                 }
6815         }
6816
6817         /* now we have completed mainbin. take it */
6818         player->pipeline->mainbin = mainbin;
6819
6820         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6821                 GstPad *srcpad = NULL;
6822
6823                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6824                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6825                         if (srcpad) {
6826                                 __mmplayer_gst_create_decoder(player,
6827                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6828                                                                                                 srcpad,
6829                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6830                                                                                                 "video_decodebin");
6831
6832                                 gst_object_unref(GST_OBJECT(srcpad));
6833                                 srcpad = NULL;
6834                         }
6835                 }
6836
6837                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6838                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6839                         if (srcpad) {
6840                                 __mmplayer_gst_create_decoder(player,
6841                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6842                                                                                                 srcpad,
6843                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6844                                                                                                 "audio_decodebin");
6845
6846                                 gst_object_unref(GST_OBJECT(srcpad));
6847                                 srcpad = NULL;
6848                         } // else error
6849                 } //  else error
6850
6851                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6852                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6853         }
6854
6855         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6856         if (__mmplayer_check_subtitle(player)) {
6857                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6858                         LOGE("fail to create text pipeline");
6859         }
6860
6861         /* connect bus callback */
6862         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6863         if (!bus) {
6864                 LOGE("cannot get bus from pipeline.\n");
6865                 goto INIT_ERROR;
6866         }
6867
6868         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6869
6870         player->context.thread_default = g_main_context_get_thread_default();
6871
6872         if (player->context.thread_default == NULL) {
6873                 player->context.thread_default = g_main_context_default();
6874                 LOGD("thread-default context is the global default context");
6875         }
6876         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6877
6878         /* set sync handler to get tag synchronously */
6879         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6880
6881         /* finished */
6882         gst_object_unref(GST_OBJECT(bus));
6883         g_list_free(element_bucket);
6884
6885         /* create gst bus_msb_cb thread */
6886         g_mutex_init(&player->bus_msg_thread_mutex);
6887         g_cond_init(&player->bus_msg_thread_cond);
6888         player->bus_msg_thread_exit = FALSE;
6889         player->bus_msg_thread =
6890                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6891         if (!player->bus_msg_thread) {
6892                 LOGE("failed to create gst BUS msg thread");
6893                 g_mutex_clear(&player->bus_msg_thread_mutex);
6894                 g_cond_clear(&player->bus_msg_thread_cond);
6895                 goto INIT_ERROR;
6896         }
6897
6898         MMPLAYER_FLEAVE();
6899
6900         return MM_ERROR_NONE;
6901
6902 INIT_ERROR:
6903         __mmplayer_gst_destroy_pipeline(player);
6904         g_list_free(element_bucket);
6905
6906         if (mainbin) {
6907                 /* release element which are not added to bin */
6908                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6909                         /* NOTE : skip pipeline */
6910                         if (mainbin[i].gst) {
6911                                 GstObject* parent = NULL;
6912                                 parent = gst_element_get_parent(mainbin[i].gst);
6913
6914                                 if (!parent) {
6915                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6916                                         mainbin[i].gst = NULL;
6917                                 } else
6918                                         gst_object_unref(GST_OBJECT(parent));
6919                         }
6920                 }
6921
6922                 /* release pipeline with it's childs */
6923                 if (mainbin[MMPLAYER_M_PIPE].gst)
6924                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6925
6926                 MMPLAYER_FREEIF(mainbin);
6927         }
6928
6929         MMPLAYER_FREEIF(player->pipeline);
6930         return MM_ERROR_PLAYER_INTERNAL;
6931 }
6932
6933 static void
6934 __mmplayer_reset_gapless_state(mm_player_t* player)
6935 {
6936         MMPLAYER_FENTER();
6937         MMPLAYER_RETURN_IF_FAIL(player
6938                 && player->pipeline
6939                 && player->pipeline->audiobin
6940                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6941
6942         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6943
6944         MMPLAYER_FLEAVE();
6945         return;
6946 }
6947
6948 static int
6949 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6950 {
6951         gint timeout = 0;
6952         int ret = MM_ERROR_NONE;
6953
6954         MMPLAYER_FENTER();
6955
6956         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6957
6958         /* cleanup stuffs */
6959         MMPLAYER_FREEIF(player->type);
6960         player->have_dynamic_pad = FALSE;
6961         player->no_more_pad = FALSE;
6962         player->num_dynamic_pad = 0;
6963         player->demux_pad_index = 0;
6964         player->use_deinterleave = FALSE;
6965         player->max_audio_channels = 0;
6966         player->video_share_api_delta = 0;
6967         player->video_share_clock_delta = 0;
6968         player->video_hub_download_mode = 0;
6969
6970         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6971         player->subtitle_language_list = NULL;
6972         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6973
6974         __mmplayer_reset_gapless_state(player);
6975
6976         if (player->streamer) {
6977                 __mm_player_streaming_deinitialize(player->streamer);
6978                 __mm_player_streaming_destroy(player->streamer);
6979                 player->streamer = NULL;
6980         }
6981
6982         /* cleanup unlinked mime type */
6983         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6984         MMPLAYER_FREEIF(player->unlinked_video_mime);
6985         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6986
6987         /* cleanup running stuffs */
6988         __mmplayer_cancel_eos_timer(player);
6989
6990         /* cleanup gst stuffs */
6991         if (player->pipeline) {
6992                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6993                 GstTagList* tag_list = player->pipeline->tag_list;
6994
6995                 /* first we need to disconnect all signal hander */
6996                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6997
6998                 if (mainbin) {
6999                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7000                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7001                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7002                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7003                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7004                         gst_object_unref(bus);
7005
7006                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7007                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7008                         if (ret != MM_ERROR_NONE) {
7009                                 LOGE("fail to change state to NULL\n");
7010                                 return MM_ERROR_PLAYER_INTERNAL;
7011                         }
7012
7013                         LOGW("succeeded in chaning state to NULL\n");
7014
7015                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7016
7017                         /* free fakesink */
7018                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7019                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7020
7021                         /* free avsysaudiosink
7022                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7023                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7024                         */
7025                         MMPLAYER_FREEIF(audiobin);
7026                         MMPLAYER_FREEIF(videobin);
7027                         MMPLAYER_FREEIF(textbin);
7028                         MMPLAYER_FREEIF(mainbin);
7029                 }
7030
7031                 if (tag_list)
7032                         gst_tag_list_free(tag_list);
7033
7034                 MMPLAYER_FREEIF(player->pipeline);
7035         }
7036         MMPLAYER_FREEIF(player->album_art);
7037
7038         if (player->v_stream_caps) {
7039                 gst_caps_unref(player->v_stream_caps);
7040                 player->v_stream_caps = NULL;
7041         }
7042         if (player->a_stream_caps) {
7043                 gst_caps_unref(player->a_stream_caps);
7044                 player->a_stream_caps = NULL;
7045         }
7046
7047         if (player->s_stream_caps) {
7048                 gst_caps_unref(player->s_stream_caps);
7049                 player->s_stream_caps = NULL;
7050         }
7051         _mmplayer_track_destroy(player);
7052
7053         if (player->sink_elements)
7054                 g_list_free(player->sink_elements);
7055         player->sink_elements = NULL;
7056
7057         if (player->bufmgr) {
7058                 tbm_bufmgr_deinit(player->bufmgr);
7059                 player->bufmgr = NULL;
7060         }
7061
7062         LOGW("finished destroy pipeline\n");
7063
7064         MMPLAYER_FLEAVE();
7065
7066         return ret;
7067 }
7068
7069 static int __gst_realize(mm_player_t* player)
7070 {
7071         gint timeout = 0;
7072         int ret = MM_ERROR_NONE;
7073
7074         MMPLAYER_FENTER();
7075
7076         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7077
7078         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7079
7080         ret = __mmplayer_gst_create_pipeline(player);
7081         if (ret) {
7082                 LOGE("failed to create pipeline\n");
7083                 return ret;
7084         }
7085
7086         /* set pipeline state to READY */
7087         /* NOTE : state change to READY must be performed sync. */
7088         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7089         ret = __mmplayer_gst_set_state(player,
7090                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7091
7092         if (ret != MM_ERROR_NONE) {
7093                 /* return error if failed to set state */
7094                 LOGE("failed to set READY state");
7095                 return ret;
7096         }
7097
7098         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7099
7100         /* create dot before error-return. for debugging */
7101         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7102
7103         MMPLAYER_FLEAVE();
7104
7105         return ret;
7106 }
7107
7108 static int __gst_unrealize(mm_player_t* player)
7109 {
7110         int ret = MM_ERROR_NONE;
7111
7112         MMPLAYER_FENTER();
7113
7114         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7115
7116         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7117         MMPLAYER_PRINT_STATE(player);
7118
7119         /* release miscellaneous information */
7120         __mmplayer_release_misc(player);
7121
7122         /* destroy pipeline */
7123         ret = __mmplayer_gst_destroy_pipeline(player);
7124         if (ret != MM_ERROR_NONE) {
7125                 LOGE("failed to destory pipeline\n");
7126                 return ret;
7127         }
7128
7129         /* release miscellaneous information.
7130            these info needs to be released after pipeline is destroyed. */
7131         __mmplayer_release_misc_post(player);
7132
7133         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7134
7135         MMPLAYER_FLEAVE();
7136
7137         return ret;
7138 }
7139
7140 static int __gst_pending_seek(mm_player_t* player)
7141 {
7142         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7143         int ret = MM_ERROR_NONE;
7144
7145         MMPLAYER_FENTER();
7146
7147         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7148
7149         if (!player->pending_seek.is_pending) {
7150                 LOGD("pending seek is not reserved. nothing to do.\n");
7151                 return ret;
7152         }
7153
7154         /* check player state if player could pending seek or not. */
7155         current_state = MMPLAYER_CURRENT_STATE(player);
7156
7157         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7158                 LOGW("try to pending seek in %s state, try next time. \n",
7159                         MMPLAYER_STATE_GET_NAME(current_state));
7160                 return ret;
7161         }
7162
7163         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7164
7165         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7166
7167         if (MM_ERROR_NONE != ret)
7168                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7169
7170         player->pending_seek.is_pending = FALSE;
7171
7172         MMPLAYER_FLEAVE();
7173
7174         return ret;
7175 }
7176
7177 static int __gst_start(mm_player_t* player)
7178 {
7179         gboolean sound_extraction = 0;
7180         int ret = MM_ERROR_NONE;
7181         gboolean async = FALSE;
7182
7183         MMPLAYER_FENTER();
7184
7185         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7186
7187         /* get sound_extraction property */
7188         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7189
7190         /* NOTE : if SetPosition was called before Start. do it now */
7191         /* streaming doesn't support it. so it should be always sync */
7192         /* !!create one more api to check if there is pending seek rather than checking variables */
7193         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7194                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7195                 ret = __gst_pause(player, FALSE);
7196                 if (ret != MM_ERROR_NONE) {
7197                         LOGE("failed to set state to PAUSED for pending seek\n");
7198                         return ret;
7199                 }
7200
7201                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7202
7203                 if (sound_extraction) {
7204                         LOGD("setting pcm extraction\n");
7205
7206                         ret = __mmplayer_set_pcm_extraction(player);
7207                         if (MM_ERROR_NONE != ret) {
7208                                 LOGW("failed to set pcm extraction\n");
7209                                 return ret;
7210                         }
7211                 } else {
7212                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7213                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7214                 }
7215         }
7216
7217         LOGD("current state before doing transition");
7218         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7219         MMPLAYER_PRINT_STATE(player);
7220
7221         /* set pipeline state to PLAYING  */
7222         if (player->es_player_push_mode)
7223                 async = TRUE;
7224         /* set pipeline state to PLAYING  */
7225         ret = __mmplayer_gst_set_state(player,
7226                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7227
7228         if (ret == MM_ERROR_NONE) {
7229                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7230         } else {
7231                 LOGE("failed to set state to PLAYING");
7232                 return ret;
7233         }
7234
7235         /* generating debug info before returning error */
7236         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7237
7238         MMPLAYER_FLEAVE();
7239
7240         return ret;
7241 }
7242
7243 static int __gst_stop(mm_player_t* player)
7244 {
7245         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7246         MMHandleType attrs = 0;
7247         gboolean rewind = FALSE;
7248         gint timeout = 0;
7249         int ret = MM_ERROR_NONE;
7250         gboolean async = FALSE;
7251
7252         MMPLAYER_FENTER();
7253
7254         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7255         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7256
7257         LOGD("current state before doing transition");
7258         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7259         MMPLAYER_PRINT_STATE(player);
7260
7261         attrs = MMPLAYER_GET_ATTRS(player);
7262         if (!attrs) {
7263                 LOGE("cannot get content attribute\n");
7264                 return MM_ERROR_PLAYER_INTERNAL;
7265         }
7266
7267         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7268         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7269
7270         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7271                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7272                 rewind = TRUE;
7273
7274         if (player->es_player_push_mode)
7275                 async = TRUE;
7276         /* set gst state */
7277         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7278
7279         /* return if set_state has failed */
7280         if (ret != MM_ERROR_NONE) {
7281                 LOGE("failed to set state.\n");
7282                 return ret;
7283         }
7284
7285         /* rewind */
7286         if (rewind) {
7287                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7288                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7289                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7290                         LOGW("failed to rewind\n");
7291                         ret = MM_ERROR_PLAYER_SEEK;
7292                 }
7293         }
7294
7295         /* initialize */
7296         player->sent_bos = FALSE;
7297
7298         if (player->es_player_push_mode) //for cloudgame
7299                 timeout = 0;
7300
7301         /* wait for seek to complete */
7302         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7303         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7304                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7305         } else {
7306                 LOGE("fail to stop player.\n");
7307                 ret = MM_ERROR_PLAYER_INTERNAL;
7308                 __mmplayer_dump_pipeline_state(player);
7309         }
7310
7311         /* generate dot file if enabled */
7312         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7313
7314         MMPLAYER_FLEAVE();
7315
7316         return ret;
7317 }
7318
7319 int __gst_pause(mm_player_t* player, gboolean async)
7320 {
7321         int ret = MM_ERROR_NONE;
7322
7323         MMPLAYER_FENTER();
7324
7325         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7326         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7327
7328         LOGD("current state before doing transition");
7329         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7330         MMPLAYER_PRINT_STATE(player);
7331
7332         /* set pipeline status to PAUSED */
7333         ret = __mmplayer_gst_set_state(player,
7334                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7335
7336         if (FALSE == async) {
7337                 if (ret != MM_ERROR_NONE) {
7338                         GstMessage *msg = NULL;
7339                         GTimer *timer = NULL;
7340                         gdouble MAX_TIMEOUT_SEC = 3;
7341
7342                         LOGE("failed to set state to PAUSED");
7343
7344                         if (player->msg_posted) {
7345                                 LOGE("error msg is already posted.");
7346                                 return ret;
7347                         }
7348
7349                         timer = g_timer_new();
7350                         g_timer_start(timer);
7351
7352                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7353
7354                         do {
7355                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7356                                 if (msg) {
7357                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7358                                                 GError *error = NULL;
7359
7360                                                 /* parse error code */
7361                                                 gst_message_parse_error(msg, &error, NULL);
7362
7363                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7364                                                         /* Note : the streaming error from the streaming source is handled
7365                                                          *   using __mmplayer_handle_streaming_error.
7366                                                          */
7367                                                         __mmplayer_handle_streaming_error(player, msg);
7368
7369                                                 } else if (error) {
7370                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7371
7372                                                         if (error->domain == GST_STREAM_ERROR)
7373                                                                 ret = __gst_handle_stream_error(player, error, msg);
7374                                                         else if (error->domain == GST_RESOURCE_ERROR)
7375                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7376                                                         else if (error->domain == GST_LIBRARY_ERROR)
7377                                                                 ret = __gst_handle_library_error(player, error->code);
7378                                                         else if (error->domain == GST_CORE_ERROR)
7379                                                                 ret = __gst_handle_core_error(player, error->code);
7380
7381                                                         g_error_free(error);
7382                                                 }
7383                                                 player->msg_posted = TRUE;
7384                                         }
7385                                         gst_message_unref(msg);
7386                                 }
7387                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7388                         /* clean */
7389                         gst_object_unref(bus);
7390                         g_timer_stop(timer);
7391                         g_timer_destroy(timer);
7392
7393                         return ret;
7394
7395                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7396                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7397
7398                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7399
7400                 } else if (ret == MM_ERROR_NONE) {
7401
7402                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7403                 }
7404         }
7405
7406         /* generate dot file before returning error */
7407         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7408
7409         MMPLAYER_FLEAVE();
7410
7411         return ret;
7412 }
7413
7414 int __gst_resume(mm_player_t* player, gboolean async)
7415 {
7416         int ret = MM_ERROR_NONE;
7417         gint timeout = 0;
7418
7419         MMPLAYER_FENTER();
7420
7421         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7422                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7423
7424         LOGD("current state before doing transition");
7425         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7426         MMPLAYER_PRINT_STATE(player);
7427
7428         /* generate dot file before returning error */
7429         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7430
7431         if (async)
7432                 LOGD("do async state transition to PLAYING.\n");
7433
7434         /* set pipeline state to PLAYING */
7435         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7436
7437         ret = __mmplayer_gst_set_state(player,
7438                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7439         if (ret != MM_ERROR_NONE) {
7440                 LOGE("failed to set state to PLAYING\n");
7441                 return ret;
7442         } else {
7443                 if (async == FALSE) {
7444                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7445                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7446                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7447                 }
7448         }
7449
7450         /* generate dot file before returning error */
7451         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7452
7453         MMPLAYER_FLEAVE();
7454
7455         return ret;
7456 }
7457
7458 static int
7459 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7460 {
7461         gint64 dur_nsec = 0;
7462         gint64 pos_nsec = 0;
7463         gboolean ret = TRUE;
7464         gboolean accurated = FALSE;
7465         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7466
7467         MMPLAYER_FENTER();
7468         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7469         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7470
7471         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7472                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7473                 goto PENDING;
7474
7475         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7476                 /* check duration */
7477                 /* NOTE : duration cannot be zero except live streaming.
7478                  *              Since some element could have some timing problemn with quering duration, try again.
7479                  */
7480                 if (player->duration == 0) {
7481                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7482                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7483                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7484                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7485                                         player->pending_seek.is_pending = TRUE;
7486                                         player->pending_seek.format = format;
7487                                         player->pending_seek.pos = position;
7488                                         player->doing_seek = FALSE;
7489                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7490                                         return MM_ERROR_NONE;
7491                                 } else {
7492                                         goto SEEK_ERROR;
7493                                 }
7494                         }
7495                         player->duration = dur_nsec;
7496                 }
7497         }
7498         LOGD("playback rate: %f\n", player->playback_rate);
7499
7500         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7501         if (accurated)
7502                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7503         else
7504                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7505
7506         /* do seek */
7507         switch (format) {
7508         case MM_PLAYER_POS_FORMAT_TIME:
7509         {
7510                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7511                         GstQuery *query = NULL;
7512                         gboolean seekable = FALSE;
7513
7514                         /* check position is valid or not */
7515                         if (position > player->duration)
7516                                 goto INVALID_ARGS;
7517
7518                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7519                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7520                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7521                                 gst_query_unref(query);
7522
7523                                 if (!seekable) {
7524                                         LOGW("non-seekable content");
7525                                         player->doing_seek = FALSE;
7526                                         return MM_ERROR_PLAYER_NO_OP;
7527                                 }
7528                         } else {
7529                                 LOGW("failed to get seeking query");
7530                                 gst_query_unref(query); /* keep seeking operation */
7531                         }
7532
7533                         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7534
7535                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7536                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7537                            This causes problem is position calculation during normal pause resume scenarios also.
7538                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7539                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7540                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7541                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7542                                         LOGW("getting current position failed in seek\n");
7543
7544                                 player->last_position = pos_nsec;
7545                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7546                         }
7547
7548                         if (player->doing_seek) {
7549                                 LOGD("not completed seek");
7550                                 return MM_ERROR_PLAYER_DOING_SEEK;
7551                         }
7552                 }
7553
7554                 if (!internal_called)
7555                         player->doing_seek = TRUE;
7556
7557                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7558                         gint64 cur_time = 0;
7559
7560                         /* get current position */
7561                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7562
7563                         /* flush */
7564                         GstEvent *event = gst_event_new_seek(1.0,
7565                                                         GST_FORMAT_TIME,
7566                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7567                                                         GST_SEEK_TYPE_SET, cur_time,
7568                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7569                         if (event)
7570                                 __gst_send_event_to_sink(player, event);
7571
7572                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7573                                 __gst_pause(player, FALSE);
7574                 }
7575
7576                 pos_nsec = position;
7577
7578                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7579                         that's why set position through property. */
7580                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7581                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7582                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7583                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7584
7585                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7586                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7587                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7588                         player->doing_seek = FALSE;
7589                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7590                 } else {
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                 }
7595
7596                 if (!ret) {
7597                         LOGE("failed to set position.");
7598                         goto SEEK_ERROR;
7599                 }
7600         }
7601         break;
7602
7603         case MM_PLAYER_POS_FORMAT_PERCENT:
7604         {
7605                 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7606
7607                 if (player->doing_seek) {
7608                         LOGD("not completed seek");
7609                         return MM_ERROR_PLAYER_DOING_SEEK;
7610                 }
7611
7612                 if (!internal_called)
7613                         player->doing_seek = TRUE;
7614
7615                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7616                 pos_nsec = (gint64)((position * player->duration) / 100);
7617                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7618                                                 GST_FORMAT_TIME, seek_flags,
7619                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7620                 if (!ret) {
7621                         LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7622                         goto SEEK_ERROR;
7623                 }
7624         }
7625         break;
7626
7627         default:
7628                 goto INVALID_ARGS;
7629         }
7630
7631         /* NOTE : store last seeking point to overcome some bad operation
7632           *     (returning zero when getting current position) of some elements
7633           */
7634         player->last_position = pos_nsec;
7635
7636         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7637         if (player->playback_rate > 1.0)
7638                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7639
7640         MMPLAYER_FLEAVE();
7641         return MM_ERROR_NONE;
7642
7643 PENDING:
7644         player->pending_seek.is_pending = TRUE;
7645         player->pending_seek.format = format;
7646         player->pending_seek.pos = position;
7647
7648         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7649                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7650                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7651                 player->pending_seek.pos);
7652
7653         return MM_ERROR_NONE;
7654
7655 INVALID_ARGS:
7656         LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7657         return MM_ERROR_INVALID_ARGUMENT;
7658
7659 SEEK_ERROR:
7660         player->doing_seek = FALSE;
7661         return MM_ERROR_PLAYER_SEEK;
7662 }
7663
7664 #define TRICKPLAY_OFFSET GST_MSECOND
7665
7666 static int
7667 __gst_get_position(mm_player_t* player, int format, gint64* position)
7668 {
7669         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7670         gint64 pos_nsec = 0;
7671         gboolean ret = TRUE;
7672
7673         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7674                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7675
7676         current_state = MMPLAYER_CURRENT_STATE(player);
7677
7678         /* NOTE : query position except paused state to overcome some bad operation
7679          * please refer to below comments in details
7680          */
7681         if (current_state != MM_PLAYER_STATE_PAUSED)
7682                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7683
7684         /* NOTE : get last point to overcome some bad operation of some elements
7685          *(returning zero when getting current position in paused state
7686          * and when failed to get postion during seeking
7687          */
7688         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7689                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7690
7691                 if (player->playback_rate < 0.0)
7692                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7693                 else
7694                         pos_nsec = player->last_position;
7695
7696                 if (!ret)
7697                         pos_nsec = player->last_position;
7698                 else
7699                         player->last_position = pos_nsec;
7700
7701                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7702
7703         } else {
7704                 if (player->duration > 0 && pos_nsec > player->duration)
7705                         pos_nsec = player->duration;
7706
7707                 player->last_position = pos_nsec;
7708         }
7709
7710         switch (format) {
7711         case MM_PLAYER_POS_FORMAT_TIME:
7712                 *position = pos_nsec;
7713                 break;
7714
7715         case MM_PLAYER_POS_FORMAT_PERCENT:
7716         {
7717                 if (player->duration <= 0) {
7718                         LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7719                         *position = 0;
7720                 } else {
7721                         LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7722                         *position = (gint64)(pos_nsec * 100 / player->duration);
7723                 }
7724                 break;
7725         }
7726         default:
7727                 return MM_ERROR_PLAYER_INTERNAL;
7728         }
7729
7730         return MM_ERROR_NONE;
7731 }
7732
7733
7734 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7735 {
7736 #define STREAMING_IS_FINISHED   0
7737 #define BUFFERING_MAX_PER       100
7738 #define DEFAULT_PER_VALUE       -1
7739 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7740
7741         MMPlayerGstElement *mainbin = NULL;
7742         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7743         gint64 buffered_total = 0;
7744         gint64 position = 0;
7745         gint buffered_sec = -1;
7746         GstBufferingMode mode = GST_BUFFERING_STREAM;
7747         gint64 content_size_time = player->duration;
7748         guint64 content_size_bytes = player->http_content_size;
7749
7750         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7751                                                 player->pipeline &&
7752                                                 player->pipeline->mainbin,
7753                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7754
7755         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7756
7757         *start_pos = 0;
7758         *stop_pos = 0;
7759
7760         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7761                 /* and rtsp is not ready yet. */
7762                 LOGW("it's only used for http streaming case.\n");
7763                 return MM_ERROR_PLAYER_NO_OP;
7764         }
7765
7766         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7767                 LOGW("Time format is not supported yet.\n");
7768                 return MM_ERROR_INVALID_ARGUMENT;
7769         }
7770
7771         if (content_size_time <= 0 || content_size_bytes <= 0) {
7772                 LOGW("there is no content size.");
7773                 return MM_ERROR_NONE;
7774         }
7775
7776         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7777                 LOGW("fail to get current position.");
7778                 return MM_ERROR_NONE;
7779         }
7780
7781         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7782                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7783
7784         mainbin = player->pipeline->mainbin;
7785         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7786
7787         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7788                 GstQuery *query = NULL;
7789                 gint byte_in_rate = 0, byte_out_rate = 0;
7790                 gint64 estimated_total = 0;
7791
7792                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7793                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7794                         LOGW("fail to get buffering query from queue2");
7795                         if (query)
7796                                 gst_query_unref(query);
7797                         return MM_ERROR_NONE;
7798                 }
7799
7800                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7801                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7802
7803                 if (mode == GST_BUFFERING_STREAM) {
7804                         /* using only queue in case of push mode(ts / mp3) */
7805                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7806                                 GST_FORMAT_BYTES, &buffered_total)) {
7807                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7808                                 stop_per = 100 * buffered_total / content_size_bytes;
7809                         }
7810                 } else {
7811                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7812                         guint idx = 0;
7813                         guint num_of_ranges = 0;
7814                         gint64 start_byte = 0, stop_byte = 0;
7815
7816                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7817                         if (estimated_total != STREAMING_IS_FINISHED) {
7818                                 /* buffered size info from queue2 */
7819                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7820                                 for (idx = 0; idx < num_of_ranges; idx++) {
7821                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7822                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7823
7824                                         buffered_total += (stop_byte - start_byte);
7825                                 }
7826                         } else
7827                                 stop_per = BUFFERING_MAX_PER;
7828                 }
7829                 gst_query_unref(query);
7830         }
7831
7832         if (stop_per == DEFAULT_PER_VALUE) {
7833                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7834                 if (dur_sec > 0) {
7835                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7836
7837                         /* buffered size info from multiqueue */
7838                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7839                                 guint curr_size_bytes = 0;
7840                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7841                                         "curr-size-bytes", &curr_size_bytes, NULL);
7842                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7843                                 buffered_total += curr_size_bytes;
7844                         }
7845
7846                         if (avg_byterate > 0)
7847                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7848                         else if (player->total_maximum_bitrate > 0)
7849                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7850                         else if (player->total_bitrate > 0)
7851                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7852
7853                         if (buffered_sec >= 0)
7854                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7855                 }
7856         }
7857
7858         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7859         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7860
7861         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7862                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7863
7864         return MM_ERROR_NONE;
7865 }
7866
7867 static int
7868 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7869 {
7870         MMPLAYER_FENTER();
7871
7872         if (!player) {
7873                 LOGW("set_message_callback is called with invalid player handle\n");
7874                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7875         }
7876
7877         player->msg_cb = callback;
7878         player->msg_cb_param = user_param;
7879
7880         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7881
7882         MMPLAYER_FLEAVE();
7883
7884         return MM_ERROR_NONE;
7885 }
7886
7887 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7888 {
7889         int ret = MM_ERROR_PLAYER_INVALID_URI;
7890         char *path = NULL;
7891
7892         MMPLAYER_FENTER();
7893
7894         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7895         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7896         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7897
7898         memset(data, 0, sizeof(MMPlayerParseProfile));
7899
7900         if ((path = strstr(uri, "es_buff://"))) {
7901                 if (strlen(path)) {
7902                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7903                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7904                         ret = MM_ERROR_NONE;
7905                 }
7906         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7907                 if (strlen(path)) {
7908                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7909                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7910                         ret = MM_ERROR_NONE;
7911                 }
7912         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7913                 if (strlen(path)) {
7914                         gchar *tmp = NULL;
7915                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7916                         tmp = g_ascii_strdown(uri, strlen(uri));
7917
7918                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7919                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7920                         else
7921                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7922
7923                         ret = MM_ERROR_NONE;
7924                         g_free(tmp);
7925                 }
7926         } else if ((path = strstr(uri, "rtspu://"))) {
7927                 if (strlen(path)) {
7928                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7929                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7930                         ret = MM_ERROR_NONE;
7931                 }
7932         } else if ((path = strstr(uri, "rtspr://"))) {
7933                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7934                 char *separater = strstr(path, "*");
7935
7936                 if (separater) {
7937                         int urgent_len = 0;
7938                         char *urgent = separater + strlen("*");
7939
7940                         if ((urgent_len = strlen(urgent))) {
7941                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7942                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7943                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7944                                 ret = MM_ERROR_NONE;
7945                         }
7946                 }
7947         } else if ((path = strstr(uri, "mms://"))) {
7948                 if (strlen(path)) {
7949                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7950                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7951                         ret = MM_ERROR_NONE;
7952                 }
7953         } else if ((path = strstr(uri, "mem://"))) {
7954                 if (strlen(path)) {
7955                         int mem_size = 0;
7956                         char *buffer = NULL;
7957                         char *seperator = strchr(path, ',');
7958                         char ext[100] = {0,}, size[100] = {0,};
7959
7960                         if (seperator) {
7961                                 if ((buffer = strstr(path, "ext="))) {
7962                                         buffer += strlen("ext=");
7963
7964                                         if (strlen(buffer)) {
7965                                                 strncpy(ext, buffer, 99);
7966
7967                                                 if ((seperator = strchr(ext, ','))
7968                                                         || (seperator = strchr(ext, ' '))
7969                                                         || (seperator = strchr(ext, '\0'))) {
7970                                                         seperator[0] = '\0';
7971                                                 }
7972                                         }
7973                                 }
7974
7975                                 if ((buffer = strstr(path, "size="))) {
7976                                         buffer += strlen("size=");
7977
7978                                         if (strlen(buffer) > 0) {
7979                                                 strncpy(size, buffer, 99);
7980
7981                                                 if ((seperator = strchr(size, ','))
7982                                                         || (seperator = strchr(size, ' '))
7983                                                         || (seperator = strchr(size, '\0'))) {
7984                                                         seperator[0] = '\0';
7985                                                 }
7986
7987                                                 mem_size = atoi(size);
7988                                         }
7989                                 }
7990                         }
7991
7992                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7993                         if (mem_size && param) {
7994                                 if (data->input_mem.buf)
7995                                         free(data->input_mem.buf);
7996                                 data->input_mem.buf = malloc(mem_size);
7997
7998                                 if (data->input_mem.buf) {
7999                                         memcpy(data->input_mem.buf, param, mem_size);
8000                                         data->input_mem.len = mem_size;
8001                                         ret = MM_ERROR_NONE;
8002                                 } else {
8003                                         LOGE("failed to alloc mem %d", mem_size);
8004                                         ret = MM_ERROR_PLAYER_INTERNAL;
8005                                 }
8006
8007                                 data->input_mem.offset = 0;
8008                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8009                         }
8010                 }
8011         } else {
8012                 gchar *location = NULL;
8013                 GError *err = NULL;
8014
8015                 if ((path = strstr(uri, "file://"))) {
8016
8017                         location = g_filename_from_uri(uri, NULL, &err);
8018
8019                         if (!location || (err != NULL)) {
8020                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8021                                  (err != NULL) ? err->message : "unknown error");
8022
8023                           if (err) g_error_free(err);
8024                           if (location) g_free(location);
8025
8026                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8027                           goto exit;
8028                         }
8029
8030                         LOGD("path from uri: %s", location);
8031                 }
8032
8033                 path = (location != NULL) ? (location) : ((char*)uri);
8034                 int file_stat = MM_ERROR_NONE;
8035
8036                 file_stat = util_exist_file_path(path);
8037
8038                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8039                 if (file_stat == MM_ERROR_NONE) {
8040                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8041
8042                         if (util_is_sdp_file(path)) {
8043                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8044                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8045                         } else {
8046                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8047                         }
8048                         ret = MM_ERROR_NONE;
8049                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8050                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8051                 } else {
8052                         LOGE("invalid uri, could not play..\n");
8053                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8054                 }
8055
8056                 if (location) g_free(location);
8057         }
8058
8059 exit:
8060         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8061                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8062         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8063                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8064
8065         /* dump parse result */
8066         SECURE_LOGW("incomming uri : %s\n", uri);
8067         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8068                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8069
8070         MMPLAYER_FLEAVE();
8071
8072         return ret;
8073 }
8074
8075 gboolean
8076 __mmplayer_can_do_interrupt(mm_player_t *player)
8077 {
8078         if (!player || !player->pipeline || !player->attrs) {
8079                 LOGW("not initialized");
8080                 goto FAILED;
8081         }
8082
8083         if (player->set_mode.pcm_extraction) {
8084                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8085                 goto FAILED;
8086         }
8087
8088         /* check if seeking */
8089         if (player->doing_seek) {
8090                 MMMessageParamType msg_param;
8091                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8092                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8093                 player->doing_seek = FALSE;
8094                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8095                 goto FAILED;
8096         }
8097
8098         /* check other thread */
8099         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8100                 LOGW("locked already, cmd state : %d", player->cmd);
8101
8102                 /* check application command */
8103                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8104                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8105
8106                         /* lock will be released at mrp_resource_release_cb() */
8107                         MMPLAYER_CMD_LOCK(player);
8108                         goto INTERRUPT;
8109                 }
8110                 LOGW("nothing to do");
8111                 goto FAILED;
8112         } else {
8113                 LOGW("can interrupt immediately");
8114                 goto INTERRUPT;
8115         }
8116
8117 FAILED:    /* with CMD UNLOCKED */
8118         return FALSE;
8119
8120 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8121         return TRUE;
8122 }
8123
8124 static int
8125 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8126                 void *user_data)
8127 {
8128         mm_player_t *player = NULL;
8129
8130         MMPLAYER_FENTER();
8131
8132         if (user_data == NULL) {
8133                 LOGE("- user_data is null\n");
8134                 return FALSE;
8135         }
8136         player = (mm_player_t *)user_data;
8137
8138         /* do something to release resource here.
8139          * player stop and interrupt forwarding */
8140         if (!__mmplayer_can_do_interrupt(player)) {
8141                 LOGW("no need to interrupt, so leave");
8142         } else {
8143                 MMMessageParamType msg = {0, };
8144                 gint64 pos = 0;
8145
8146                 player->interrupted_by_resource = TRUE;
8147
8148                 /* get last play position */
8149                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8150                         LOGW("failed to get play position.");
8151                 } else {
8152                         msg.union_type = MM_MSG_UNION_TIME;
8153                         msg.time.elapsed = pos;
8154                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8155                 }
8156                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8157                 if (_mmplayer_unrealize((MMHandleType)player))
8158                         LOGW("failed to unrealize");
8159
8160                 /* lock is called in __mmplayer_can_do_interrupt() */
8161                 MMPLAYER_CMD_UNLOCK(player);
8162         }
8163
8164         if (res == player->video_overlay_resource)
8165                 player->video_overlay_resource = FALSE;
8166         else
8167                 player->video_decoder_resource = FALSE;
8168
8169         MMPLAYER_FLEAVE();
8170
8171         return FALSE;
8172 }
8173
8174 int
8175 _mmplayer_create_player(MMHandleType handle)
8176 {
8177         int ret = MM_ERROR_PLAYER_INTERNAL;
8178         bool enabled = false;
8179
8180         mm_player_t* player = MM_PLAYER_CAST(handle);
8181
8182         MMPLAYER_FENTER();
8183
8184         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8185
8186         /* initialize player state */
8187         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8188         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8189         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8190         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8191
8192         /* check current state */
8193         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8194
8195         /* construct attributes */
8196         player->attrs = _mmplayer_construct_attribute(handle);
8197
8198         if (!player->attrs) {
8199                 LOGE("Failed to construct attributes\n");
8200                 return ret;
8201         }
8202
8203         /* initialize gstreamer with configured parameter */
8204         if (!__mmplayer_init_gstreamer(player)) {
8205                 LOGE("Initializing gstreamer failed\n");
8206                 _mmplayer_deconstruct_attribute(handle);
8207                 return ret;
8208         }
8209
8210         /* create lock. note that g_tread_init() has already called in gst_init() */
8211         g_mutex_init(&player->fsink_lock);
8212
8213         /* create update tag lock */
8214         g_mutex_init(&player->update_tag_lock);
8215
8216         /* create next play mutex */
8217         g_mutex_init(&player->next_play_thread_mutex);
8218
8219         /* create next play cond */
8220         g_cond_init(&player->next_play_thread_cond);
8221
8222         /* create next play thread */
8223         player->next_play_thread =
8224                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8225         if (!player->next_play_thread) {
8226                 LOGE("failed to create next play thread");
8227                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8228                 g_mutex_clear(&player->next_play_thread_mutex);
8229                 g_cond_clear(&player->next_play_thread_cond);
8230                 goto ERROR;
8231         }
8232
8233         player->bus_msg_q = g_queue_new();
8234         if (!player->bus_msg_q) {
8235                 LOGE("failed to create queue for bus_msg");
8236                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8237                 goto ERROR;
8238         }
8239
8240         ret = _mmplayer_initialize_video_capture(player);
8241         if (ret != MM_ERROR_NONE) {
8242                 LOGE("failed to initialize video capture\n");
8243                 goto ERROR;
8244         }
8245
8246         /* initialize resource manager */
8247         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8248                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8249                         &player->resource_manager)) {
8250                 LOGE("failed to initialize resource manager\n");
8251                 goto ERROR;
8252         }
8253
8254         if (MMPLAYER_IS_HTTP_PD(player)) {
8255                 player->pd_downloader = NULL;
8256                 player->pd_file_save_path = NULL;
8257         }
8258
8259         /* create video bo lock and cond */
8260         g_mutex_init(&player->video_bo_mutex);
8261         g_cond_init(&player->video_bo_cond);
8262
8263         /* create media stream callback mutex */
8264         g_mutex_init(&player->media_stream_cb_lock);
8265
8266         /* create subtitle info lock and cond */
8267         g_mutex_init(&player->subtitle_info_mutex);
8268         g_cond_init(&player->subtitle_info_cond);
8269
8270         player->streaming_type = STREAMING_SERVICE_NONE;
8271
8272         /* give default value of audio effect setting */
8273         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8274         player->sound.rg_enable = false;
8275         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8276
8277         player->play_subtitle = FALSE;
8278         player->use_deinterleave = FALSE;
8279         player->max_audio_channels = 0;
8280         player->video_share_api_delta = 0;
8281         player->video_share_clock_delta = 0;
8282         player->has_closed_caption = FALSE;
8283         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8284         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8285         player->pending_resume = FALSE;
8286         if (player->ini.dump_element_keyword[0][0] == '\0')
8287                 player->ini.set_dump_element_flag = FALSE;
8288         else
8289                 player->ini.set_dump_element_flag = TRUE;
8290
8291         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8292         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8293         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8294
8295         /* Set video360 settings to their defaults for just-created player.
8296          * */
8297
8298         player->is_360_feature_enabled = FALSE;
8299         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8300                 LOGI("spherical feature info: %d", enabled);
8301                 if (enabled)
8302                         player->is_360_feature_enabled = TRUE;
8303         } else {
8304                 LOGE("failed to get spherical feature info");
8305         }
8306
8307         player->is_content_spherical = FALSE;
8308         player->is_video360_enabled = TRUE;
8309         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8310         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8311         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8312         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8313         player->video360_zoom = 1.0f;
8314         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8315         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8316
8317         /* set player state to null */
8318         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8319         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8320
8321         return MM_ERROR_NONE;
8322
8323 ERROR:
8324         /* free lock */
8325         g_mutex_clear(&player->fsink_lock);
8326
8327         /* free update tag lock */
8328         g_mutex_clear(&player->update_tag_lock);
8329
8330         g_queue_free(player->bus_msg_q);
8331
8332         /* free next play thread */
8333         if (player->next_play_thread) {
8334                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8335                 player->next_play_thread_exit = TRUE;
8336                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8337                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8338
8339                 g_thread_join(player->next_play_thread);
8340                 player->next_play_thread = NULL;
8341
8342                 g_mutex_clear(&player->next_play_thread_mutex);
8343                 g_cond_clear(&player->next_play_thread_cond);
8344         }
8345
8346         /* release attributes */
8347         _mmplayer_deconstruct_attribute(handle);
8348
8349         MMPLAYER_FLEAVE();
8350
8351         return ret;
8352 }
8353
8354 static gboolean
8355 __mmplayer_init_gstreamer(mm_player_t* player)
8356 {
8357         static gboolean initialized = FALSE;
8358         static const int max_argc = 50;
8359         gint* argc = NULL;
8360         gchar** argv = NULL;
8361         gchar** argv2 = NULL;
8362         GError *err = NULL;
8363         int i = 0;
8364         int arg_count = 0;
8365
8366         if (initialized) {
8367                 LOGD("gstreamer already initialized.\n");
8368                 return TRUE;
8369         }
8370
8371         /* alloc */
8372         argc = malloc(sizeof(int));
8373         argv = malloc(sizeof(gchar*) * max_argc);
8374         argv2 = malloc(sizeof(gchar*) * max_argc);
8375
8376         if (!argc || !argv || !argv2)
8377                 goto ERROR;
8378
8379         memset(argv, 0, sizeof(gchar*) * max_argc);
8380         memset(argv2, 0, sizeof(gchar*) * max_argc);
8381
8382         /* add initial */
8383         *argc = 1;
8384         argv[0] = g_strdup("mmplayer");
8385
8386         /* add gst_param */
8387         for (i = 0; i < 5; i++) {
8388                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8389                 if (strlen(player->ini.gst_param[i]) > 0) {
8390                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8391                         (*argc)++;
8392                 }
8393         }
8394
8395         /* we would not do fork for scanning plugins */
8396         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8397         (*argc)++;
8398
8399         /* check disable registry scan */
8400         if (player->ini.skip_rescan) {
8401                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8402                 (*argc)++;
8403         }
8404
8405         /* check disable segtrap */
8406         if (player->ini.disable_segtrap) {
8407                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8408                 (*argc)++;
8409         }
8410
8411         LOGD("initializing gstreamer with following parameter\n");
8412         LOGD("argc : %d\n", *argc);
8413         arg_count = *argc;
8414
8415         for (i = 0; i < arg_count; i++) {
8416                 argv2[i] = argv[i];
8417                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8418         }
8419
8420         /* initializing gstreamer */
8421         if (!gst_init_check(argc, &argv, &err)) {
8422                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8423                 if (err)
8424                         g_error_free(err);
8425
8426                 goto ERROR;
8427         }
8428         /* release */
8429         for (i = 0; i < arg_count; i++) {
8430                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8431                 MMPLAYER_FREEIF(argv2[i]);
8432         }
8433
8434         MMPLAYER_FREEIF(argv);
8435         MMPLAYER_FREEIF(argv2);
8436         MMPLAYER_FREEIF(argc);
8437
8438         /* done */
8439         initialized = TRUE;
8440
8441         return TRUE;
8442
8443 ERROR:
8444
8445         /* release */
8446         for (i = 0; i < arg_count; i++) {
8447                 LOGD("free[%d] : %s\n", i, argv2[i]);
8448                 MMPLAYER_FREEIF(argv2[i]);
8449         }
8450
8451         MMPLAYER_FREEIF(argv);
8452         MMPLAYER_FREEIF(argv2);
8453         MMPLAYER_FREEIF(argc);
8454
8455         return FALSE;
8456 }
8457
8458 int
8459 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8460 {
8461         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8462
8463         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8464                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8465                 MMPLAYER_FREEIF(player->pd_file_save_path);
8466         }
8467
8468         return MM_ERROR_NONE;
8469 }
8470
8471 static void
8472 __mmplayer_check_async_state_transition(mm_player_t* player)
8473 {
8474         GstState element_state = GST_STATE_VOID_PENDING;
8475         GstState element_pending_state = GST_STATE_VOID_PENDING;
8476         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8477         GstElement * element = NULL;
8478         gboolean async = FALSE;
8479
8480         /* check player handle */
8481         MMPLAYER_RETURN_IF_FAIL(player &&
8482                                                 player->pipeline &&
8483                                                 player->pipeline->mainbin &&
8484                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8485
8486         if (player->attrs)
8487                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8488
8489         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8490                 LOGD("don't need to check the pipeline state");
8491                 return;
8492         }
8493
8494         MMPLAYER_PRINT_STATE(player);
8495
8496         /* wait for state transition */
8497         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8498         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8499
8500         if (ret == GST_STATE_CHANGE_FAILURE) {
8501                 LOGE(" [%s] state : %s   pending : %s \n",
8502                         GST_ELEMENT_NAME(element),
8503                         gst_element_state_get_name(element_state),
8504                         gst_element_state_get_name(element_pending_state));
8505
8506                 /* dump state of all element */
8507                 __mmplayer_dump_pipeline_state(player);
8508
8509                 return;
8510         }
8511
8512         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8513         return;
8514 }
8515
8516 int
8517 _mmplayer_destroy(MMHandleType handle)
8518 {
8519         mm_player_t* player = MM_PLAYER_CAST(handle);
8520
8521         MMPLAYER_FENTER();
8522
8523         /* check player handle */
8524         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8525
8526         /* destroy can called at anytime */
8527         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8528
8529         /* check async state transition */
8530         __mmplayer_check_async_state_transition(player);
8531
8532         __mmplayer_destroy_streaming_ext(player);
8533
8534         /* release next play thread */
8535         if (player->next_play_thread) {
8536                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8537                 player->next_play_thread_exit = TRUE;
8538                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8539                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8540
8541                 LOGD("waitting for next play thread exit\n");
8542                 g_thread_join(player->next_play_thread);
8543                 g_mutex_clear(&player->next_play_thread_mutex);
8544                 g_cond_clear(&player->next_play_thread_cond);
8545                 LOGD("next play thread released\n");
8546         }
8547
8548         _mmplayer_release_video_capture(player);
8549
8550         /* de-initialize resource manager */
8551         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8552                         player->resource_manager))
8553                 LOGE("failed to deinitialize resource manager\n");
8554
8555         /* release pipeline */
8556         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8557                 LOGE("failed to destory pipeline\n");
8558                 return MM_ERROR_PLAYER_INTERNAL;
8559         }
8560
8561         g_queue_free(player->bus_msg_q);
8562
8563         /* release subtitle info lock and cond */
8564         g_mutex_clear(&player->subtitle_info_mutex);
8565         g_cond_clear(&player->subtitle_info_cond);
8566
8567         __mmplayer_release_dump_list(player->dump_list);
8568
8569         /* release miscellaneous information */
8570         __mmplayer_release_misc(player);
8571
8572         /* release miscellaneous information.
8573            these info needs to be released after pipeline is destroyed. */
8574         __mmplayer_release_misc_post(player);
8575
8576         /* release attributes */
8577         _mmplayer_deconstruct_attribute(handle);
8578
8579         /* release lock */
8580         g_mutex_clear(&player->fsink_lock);
8581
8582         /* release lock */
8583         g_mutex_clear(&player->update_tag_lock);
8584
8585         /* release video bo lock and cond */
8586         g_mutex_clear(&player->video_bo_mutex);
8587         g_cond_clear(&player->video_bo_cond);
8588
8589         /* release media stream callback lock */
8590         g_mutex_clear(&player->media_stream_cb_lock);
8591
8592         MMPLAYER_FLEAVE();
8593
8594         return MM_ERROR_NONE;
8595 }
8596
8597 int
8598 __mmplayer_realize_streaming_ext(mm_player_t* player)
8599 {
8600         int ret = MM_ERROR_NONE;
8601
8602         MMPLAYER_FENTER();
8603         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8604
8605         if (MMPLAYER_IS_HTTP_PD(player)) {
8606                 gboolean bret = FALSE;
8607
8608                 player->pd_downloader = _mmplayer_create_pd_downloader();
8609                 if (!player->pd_downloader) {
8610                         LOGE("Unable to create PD Downloader...");
8611                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8612                 }
8613
8614                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8615
8616                 if (FALSE == bret) {
8617                         LOGE("Unable to create PD Downloader...");
8618                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8619                 }
8620         }
8621
8622         MMPLAYER_FLEAVE();
8623         return ret;
8624 }
8625
8626 int
8627 _mmplayer_realize(MMHandleType hplayer)
8628 {
8629         mm_player_t* player = (mm_player_t*)hplayer;
8630         char *uri = NULL;
8631         void *param = NULL;
8632         MMHandleType attrs = 0;
8633         int ret = MM_ERROR_NONE;
8634
8635         MMPLAYER_FENTER();
8636
8637         /* check player handle */
8638         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8639
8640         /* check current state */
8641         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8642
8643         attrs = MMPLAYER_GET_ATTRS(player);
8644         if (!attrs) {
8645                 LOGE("fail to get attributes.\n");
8646                 return MM_ERROR_PLAYER_INTERNAL;
8647         }
8648         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8649         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8650
8651         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8652                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8653
8654                 if (ret != MM_ERROR_NONE) {
8655                         LOGE("failed to parse profile\n");
8656                         return ret;
8657                 }
8658         }
8659
8660         if (uri && (strstr(uri, "es_buff://"))) {
8661                 if (strstr(uri, "es_buff://push_mode"))
8662                         player->es_player_push_mode = TRUE;
8663                 else
8664                         player->es_player_push_mode = FALSE;
8665         }
8666
8667         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8668                 LOGW("mms protocol is not supported format.\n");
8669                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8670         }
8671
8672         if (MMPLAYER_IS_STREAMING(player))
8673                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8674         else
8675                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8676
8677         player->smooth_streaming = FALSE;
8678         player->videodec_linked  = 0;
8679         player->videosink_linked = 0;
8680         player->audiodec_linked  = 0;
8681         player->audiosink_linked = 0;
8682         player->textsink_linked = 0;
8683         player->is_external_subtitle_present = FALSE;
8684         player->is_external_subtitle_added_now = FALSE;
8685         /* set the subtitle ON default */
8686         player->is_subtitle_off = FALSE;
8687
8688         /* realize pipeline */
8689         ret = __gst_realize(player);
8690         if (ret != MM_ERROR_NONE)
8691                 LOGE("fail to realize the player.\n");
8692         else
8693                 ret = __mmplayer_realize_streaming_ext(player);
8694
8695         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8696
8697         MMPLAYER_FLEAVE();
8698
8699         return ret;
8700 }
8701
8702 int
8703 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8704 {
8705         MMPLAYER_FENTER();
8706         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8707
8708         /* destroy can called at anytime */
8709         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8710                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8711
8712         MMPLAYER_FLEAVE();
8713         return MM_ERROR_NONE;
8714 }
8715
8716 int
8717 _mmplayer_unrealize(MMHandleType hplayer)
8718 {
8719         mm_player_t* player = (mm_player_t*)hplayer;
8720         int ret = MM_ERROR_NONE;
8721
8722         MMPLAYER_FENTER();
8723
8724         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8725
8726         MMPLAYER_CMD_UNLOCK(player);
8727         /* destroy the gst bus msg thread which is created during realize.
8728            this funct have to be called before getting cmd lock. */
8729         _mmplayer_bus_msg_thread_destroy(player);
8730         MMPLAYER_CMD_LOCK(player);
8731
8732         /* check current state */
8733         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8734
8735         /* check async state transition */
8736         __mmplayer_check_async_state_transition(player);
8737
8738         __mmplayer_unrealize_streaming_ext(player);
8739
8740         /* unrealize pipeline */
8741         ret = __gst_unrealize(player);
8742
8743         /* set asm stop if success */
8744         if (MM_ERROR_NONE == ret) {
8745                 if (!player->interrupted_by_resource) {
8746                         if (player->video_decoder_resource != NULL) {
8747                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8748                                                 player->video_decoder_resource);
8749                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8750                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8751                                 else
8752                                         player->video_decoder_resource = NULL;
8753                         }
8754
8755                         if (player->video_overlay_resource != NULL) {
8756                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8757                                                 player->video_overlay_resource);
8758                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8759                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8760                                 else
8761                                         player->video_overlay_resource = NULL;
8762                         }
8763
8764                         ret = mm_resource_manager_commit(player->resource_manager);
8765                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8766                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8767                 }
8768         } else
8769                 LOGE("failed and don't change asm state to stop");
8770
8771         MMPLAYER_FLEAVE();
8772
8773         return ret;
8774 }
8775
8776 int
8777 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8778 {
8779         mm_player_t* player = (mm_player_t*)hplayer;
8780
8781         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8782
8783         return __gst_set_message_callback(player, callback, user_param);
8784 }
8785
8786 int
8787 _mmplayer_get_state(MMHandleType hplayer, int* state)
8788 {
8789         mm_player_t *player = (mm_player_t*)hplayer;
8790
8791         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8792
8793         *state = MMPLAYER_CURRENT_STATE(player);
8794
8795         return MM_ERROR_NONE;
8796 }
8797
8798
8799 int
8800 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8801 {
8802         mm_player_t* player = (mm_player_t*) hplayer;
8803         GstElement* vol_element = NULL;
8804         int i = 0;
8805
8806         MMPLAYER_FENTER();
8807
8808         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8809
8810         LOGD("volume [L]=%f:[R]=%f\n",
8811                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8812
8813         /* invalid factor range or not */
8814         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8815                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8816                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8817                         return MM_ERROR_INVALID_ARGUMENT;
8818                 }
8819         }
8820
8821         /* not support to set other value into each channel */
8822         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8823                 return MM_ERROR_INVALID_ARGUMENT;
8824
8825         /* Save volume to handle. Currently the first array element will be saved. */
8826         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8827
8828         /* check pipeline handle */
8829         if (!player->pipeline || !player->pipeline->audiobin) {
8830                 LOGD("audiobin is not created yet\n");
8831                 LOGD("but, current stored volume will be set when it's created.\n");
8832
8833                 /* NOTE : stored volume will be used in create_audiobin
8834                  * returning MM_ERROR_NONE here makes application to able to
8835                  * set volume at anytime.
8836                  */
8837                 return MM_ERROR_NONE;
8838         }
8839
8840         /* setting volume to volume element */
8841         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8842
8843         if (vol_element) {
8844                 LOGD("volume is set [%f]\n", player->sound.volume);
8845                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8846         }
8847
8848         MMPLAYER_FLEAVE();
8849
8850         return MM_ERROR_NONE;
8851 }
8852
8853
8854 int
8855 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8856 {
8857         mm_player_t* player = (mm_player_t*) hplayer;
8858         int i = 0;
8859
8860         MMPLAYER_FENTER();
8861
8862         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8863         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8864
8865         /* returning stored volume */
8866         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8867                 volume->level[i] = player->sound.volume;
8868
8869         MMPLAYER_FLEAVE();
8870
8871         return MM_ERROR_NONE;
8872 }
8873
8874 int
8875 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8876 {
8877         mm_player_t* player = (mm_player_t*) hplayer;
8878         GstElement* vol_element = NULL;
8879
8880         MMPLAYER_FENTER();
8881
8882         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8883
8884         /* mute value shoud 0 or 1 */
8885         if (mute != 0 && mute != 1) {
8886                 LOGE("bad mute value\n");
8887
8888                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8889                 return MM_ERROR_INVALID_ARGUMENT;
8890         }
8891
8892         player->sound.mute = mute;
8893
8894         /* just hold mute value if pipeline is not ready */
8895         if (!player->pipeline || !player->pipeline->audiobin) {
8896                 LOGD("pipeline is not ready. holding mute value\n");
8897                 return MM_ERROR_NONE;
8898         }
8899
8900         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8901
8902         /* NOTE : volume will only created when the bt is enabled */
8903         if (vol_element) {
8904                 LOGD("mute : %d\n", mute);
8905                 g_object_set(vol_element, "mute", mute, NULL);
8906         } else
8907                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8908
8909         MMPLAYER_FLEAVE();
8910
8911         return MM_ERROR_NONE;
8912 }
8913
8914 int
8915 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8916 {
8917         mm_player_t* player = (mm_player_t*) hplayer;
8918
8919         MMPLAYER_FENTER();
8920
8921         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8922         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8923
8924         /* just hold mute value if pipeline is not ready */
8925         if (!player->pipeline || !player->pipeline->audiobin) {
8926                 LOGD("pipeline is not ready. returning stored value\n");
8927                 *pmute = player->sound.mute;
8928                 return MM_ERROR_NONE;
8929         }
8930
8931         *pmute = player->sound.mute;
8932
8933         MMPLAYER_FLEAVE();
8934
8935         return MM_ERROR_NONE;
8936 }
8937
8938 int
8939 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8940 {
8941         mm_player_t* player = (mm_player_t*) hplayer;
8942
8943         MMPLAYER_FENTER();
8944
8945         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8946
8947         player->video_stream_changed_cb = callback;
8948         player->video_stream_changed_cb_user_param = user_param;
8949         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8950
8951         MMPLAYER_FLEAVE();
8952
8953         return MM_ERROR_NONE;
8954 }
8955
8956 int
8957 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8958 {
8959         mm_player_t* player = (mm_player_t*) hplayer;
8960
8961         MMPLAYER_FENTER();
8962
8963         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8964
8965         player->audio_stream_changed_cb = callback;
8966         player->audio_stream_changed_cb_user_param = user_param;
8967         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8968
8969         MMPLAYER_FLEAVE();
8970
8971         return MM_ERROR_NONE;
8972 }
8973
8974 int
8975 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8976 {
8977         mm_player_t* player = (mm_player_t*) hplayer;
8978
8979         MMPLAYER_FENTER();
8980
8981         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8982
8983         player->audio_stream_render_cb_ex = callback;
8984         player->audio_stream_cb_user_param = user_param;
8985         player->audio_stream_sink_sync = sync;
8986         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);
8987
8988         MMPLAYER_FLEAVE();
8989
8990         return MM_ERROR_NONE;
8991 }
8992
8993 int
8994 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8995 {
8996         mm_player_t* player = (mm_player_t*) hplayer;
8997
8998         MMPLAYER_FENTER();
8999
9000         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9001
9002         if (callback && !player->bufmgr)
9003                 player->bufmgr = tbm_bufmgr_init(-1);
9004
9005         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9006         player->video_stream_cb = callback;
9007         player->video_stream_cb_user_param = user_param;
9008
9009         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9010
9011         MMPLAYER_FLEAVE();
9012
9013         return MM_ERROR_NONE;
9014 }
9015
9016 int
9017 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9018 {
9019         mm_player_t* player = (mm_player_t*) hplayer;
9020
9021         MMPLAYER_FENTER();
9022
9023         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9024
9025         player->audio_stream_cb = callback;
9026         player->audio_stream_cb_user_param = user_param;
9027         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9028
9029         MMPLAYER_FLEAVE();
9030
9031         return MM_ERROR_NONE;
9032 }
9033
9034 static int
9035 __mmplayer_start_streaming_ext(mm_player_t *player)
9036 {
9037         gint ret = MM_ERROR_NONE;
9038
9039         MMPLAYER_FENTER();
9040         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9041
9042         if (MMPLAYER_IS_HTTP_PD(player)) {
9043                 if (!player->pd_downloader) {
9044                         ret = __mmplayer_realize_streaming_ext(player);
9045
9046                         if (ret != MM_ERROR_NONE) {
9047                                 LOGE("failed to realize streaming ext\n");
9048                                 return ret;
9049                         }
9050                 }
9051
9052                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9053                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9054                         if (!ret) {
9055                                 LOGE("ERROR while starting PD...\n");
9056                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9057                         }
9058                         ret = MM_ERROR_NONE;
9059                 }
9060         }
9061
9062         MMPLAYER_FLEAVE();
9063         return ret;
9064 }
9065
9066 int
9067 _mmplayer_start(MMHandleType hplayer)
9068 {
9069         mm_player_t* player = (mm_player_t*) hplayer;
9070         gint ret = MM_ERROR_NONE;
9071
9072         MMPLAYER_FENTER();
9073
9074         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9075
9076         /* check current state */
9077         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9078
9079         /* NOTE : we should check and create pipeline again if not created as we destroy
9080          * whole pipeline when stopping in streamming playback
9081          */
9082         if (!player->pipeline) {
9083                 ret = __gst_realize(player);
9084                 if (MM_ERROR_NONE != ret) {
9085                         LOGE("failed to realize before starting. only in streamming\n");
9086                         /* unlock */
9087                         return ret;
9088                 }
9089         }
9090
9091         ret = __mmplayer_start_streaming_ext(player);
9092         if (ret != MM_ERROR_NONE) {
9093                 LOGE("failed to start streaming ext 0x%X", ret);
9094                 return ret;
9095         }
9096
9097         /* start pipeline */
9098         ret = __gst_start(player);
9099         if (ret != MM_ERROR_NONE)
9100                 LOGE("failed to start player.\n");
9101
9102         MMPLAYER_FLEAVE();
9103
9104         return ret;
9105 }
9106
9107 /* NOTE: post "not supported codec message" to application
9108  * when one codec is not found during AUTOPLUGGING in MSL.
9109  * So, it's separated with error of __mmplayer_gst_callback().
9110  * And, if any codec is not found, don't send message here.
9111  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9112  */
9113 int
9114 __mmplayer_handle_missed_plugin(mm_player_t* player)
9115 {
9116         MMMessageParamType msg_param;
9117         memset(&msg_param, 0, sizeof(MMMessageParamType));
9118         gboolean post_msg_direct = FALSE;
9119
9120         MMPLAYER_FENTER();
9121
9122         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9123
9124         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9125                         player->not_supported_codec, player->can_support_codec);
9126
9127         if (player->not_found_demuxer) {
9128                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9129                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9130
9131                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9132                 MMPLAYER_FREEIF(msg_param.data);
9133
9134                 return MM_ERROR_NONE;
9135         }
9136
9137         if (player->not_supported_codec) {
9138                 if (player->can_support_codec) {
9139                         // There is one codec to play
9140                         post_msg_direct = TRUE;
9141                 } else {
9142                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9143                                 post_msg_direct = TRUE;
9144                 }
9145
9146                 if (post_msg_direct) {
9147                         MMMessageParamType msg_param;
9148                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9149
9150                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9151                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9152
9153                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9154                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9155                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9156                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9157
9158                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9159                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9160                         }
9161
9162                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9163
9164                         MMPLAYER_FREEIF(msg_param.data);
9165
9166                         return MM_ERROR_NONE;
9167                 } else {
9168                         // no any supported codec case
9169                         LOGW("not found any codec, posting error code to application.\n");
9170
9171                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9172                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9173                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9174                         } else {
9175                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9176                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9177                         }
9178
9179                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9180
9181                         MMPLAYER_FREEIF(msg_param.data);
9182                 }
9183         }
9184
9185         MMPLAYER_FLEAVE();
9186
9187         return MM_ERROR_NONE;
9188 }
9189
9190 static void __mmplayer_check_pipeline(mm_player_t* player)
9191 {
9192         GstState element_state = GST_STATE_VOID_PENDING;
9193         GstState element_pending_state = GST_STATE_VOID_PENDING;
9194         gint timeout = 0;
9195         int ret = MM_ERROR_NONE;
9196
9197         if (player->gapless.reconfigure) {
9198                 LOGW("pipeline is under construction.\n");
9199
9200                 MMPLAYER_PLAYBACK_LOCK(player);
9201                 MMPLAYER_PLAYBACK_UNLOCK(player);
9202
9203                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9204
9205                 /* wait for state transition */
9206                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9207
9208                 if (ret == GST_STATE_CHANGE_FAILURE)
9209                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9210         }
9211 }
9212
9213 /* NOTE : it should be able to call 'stop' anytime*/
9214 int
9215 _mmplayer_stop(MMHandleType hplayer)
9216 {
9217         mm_player_t* player = (mm_player_t*)hplayer;
9218         int ret = MM_ERROR_NONE;
9219
9220         MMPLAYER_FENTER();
9221
9222         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9223
9224         /* check current state */
9225         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9226
9227         /* check pipline building state */
9228         __mmplayer_check_pipeline(player);
9229         __mmplayer_reset_gapless_state(player);
9230
9231         /* NOTE : application should not wait for EOS after calling STOP */
9232         __mmplayer_cancel_eos_timer(player);
9233
9234         __mmplayer_unrealize_streaming_ext(player);
9235
9236         /* reset */
9237         player->doing_seek = FALSE;
9238
9239         /* stop pipeline */
9240         ret = __gst_stop(player);
9241
9242         if (ret != MM_ERROR_NONE)
9243                 LOGE("failed to stop player.\n");
9244
9245         MMPLAYER_FLEAVE();
9246
9247         return ret;
9248 }
9249
9250 int
9251 _mmplayer_pause(MMHandleType hplayer)
9252 {
9253         mm_player_t* player = (mm_player_t*)hplayer;
9254         gint64 pos_nsec = 0;
9255         gboolean async = FALSE;
9256         gint ret = MM_ERROR_NONE;
9257
9258         MMPLAYER_FENTER();
9259
9260         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9261
9262         /* check current state */
9263         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9264
9265         /* check pipline building state */
9266         __mmplayer_check_pipeline(player);
9267
9268         switch (MMPLAYER_CURRENT_STATE(player)) {
9269         case MM_PLAYER_STATE_READY:
9270                 {
9271                         /* check prepare async or not.
9272                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9273                          */
9274                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9275                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9276
9277                         /* Changing back sync of rtspsrc to async */
9278                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9279                                 LOGD("async prepare working mode for rtsp");
9280                                 async = TRUE;
9281                         }
9282                 }
9283                 break;
9284
9285         case MM_PLAYER_STATE_PLAYING:
9286                 {
9287                         /* NOTE : store current point to overcome some bad operation
9288                         *(returning zero when getting current position in paused state) of some
9289                         * elements
9290                         */
9291                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9292                                 LOGW("getting current position failed in paused\n");
9293
9294                         player->last_position = pos_nsec;
9295
9296                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9297                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9298                            This causes problem is position calculation during normal pause resume scenarios also.
9299                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9300                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9301                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9302                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9303                         }
9304                 }
9305                 break;
9306         }
9307
9308         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9309                 LOGD("doing async pause in case of ms buff src");
9310                 async = TRUE;
9311         }
9312
9313         /* pause pipeline */
9314         ret = __gst_pause(player, async);
9315
9316         if (ret != MM_ERROR_NONE)
9317                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9318
9319         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9320                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9321                         LOGE("failed to update display_rotation");
9322         }
9323
9324         MMPLAYER_FLEAVE();
9325
9326         return ret;
9327 }
9328
9329 int
9330 _mmplayer_resume(MMHandleType hplayer)
9331 {
9332         mm_player_t* player = (mm_player_t*)hplayer;
9333         int ret = MM_ERROR_NONE;
9334         gboolean async = FALSE;
9335
9336         MMPLAYER_FENTER();
9337
9338         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9339
9340         /* Changing back sync mode rtspsrc to async */
9341         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9342                 LOGD("async resume for rtsp case");
9343                 async = TRUE;
9344         }
9345
9346         /* check current state */
9347         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9348
9349         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9350                 LOGD("force resume even during buffering");
9351                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9352         }
9353
9354         ret = __gst_resume(player, async);
9355
9356         if (ret != MM_ERROR_NONE)
9357                 LOGE("failed to resume player.\n");
9358
9359         MMPLAYER_FLEAVE();
9360
9361         return ret;
9362 }
9363
9364 static int
9365 __mmplayer_set_pcm_extraction(mm_player_t* player)
9366 {
9367         gint64 start_nsec = 0;
9368         gint64 end_nsec = 0;
9369         gint64 dur_nsec = 0;
9370         gint64 dur_msec = 0;
9371         int required_start = 0;
9372         int required_end = 0;
9373         int ret = 0;
9374
9375         MMPLAYER_FENTER();
9376
9377         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9378
9379         mm_attrs_multiple_get(player->attrs,
9380                 NULL,
9381                 "pcm_extraction_start_msec", &required_start,
9382                 "pcm_extraction_end_msec", &required_end,
9383                 NULL);
9384
9385         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9386
9387         if (required_start == 0 && required_end == 0) {
9388                 LOGD("extracting entire stream");
9389                 return MM_ERROR_NONE;
9390         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9391                 LOGD("invalid range for pcm extraction");
9392                 return MM_ERROR_INVALID_ARGUMENT;
9393         }
9394
9395         /* get duration */
9396         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9397         if (!ret) {
9398                 LOGE("failed to get duration");
9399                 return MM_ERROR_PLAYER_INTERNAL;
9400         }
9401         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9402
9403         if (dur_msec < required_end) {
9404                 // FIXME
9405                 LOGD("invalid end pos for pcm extraction");
9406                 return MM_ERROR_INVALID_ARGUMENT;
9407         }
9408
9409         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9410         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9411
9412         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9413                                         1.0,
9414                                         GST_FORMAT_TIME,
9415                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9416                                         GST_SEEK_TYPE_SET, start_nsec,
9417                                         GST_SEEK_TYPE_SET, end_nsec))) {
9418                 LOGE("failed to seek for pcm extraction\n");
9419
9420                 return MM_ERROR_PLAYER_SEEK;
9421         }
9422
9423         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9424
9425         MMPLAYER_FLEAVE();
9426
9427         return MM_ERROR_NONE;
9428 }
9429
9430 int
9431 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9432 {
9433         mm_player_t* player = (mm_player_t*)hplayer;
9434         gint64 pos_nsec = 0;
9435         int ret = MM_ERROR_NONE;
9436         int mute = FALSE;
9437         signed long long start = 0, stop = 0;
9438         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9439         MMPLAYER_FENTER();
9440
9441         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9442         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9443
9444         /* The sound of video is not supported under 0.0 and over 2.0. */
9445         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9446                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9447                         mute = TRUE;
9448         }
9449         _mmplayer_set_mute(hplayer, mute);
9450
9451         if (player->playback_rate == rate)
9452                 return MM_ERROR_NONE;
9453
9454         /* If the position is reached at start potion during fast backward, EOS is posted.
9455          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9456          * */
9457         player->playback_rate = rate;
9458
9459         current_state = MMPLAYER_CURRENT_STATE(player);
9460
9461         if (current_state != MM_PLAYER_STATE_PAUSED)
9462                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9463
9464         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9465
9466         if ((current_state == MM_PLAYER_STATE_PAUSED)
9467                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9468                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9469                 pos_nsec = player->last_position;
9470         }
9471
9472         if (rate >= 0) {
9473                 start = pos_nsec;
9474                 stop = GST_CLOCK_TIME_NONE;
9475         } else {
9476                 start = GST_CLOCK_TIME_NONE;
9477                 stop = pos_nsec;
9478         }
9479
9480         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9481                                 player->playback_rate,
9482                                 GST_FORMAT_TIME,
9483                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9484                                 GST_SEEK_TYPE_SET, start,
9485                                 GST_SEEK_TYPE_SET, stop)) {
9486                 LOGE("failed to set speed playback\n");
9487                 return MM_ERROR_PLAYER_SEEK;
9488         }
9489
9490         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9491
9492         MMPLAYER_FLEAVE();
9493
9494         return MM_ERROR_NONE;;
9495 }
9496
9497 int
9498 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9499 {
9500         mm_player_t* player = (mm_player_t*)hplayer;
9501         int ret = MM_ERROR_NONE;
9502
9503         MMPLAYER_FENTER();
9504
9505         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9506
9507         /* check pipline building state */
9508         __mmplayer_check_pipeline(player);
9509
9510         ret = __gst_set_position(player, format, position, FALSE);
9511
9512         MMPLAYER_FLEAVE();
9513
9514         return ret;
9515 }
9516
9517 int
9518 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9519 {
9520         mm_player_t* player = (mm_player_t*)hplayer;
9521         int ret = MM_ERROR_NONE;
9522
9523         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9524
9525         ret = __gst_get_position(player, format, position);
9526
9527         return ret;
9528 }
9529
9530 int
9531 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9532 {
9533         mm_player_t* player = (mm_player_t*)hplayer;
9534         int ret = MM_ERROR_NONE;
9535
9536         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9537         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9538
9539         *duration = player->duration;
9540         return ret;
9541 }
9542
9543 int
9544 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9545 {
9546         mm_player_t* player = (mm_player_t*)hplayer;
9547         int ret = MM_ERROR_NONE;
9548
9549         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9550
9551         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9552
9553         return ret;
9554 }
9555
9556 int
9557 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9558 {
9559         mm_player_t* player = (mm_player_t*)hplayer;
9560         int ret = MM_ERROR_NONE;
9561
9562         MMPLAYER_FENTER();
9563
9564         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9565
9566         ret = __gst_adjust_subtitle_position(player, format, position);
9567
9568         MMPLAYER_FLEAVE();
9569
9570         return ret;
9571 }
9572
9573 static gboolean
9574 __mmplayer_is_midi_type(gchar* str_caps)
9575 {
9576         if ((g_strrstr(str_caps, "audio/midi")) ||
9577                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9578                 (g_strrstr(str_caps, "application/x-smaf")) ||
9579                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9580                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9581                 (g_strrstr(str_caps, "audio/xmf")) ||
9582                 (g_strrstr(str_caps, "audio/mxmf"))) {
9583                 LOGD("midi\n");
9584                 return TRUE;
9585         }
9586
9587         return FALSE;
9588 }
9589
9590 static gboolean
9591 __mmplayer_is_only_mp3_type(gchar *str_caps)
9592 {
9593         if (g_strrstr(str_caps, "application/x-id3") ||
9594                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9595                 return TRUE;
9596         return FALSE;
9597 }
9598
9599 static void
9600 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9601 {
9602         GstStructure* caps_structure = NULL;
9603         gint samplerate = 0;
9604         gint channels = 0;
9605
9606         MMPLAYER_FENTER();
9607         MMPLAYER_RETURN_IF_FAIL(player && caps);
9608
9609         caps_structure = gst_caps_get_structure(caps, 0);
9610
9611         /* set stream information */
9612         gst_structure_get_int(caps_structure, "rate", &samplerate);
9613         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9614
9615         gst_structure_get_int(caps_structure, "channels", &channels);
9616         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9617
9618         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9619 }
9620
9621 static void
9622 __mmplayer_update_content_type_info(mm_player_t* player)
9623 {
9624         MMPLAYER_FENTER();
9625         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9626
9627         if (__mmplayer_is_midi_type(player->type)) {
9628                 player->bypass_audio_effect = TRUE;
9629         } else if (g_strrstr(player->type, "application/x-hls")) {
9630                 /* If it can't know exact type when it parses uri because of redirection case,
9631                  * it will be fixed by typefinder or when doing autoplugging.
9632                  */
9633                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9634                 if (player->streamer) {
9635                         player->streamer->is_adaptive_streaming = TRUE;
9636                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9637                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9638                 }
9639         } else if (g_strrstr(player->type, "application/dash+xml")) {
9640                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9641                 if (player->streamer) {
9642                         player->streamer->is_adaptive_streaming = TRUE;
9643                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9644                 }
9645         }
9646
9647         LOGD("uri type : %d", player->profile.uri_type);
9648         MMPLAYER_FLEAVE();
9649 }
9650
9651 static void
9652 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9653 GstCaps *caps, gpointer data)
9654 {
9655         mm_player_t* player = (mm_player_t*)data;
9656         GstPad* pad = NULL;
9657
9658         MMPLAYER_FENTER();
9659
9660         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9661
9662         /* store type string */
9663         MMPLAYER_FREEIF(player->type);
9664         player->type = gst_caps_to_string(caps);
9665         if (player->type) {
9666                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9667                                 player, player->type, probability, gst_caps_get_size(caps));
9668         }
9669
9670         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9671                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9672                 LOGE("not support media format\n");
9673
9674                 if (player->msg_posted == FALSE) {
9675                         MMMessageParamType msg_param;
9676                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9677
9678                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9679                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9680
9681                         /* don't post more if one was sent already */
9682                         player->msg_posted = TRUE;
9683                 }
9684                 return;
9685         }
9686
9687         __mmplayer_update_content_type_info(player);
9688
9689         pad = gst_element_get_static_pad(tf, "src");
9690         if (!pad) {
9691                 LOGE("fail to get typefind src pad.\n");
9692                 return;
9693         }
9694
9695         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9696                 gboolean async = FALSE;
9697                 LOGE("failed to autoplug %s\n", player->type);
9698
9699                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9700
9701                 if (async && player->msg_posted == FALSE)
9702                         __mmplayer_handle_missed_plugin(player);
9703
9704                 goto DONE;
9705         }
9706
9707 DONE:
9708         gst_object_unref(GST_OBJECT(pad));
9709
9710         MMPLAYER_FLEAVE();
9711
9712         return;
9713 }
9714
9715 static GstElement *
9716 __mmplayer_create_decodebin(mm_player_t* player)
9717 {
9718         GstElement *decodebin = NULL;
9719
9720         MMPLAYER_FENTER();
9721
9722         /* create decodebin */
9723         decodebin = gst_element_factory_make("decodebin", NULL);
9724
9725         if (!decodebin) {
9726                 LOGE("fail to create decodebin\n");
9727                 goto ERROR;
9728         }
9729
9730         /* raw pad handling signal */
9731         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9732                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9733
9734         /* no-more-pad pad handling signal */
9735         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9736                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9737
9738         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9739                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9740
9741         /* This signal is emitted when a pad for which there is no further possible
9742            decoding is added to the decodebin.*/
9743         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9744                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9745
9746         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9747            before looking for any elements that can handle that stream.*/
9748         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9749                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9750
9751         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9752            before looking for any elements that can handle that stream.*/
9753         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9754                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9755
9756         /* This signal is emitted once decodebin has finished decoding all the data.*/
9757         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9758                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9759
9760         /* This signal is emitted when a element is added to the bin.*/
9761         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9762                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9763
9764 ERROR:
9765         return decodebin;
9766 }
9767
9768 static gboolean
9769 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9770 {
9771         MMPlayerGstElement* mainbin = NULL;
9772         GstElement* decodebin = NULL;
9773         GstElement* queue2 = NULL;
9774         GstPad* sinkpad = NULL;
9775         GstPad* qsrcpad = NULL;
9776         gint64 dur_bytes = 0L;
9777
9778         guint max_buffer_size_bytes = 0;
9779         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9780
9781         MMPLAYER_FENTER();
9782         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9783
9784         mainbin = player->pipeline->mainbin;
9785
9786         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9787                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9788                 LOGD("creating http streaming buffering queue(queue2)\n");
9789
9790                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9791                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9792                 } else {
9793                         queue2 = gst_element_factory_make("queue2", "queue2");
9794                         if (!queue2) {
9795                                 LOGE("failed to create buffering queue element\n");
9796                                 goto ERROR;
9797                         }
9798
9799                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9800                                 LOGE("failed to add buffering queue\n");
9801                                 goto ERROR;
9802                         }
9803
9804                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9805                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9806
9807                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9808                                 LOGE("failed to link buffering queue");
9809                                 goto ERROR;
9810                         }
9811
9812                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9813                                 LOGE("fail to get duration");
9814
9815                         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9816
9817                         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9818
9819                         if (dur_bytes > 0) {
9820                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9821                                         type = MUXED_BUFFER_TYPE_FILE;
9822                                 } else {
9823                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9824                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9825                                 }
9826                         } else {
9827                                 dur_bytes = 0;
9828                         }
9829
9830                         /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9831                          *        skip the pull mode(file or ring buffering) setting. */
9832                         if (!g_strrstr(player->type, "video/mpegts")) {
9833                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9834                                 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9835
9836                                 __mm_player_streaming_set_queue2(player->streamer,
9837                                                                                                 queue2,
9838                                                                                                 FALSE,
9839                                                                                                 max_buffer_size_bytes,
9840                                                                                                 player->ini.http_buffering_time,
9841                                                                                                 1.0,                                /* no meaning */
9842                                                                                                 player->ini.http_buffering_limit,   /* no meaning */
9843                                                                                                 type,
9844                                                                                                 player->http_file_buffering_path,
9845                                                                                                 (guint64)dur_bytes);
9846                         }
9847
9848                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9849                                 LOGE("failed to sync queue2 state with parent\n");
9850                                 goto ERROR;
9851                         }
9852
9853                         srcpad = qsrcpad;
9854
9855                         gst_object_unref(GST_OBJECT(sinkpad));
9856
9857                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9858                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9859                 }
9860         }
9861
9862         /* create decodebin */
9863         decodebin = __mmplayer_create_decodebin(player);
9864
9865         if (!decodebin) {
9866                 LOGE("can not create autoplug element\n");
9867                 goto ERROR;
9868         }
9869
9870         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9871                 LOGE("failed to add decodebin\n");
9872                 goto ERROR;
9873         }
9874
9875         /* to force caps on the decodebin element and avoid reparsing stuff by
9876         * typefind. It also avoids a deadlock in the way typefind activates pads in
9877         * the state change */
9878         g_object_set(decodebin, "sink-caps", caps, NULL);
9879
9880         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9881
9882         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9883                 LOGE("failed to link decodebin\n");
9884                 goto ERROR;
9885         }
9886
9887         gst_object_unref(GST_OBJECT(sinkpad));
9888
9889         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9890         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9891
9892         /* set decodebin property about buffer in streaming playback. *
9893          * in case of HLS/DASH, it does not need to have big buffer   *
9894          * because it is kind of adaptive streaming.                  */
9895         if (!MMPLAYER_IS_HTTP_PD(player) &&
9896             (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9897             gdouble high_percent = 0.0;
9898
9899                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9900                 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9901
9902                 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9903                         GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9904
9905                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9906                                                                                         "high-percent", (gint)high_percent,
9907                                                                                         "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9908                                                                                         "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9909                                                                                         "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9910                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9911         }
9912
9913         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9914                 LOGE("failed to sync decodebin state with parent\n");
9915                 goto ERROR;
9916         }
9917
9918         MMPLAYER_FLEAVE();
9919
9920         return TRUE;
9921
9922 ERROR:
9923
9924         if (sinkpad)
9925                 gst_object_unref(GST_OBJECT(sinkpad));
9926
9927         if (queue2) {
9928                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9929                  * You need to explicitly set elements to the NULL state before
9930                  * dropping the final reference, to allow them to clean up.
9931                  */
9932                 gst_element_set_state(queue2, GST_STATE_NULL);
9933
9934                 /* And, it still has a parent "player".
9935                  * You need to let the parent manage the object instead of unreffing the object directly.
9936                  */
9937                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9938                 gst_object_unref(queue2);
9939                 queue2 = NULL;
9940         }
9941
9942         if (decodebin) {
9943                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9944                  * You need to explicitly set elements to the NULL state before
9945                  * dropping the final reference, to allow them to clean up.
9946                  */
9947                 gst_element_set_state(decodebin, GST_STATE_NULL);
9948
9949                 /* And, it still has a parent "player".
9950                  * You need to let the parent manage the object instead of unreffing the object directly.
9951                  */
9952
9953                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9954                 gst_object_unref(decodebin);
9955                 decodebin = NULL;
9956         }
9957
9958         return FALSE;
9959 }
9960
9961 static int
9962 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9963 {
9964         MMPLAYER_FENTER();
9965
9966         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9967         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9968
9969         LOGD("class : %s, mime : %s \n", factory_class, mime);
9970
9971         /* add missing plugin */
9972         /* NOTE : msl should check missing plugin for image mime type.
9973          * Some motion jpeg clips can have playable audio track.
9974          * So, msl have to play audio after displaying popup written video format not supported.
9975          */
9976         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9977                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9978                         LOGD("not found demuxer\n");
9979                         player->not_found_demuxer = TRUE;
9980                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9981
9982                         goto DONE;
9983                 }
9984         }
9985
9986         if (!g_strrstr(factory_class, "Demuxer")) {
9987                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9988                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9989                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9990
9991                         /* check that clip have multi tracks or not */
9992                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9993                                 LOGD("video plugin is already linked\n");
9994                         } else {
9995                                 LOGW("add VIDEO to missing plugin\n");
9996                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9997                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9998                         }
9999                 } else if (g_str_has_prefix(mime, "audio")) {
10000                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10001                                 LOGD("audio plugin is already linked\n");
10002                         } else {
10003                                 LOGW("add AUDIO to missing plugin\n");
10004                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10005                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10006                         }
10007                 }
10008         }
10009
10010 DONE:
10011         MMPLAYER_FLEAVE();
10012
10013         return MM_ERROR_NONE;
10014 }
10015
10016
10017 static void
10018 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10019 {
10020         mm_player_t* player = (mm_player_t*)data;
10021
10022         MMPLAYER_FENTER();
10023
10024         MMPLAYER_RETURN_IF_FAIL(player);
10025
10026         /* remove fakesink. */
10027         if (!__mmplayer_gst_remove_fakesink(player,
10028                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10029                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10030                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10031                  * source element are not same. To overcome this situation, this function will called
10032                  * several places and several times. Therefore, this is not an error case.
10033                  */
10034                 return;
10035         }
10036
10037         LOGD("[handle: %p] pipeline has completely constructed", player);
10038
10039         if ((player->ini.async_start) &&
10040                 (player->msg_posted == FALSE) &&
10041                 (player->cmd >= MMPLAYER_COMMAND_START))
10042                 __mmplayer_handle_missed_plugin(player);
10043
10044         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10045 }
10046
10047 static gboolean
10048 __mmplayer_verify_next_play_path(mm_player_t *player)
10049 {
10050         MMHandleType attrs = 0;
10051         MMPlayerParseProfile profile;
10052         gint uri_idx = 0, check_cnt = 0;
10053         char *uri = NULL;
10054         gint mode = MM_PLAYER_PD_MODE_NONE;
10055         gint video = 0;
10056         gint count = 0;
10057         gint gapless = 0;
10058         guint num_of_list = 0;
10059         static int profile_tv = -1;
10060
10061         MMPLAYER_FENTER();
10062
10063         LOGD("checking for gapless play");
10064
10065         if (player->pipeline->textbin) {
10066                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10067                 goto ERROR;
10068         }
10069
10070         attrs = MMPLAYER_GET_ATTRS(player);
10071         if (!attrs) {
10072                 LOGE("fail to get attributes.\n");
10073                 goto ERROR;
10074         }
10075
10076         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10077
10078         if (__builtin_expect(profile_tv == -1, 0)) {
10079                 char *profileName;
10080                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10081                 switch (*profileName) {
10082                 case 't':
10083                 case 'T':
10084                         profile_tv = 1;
10085                         break;
10086                 default:
10087                         profile_tv = 0;
10088                 }
10089                 free(profileName);
10090         }
10091         /* gapless playback is not supported in case of video at TV profile. */
10092         if (profile_tv && video) {
10093                 LOGW("not support video gapless playback");
10094                 goto ERROR;
10095         }
10096
10097         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10098                 if (mode == TRUE) {
10099                         LOGW("pd mode\n");
10100                         goto ERROR;
10101                 }
10102         }
10103
10104         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10105                 LOGE("can not get play count\n");
10106
10107         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10108                 LOGE("can not get gapless mode\n");
10109
10110         if (video && !gapless) {
10111                 LOGW("not enabled video gapless playback");
10112                 goto ERROR;
10113         }
10114
10115         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10116                 gapless = 1;
10117
10118         if (!gapless) {
10119                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10120                 goto ERROR;
10121         }
10122
10123         num_of_list = g_list_length(player->uri_info.uri_list);
10124
10125         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10126
10127         if (num_of_list == 0) {
10128                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10129                         LOGE("can not get profile_uri\n");
10130                         goto ERROR;
10131                 }
10132
10133                 if (!uri) {
10134                         LOGE("uri list is empty.\n");
10135                         goto ERROR;
10136                 }
10137
10138                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10139                 LOGD("add original path : %s ", uri);
10140
10141                 num_of_list = 1;
10142                 uri = NULL;
10143         }
10144
10145         uri_idx = player->uri_info.uri_idx;
10146
10147         while (TRUE) {
10148                 check_cnt++;
10149
10150                 if (check_cnt > num_of_list) {
10151                         LOGE("there is no valid uri.");
10152                         goto ERROR;
10153                 }
10154
10155                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10156
10157                 if (uri_idx < num_of_list-1) {
10158                         uri_idx++;
10159                 } else {
10160                         if ((count <= 1) && (count != -1)) {
10161                                 LOGD("no repeat.");
10162                                 goto ERROR;
10163                         } else if (count > 1) {
10164                                 /* decrease play count */
10165                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10166                                 count--;
10167
10168                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10169
10170                                 /* commit attribute */
10171                                 if (mmf_attrs_commit(attrs))
10172                                         LOGE("failed to commit attribute\n");
10173                         }
10174
10175                         /* count < 0 : repeat continually */
10176                         uri_idx = 0;
10177                 }
10178
10179                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10180                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10181
10182                 if (uri == NULL) {
10183                         LOGW("next uri does not exist\n");
10184                         continue;
10185                 }
10186
10187                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10188                         LOGE("failed to parse profile\n");
10189                         continue;
10190                 }
10191
10192                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10193                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10194                         LOGW("uri type is not supported(%d).", profile.uri_type);
10195                         continue;
10196                 }
10197
10198                 break;
10199         }
10200
10201         player->uri_info.uri_idx = uri_idx;
10202         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10203
10204         if (mmf_attrs_commit(player->attrs)) {
10205                 LOGE("failed to commit.\n");
10206                 goto ERROR;
10207         }
10208
10209         LOGD("next uri %s(%d)\n", uri, uri_idx);
10210
10211         return TRUE;
10212
10213 ERROR:
10214
10215         LOGE("unable to play next path. EOS will be posted soon.\n");
10216         return FALSE;
10217 }
10218
10219 static void
10220 __mmplayer_initialize_next_play(mm_player_t *player)
10221 {
10222         int i;
10223
10224         MMPLAYER_FENTER();
10225
10226         player->smooth_streaming = FALSE;
10227         player->videodec_linked = 0;
10228         player->audiodec_linked = 0;
10229         player->videosink_linked = 0;
10230         player->audiosink_linked = 0;
10231         player->textsink_linked = 0;
10232         player->is_external_subtitle_present = FALSE;
10233         player->is_external_subtitle_added_now = FALSE;
10234         player->not_supported_codec = MISSING_PLUGIN_NONE;
10235         player->can_support_codec = FOUND_PLUGIN_NONE;
10236         player->pending_seek.is_pending = FALSE;
10237         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10238         player->pending_seek.pos = 0;
10239         player->msg_posted = FALSE;
10240         player->has_many_types = FALSE;
10241         player->no_more_pad = FALSE;
10242         player->not_found_demuxer = 0;
10243         player->doing_seek = FALSE;
10244         player->max_audio_channels = 0;
10245         player->is_subtitle_force_drop = FALSE;
10246         player->play_subtitle = FALSE;
10247         player->adjust_subtitle_pos = 0;
10248
10249         player->total_bitrate = 0;
10250         player->total_maximum_bitrate = 0;
10251
10252         _mmplayer_track_initialize(player);
10253         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10254
10255         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10256                 player->bitrate[i] = 0;
10257                 player->maximum_bitrate[i] = 0;
10258         }
10259
10260         if (player->v_stream_caps) {
10261                 gst_caps_unref(player->v_stream_caps);
10262                 player->v_stream_caps = NULL;
10263         }
10264
10265         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10266
10267         /* clean found parsers */
10268         if (player->parsers) {
10269                 GList *parsers = player->parsers;
10270                 for (; parsers; parsers = g_list_next(parsers)) {
10271                         gchar *name = parsers->data;
10272                         MMPLAYER_FREEIF(name);
10273                 }
10274                 g_list_free(player->parsers);
10275                 player->parsers = NULL;
10276         }
10277
10278         /* clean found audio decoders */
10279         if (player->audio_decoders) {
10280                 GList *a_dec = player->audio_decoders;
10281                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10282                         gchar *name = a_dec->data;
10283                         MMPLAYER_FREEIF(name);
10284                 }
10285                 g_list_free(player->audio_decoders);
10286                 player->audio_decoders = NULL;
10287         }
10288
10289         MMPLAYER_FLEAVE();
10290 }
10291
10292 static void
10293 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10294 {
10295         MMPlayerGstElement *mainbin = NULL;
10296         MMMessageParamType msg_param = {0,};
10297         GstElement *element = NULL;
10298         MMHandleType attrs = 0;
10299         char *uri = NULL;
10300         enum MainElementID elemId = MMPLAYER_M_NUM;
10301
10302         MMPLAYER_FENTER();
10303
10304         if ((player == NULL) ||
10305                 (player->pipeline == NULL) ||
10306                 (player->pipeline->mainbin == NULL)) {
10307                 LOGE("player is null.\n");
10308                 goto ERROR;
10309         }
10310
10311         mainbin = player->pipeline->mainbin;
10312         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10313
10314         attrs = MMPLAYER_GET_ATTRS(player);
10315         if (!attrs) {
10316                 LOGE("fail to get attributes.\n");
10317                 goto ERROR;
10318         }
10319
10320         /* Initialize Player values */
10321         __mmplayer_initialize_next_play(player);
10322
10323         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10324
10325         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10326                 LOGE("failed to parse profile\n");
10327                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10328                 goto ERROR;
10329         }
10330
10331         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10332                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10333                 LOGE("it's dash or hls. not support.");
10334                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10335                 goto ERROR;
10336         }
10337
10338         /* setup source */
10339         switch (player->profile.uri_type) {
10340         /* file source */
10341         case MM_PLAYER_URI_TYPE_FILE:
10342         {
10343                 LOGD("using filesrc for 'file://' handler.\n");
10344                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10345                         LOGE("failed to get storage info");
10346                         break;
10347                 }
10348
10349                 element = gst_element_factory_make("filesrc", "source");
10350
10351                 if (!element) {
10352                         LOGE("failed to create filesrc\n");
10353                         break;
10354                 }
10355
10356                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10357                 break;
10358         }
10359         case MM_PLAYER_URI_TYPE_URL_HTTP:
10360         {
10361                 gchar *user_agent, *cookies, **cookie_list;
10362                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10363                 user_agent = cookies = NULL;
10364                 cookie_list = NULL;
10365
10366                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10367                 if (!element) {
10368                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10369                         break;
10370                 }
10371                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10372
10373                 /* get attribute */
10374                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10375                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10376
10377                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10378                         LOGD("get timeout from ini\n");
10379                         http_timeout = player->ini.http_timeout;
10380                 }
10381
10382                 /* get attribute */
10383                 SECURE_LOGD("location : %s\n", player->profile.uri);
10384                 SECURE_LOGD("cookies : %s\n", cookies);
10385                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10386                 LOGD("timeout : %d\n", http_timeout);
10387
10388                 /* setting property to streaming source */
10389                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10390                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10391                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10392
10393                 /* parsing cookies */
10394                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10395                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10396                 if (user_agent)
10397                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10398                 break;
10399         }
10400         default:
10401                 LOGE("not support uri type %d\n", player->profile.uri_type);
10402                 break;
10403         }
10404
10405         if (!element) {
10406                 LOGE("no source element was created.\n");
10407                 goto ERROR;
10408         }
10409
10410         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10411                 LOGE("failed to add source element to pipeline\n");
10412                 gst_object_unref(GST_OBJECT(element));
10413                 element = NULL;
10414                 goto ERROR;
10415         }
10416
10417         /* take source element */
10418         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10419         mainbin[MMPLAYER_M_SRC].gst = element;
10420
10421         element = NULL;
10422
10423         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10424                 if (player->streamer == NULL) {
10425                         player->streamer = __mm_player_streaming_create();
10426                         __mm_player_streaming_initialize(player->streamer);
10427                 }
10428
10429                 elemId = MMPLAYER_M_TYPEFIND;
10430                 element = gst_element_factory_make("typefind", "typefinder");
10431                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10432                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10433         } else {
10434                 elemId = MMPLAYER_M_AUTOPLUG;
10435                 element = __mmplayer_create_decodebin(player);
10436         }
10437
10438         /* check autoplug element is OK */
10439         if (!element) {
10440                 LOGE("can not create element(%d)\n", elemId);
10441                 goto ERROR;
10442         }
10443
10444         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10445                 LOGE("failed to add sinkbin to pipeline\n");
10446                 gst_object_unref(GST_OBJECT(element));
10447                 element = NULL;
10448                 goto ERROR;
10449         }
10450
10451         mainbin[elemId].id = elemId;
10452         mainbin[elemId].gst = element;
10453
10454         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10455                 LOGE("Failed to link src - autoplug(or typefind)\n");
10456                 goto ERROR;
10457         }
10458
10459         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10460                 LOGE("Failed to change state of src element\n");
10461                 goto ERROR;
10462         }
10463
10464         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10465                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10466                         LOGE("Failed to change state of decodebin\n");
10467                         goto ERROR;
10468                 }
10469         } else {
10470                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10471                         LOGE("Failed to change state of src element\n");
10472                         goto ERROR;
10473                 }
10474         }
10475
10476         player->gapless.stream_changed = TRUE;
10477         player->gapless.running = TRUE;
10478         MMPLAYER_FLEAVE();
10479         return;
10480
10481 ERROR:
10482         if (player) {
10483                 MMPLAYER_PLAYBACK_UNLOCK(player);
10484
10485                 if (!player->msg_posted) {
10486                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10487                         player->msg_posted = TRUE;
10488                 }
10489         }
10490         return;
10491 }
10492
10493 static gboolean
10494 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10495 {
10496         mm_player_selector_t *selector = &player->selector[type];
10497         MMPlayerGstElement *sinkbin = NULL;
10498         enum MainElementID selectorId = MMPLAYER_M_NUM;
10499         enum MainElementID sinkId = MMPLAYER_M_NUM;
10500         GstPad *srcpad = NULL;
10501         GstPad *sinkpad = NULL;
10502         gboolean send_notice = FALSE;
10503
10504         MMPLAYER_FENTER();
10505         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10506
10507         LOGD("type %d", type);
10508
10509         switch (type) {
10510         case MM_PLAYER_TRACK_TYPE_AUDIO:
10511                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10512                 sinkId = MMPLAYER_A_BIN;
10513                 sinkbin = player->pipeline->audiobin;
10514                 break;
10515         case MM_PLAYER_TRACK_TYPE_VIDEO:
10516                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10517                 sinkId = MMPLAYER_V_BIN;
10518                 sinkbin = player->pipeline->videobin;
10519                 send_notice = TRUE;
10520                 break;
10521         case MM_PLAYER_TRACK_TYPE_TEXT:
10522                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10523                 sinkId = MMPLAYER_T_BIN;
10524                 sinkbin = player->pipeline->textbin;
10525                 break;
10526         default:
10527                 LOGE("requested type is not supportable");
10528                 return FALSE;
10529                 break;
10530         }
10531
10532         if (player->pipeline->mainbin[selectorId].gst) {
10533                 gint n;
10534
10535                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10536
10537                 if (selector->event_probe_id != 0)
10538                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10539                 selector->event_probe_id = 0;
10540
10541                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10542                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10543
10544                         if (srcpad && sinkpad) {
10545                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10546                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10547                                 gst_pad_unlink(srcpad, sinkpad);
10548
10549                                 /* send custom event to sink pad to handle it at video sink */
10550                                 if (send_notice) {
10551                                         LOGD("send custom event to sinkpad");
10552                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10553                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10554                                         gst_pad_send_event(sinkpad, event);
10555                                 }
10556                         }
10557
10558                         gst_object_unref(sinkpad);
10559                         sinkpad = NULL;
10560                 }
10561                 gst_object_unref(srcpad);
10562                 srcpad = NULL;
10563
10564                 LOGD("selector release");
10565
10566                 /* release and unref requests pad from the selector */
10567                 for (n = 0; n < selector->channels->len; n++) {
10568                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10569                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10570                 }
10571                 g_ptr_array_set_size(selector->channels, 0);
10572
10573                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10574                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10575
10576                 player->pipeline->mainbin[selectorId].gst = NULL;
10577                 selector = NULL;
10578         }
10579
10580         return TRUE;
10581 }
10582
10583 static void
10584 __mmplayer_deactivate_old_path(mm_player_t *player)
10585 {
10586         MMPLAYER_FENTER();
10587         MMPLAYER_RETURN_IF_FAIL(player);
10588
10589         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10590                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10591                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10592                 LOGE("deactivate selector error");
10593                 goto ERROR;
10594         }
10595
10596         _mmplayer_track_destroy(player);
10597         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10598
10599         if (player->streamer) {
10600                 __mm_player_streaming_deinitialize(player->streamer);
10601                 __mm_player_streaming_destroy(player->streamer);
10602                 player->streamer = NULL;
10603         }
10604
10605         MMPLAYER_PLAYBACK_LOCK(player);
10606         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10607
10608         MMPLAYER_FLEAVE();
10609         return;
10610
10611 ERROR:
10612
10613         if (!player->msg_posted) {
10614                 MMMessageParamType msg = {0,};
10615
10616                 /*post error*/
10617                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10618                 LOGE("next_uri_play> deactivate error");
10619
10620                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10621                 player->msg_posted = TRUE;
10622         }
10623         return;
10624 }
10625
10626 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10627 {
10628         int result = MM_ERROR_NONE;
10629         mm_player_t* player = (mm_player_t*) hplayer;
10630         MMPLAYER_FENTER();
10631
10632         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10633
10634         if (file_path) {
10635                 player->http_file_buffering_path = (gchar*)file_path;
10636                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10637         }
10638         MMPLAYER_FLEAVE();
10639         return result;
10640 }
10641
10642 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10643 {
10644         int result = MM_ERROR_NONE;
10645         mm_player_t* player = (mm_player_t*) hplayer;
10646         MMPLAYER_FENTER();
10647
10648         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10649
10650         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10651         if (mmf_attrs_commit(player->attrs)) {
10652                 LOGE("failed to commit the original uri.\n");
10653                 result = MM_ERROR_PLAYER_INTERNAL;
10654         } else {
10655                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10656                         LOGE("failed to add the original uri in the uri list.\n");
10657         }
10658
10659         MMPLAYER_FLEAVE();
10660         return result;
10661 }
10662
10663 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10664 {
10665         mm_player_t* player = (mm_player_t*) hplayer;
10666         guint num_of_list = 0;
10667
10668         MMPLAYER_FENTER();
10669
10670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10671         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10672
10673         if (player->pipeline && player->pipeline->textbin) {
10674                 LOGE("subtitle path is enabled.\n");
10675                 return MM_ERROR_PLAYER_INVALID_STATE;
10676         }
10677
10678         num_of_list = g_list_length(player->uri_info.uri_list);
10679
10680         if (is_first_path == TRUE) {
10681                 if (num_of_list == 0) {
10682                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10683                         LOGD("add original path : %s", uri);
10684                 } else {
10685                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10686                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10687
10688                         LOGD("change original path : %s", uri);
10689                 }
10690         } else {
10691                 MMHandleType attrs = 0;
10692                 attrs = MMPLAYER_GET_ATTRS(player);
10693
10694                 if (num_of_list == 0) {
10695                         char *original_uri = NULL;
10696
10697                         if (attrs) {
10698                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10699
10700                                 if (!original_uri) {
10701                                         LOGE("there is no original uri.");
10702                                         return MM_ERROR_PLAYER_INVALID_STATE;
10703                                 }
10704
10705                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10706                                 player->uri_info.uri_idx = 0;
10707
10708                                 LOGD("add original path at first : %s(%d)", original_uri);
10709                         }
10710                 }
10711
10712                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10713                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10714         }
10715
10716         MMPLAYER_FLEAVE();
10717         return MM_ERROR_NONE;
10718 }
10719
10720 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10721 {
10722         mm_player_t* player = (mm_player_t*) hplayer;
10723         char *next_uri = NULL;
10724         guint num_of_list = 0;
10725
10726         MMPLAYER_FENTER();
10727         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10728
10729         num_of_list = g_list_length(player->uri_info.uri_list);
10730
10731         if (num_of_list > 0) {
10732                 gint uri_idx = player->uri_info.uri_idx;
10733
10734                 if (uri_idx < num_of_list-1)
10735                         uri_idx++;
10736                 else
10737                         uri_idx = 0;
10738
10739                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10740                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10741
10742                 *uri = g_strdup(next_uri);
10743         }
10744
10745         MMPLAYER_FLEAVE();
10746         return MM_ERROR_NONE;
10747 }
10748
10749 static void
10750 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10751 GstCaps *caps, gpointer data)
10752 {
10753         mm_player_t* player = (mm_player_t*)data;
10754         const gchar* klass = NULL;
10755         const gchar* mime = NULL;
10756         gchar* caps_str = NULL;
10757
10758         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10759         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10760         caps_str = gst_caps_to_string(caps);
10761
10762         LOGW("unknown type of caps : %s from %s",
10763                                         caps_str, GST_ELEMENT_NAME(elem));
10764
10765         MMPLAYER_FREEIF(caps_str);
10766
10767         /* There is no available codec. */
10768         __mmplayer_check_not_supported_codec(player, klass, mime);
10769 }
10770
10771 static gboolean
10772 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10773 GstCaps * caps,  gpointer data)
10774 {
10775         mm_player_t* player = (mm_player_t*)data;
10776         const char* mime = NULL;
10777         gboolean ret = TRUE;
10778
10779         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10780         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10781
10782         if (g_str_has_prefix(mime, "audio")) {
10783                 GstStructure* caps_structure = NULL;
10784                 gint samplerate = 0;
10785                 gint channels = 0;
10786                 gchar *caps_str = NULL;
10787
10788                 caps_structure = gst_caps_get_structure(caps, 0);
10789                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10790                 gst_structure_get_int(caps_structure, "channels", &channels);
10791
10792                 if ((channels > 0 && samplerate == 0)) {
10793                         LOGD("exclude audio...");
10794                         ret = FALSE;
10795                 }
10796
10797                 caps_str = gst_caps_to_string(caps);
10798                 /* set it directly because not sent by TAG */
10799                 if (g_strrstr(caps_str, "mobile-xmf"))
10800                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10801                 MMPLAYER_FREEIF(caps_str);
10802         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10803                 MMMessageParamType msg_param;
10804                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10805                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10806                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10807                 LOGD("video file is not supported on this device");
10808                 ret = FALSE;
10809         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10810                 LOGD("already video linked");
10811                 ret = FALSE;
10812         } else {
10813                 LOGD("found new stream");
10814         }
10815
10816         return ret;
10817 }
10818
10819 static int
10820 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10821 {
10822         int ret = MM_ERROR_NONE;
10823         int idx = 0;
10824         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10825
10826         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10827                 GstStructure* str = NULL;
10828                 gint channels = 0;
10829                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10830
10831                 LOGD("audio codec type: %d", codec_type);
10832                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10833                         /* sw codec will be skipped */
10834                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10835                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10836                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10837                                         ret = MM_ERROR_PLAYER_INTERNAL;
10838                                         goto DONE;
10839                                 }
10840                         }
10841                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10842                         /* hw codec will be skipped */
10843                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10844                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10845                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10846                                 ret = MM_ERROR_PLAYER_INTERNAL;
10847                                 goto DONE;
10848                         }
10849                 }
10850
10851                 str = gst_caps_get_structure(caps, 0);
10852                 if (str) {
10853                         gst_structure_get_int(str, "channels", &channels);
10854
10855                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10856                         if (player->max_audio_channels < channels)
10857                                 player->max_audio_channels = channels;
10858                 }
10859                 /* set stream information */
10860                 if (!player->audiodec_linked)
10861                         __mmplayer_set_audio_attrs(player, caps);
10862
10863                 /* update codec info */
10864                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10865                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10866                 player->audiodec_linked = 1;
10867
10868         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10869
10870                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10871
10872                 LOGD("video codec type: %d", codec_type);
10873                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10874                         /* sw codec is skipped */
10875                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10876                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10877                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10878                                         ret = MM_ERROR_PLAYER_INTERNAL;
10879                                         goto DONE;
10880                                 }
10881                         }
10882                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10883                         /* hw codec is skipped */
10884                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10885                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10886                                 ret = MM_ERROR_PLAYER_INTERNAL;
10887                                 goto DONE;
10888                         }
10889                 }
10890
10891                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10892                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10893
10894                         /* mark video decoder for acquire */
10895                         if (player->video_decoder_resource == NULL) {
10896                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10897                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10898                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10899                                                 &player->video_decoder_resource)
10900                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10901                                         LOGE("could not mark video_decoder resource for acquire");
10902                                         ret = MM_ERROR_PLAYER_INTERNAL;
10903                                         goto DONE;
10904                                 }
10905                         } else {
10906                                 LOGW("video decoder resource is already acquired, skip it.");
10907                                 ret = MM_ERROR_PLAYER_INTERNAL;
10908                                 goto DONE;
10909                         }
10910
10911                         player->interrupted_by_resource = FALSE;
10912                         /* acquire resources for video playing */
10913                         if (mm_resource_manager_commit(player->resource_manager)
10914                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10915                                 LOGE("could not acquire resources for video decoding\n");
10916                                 ret = MM_ERROR_PLAYER_INTERNAL;
10917                                 goto DONE;
10918                         }
10919                 }
10920
10921                 /* update codec info */
10922                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10923                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10924                 player->videodec_linked = 1;
10925         }
10926
10927 DONE:
10928         return ret;
10929 }
10930
10931 static gint
10932 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10933 GstCaps* caps, GstElementFactory* factory, gpointer data)
10934 {
10935         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10936          We are defining our own and will be removed when it actually exposed */
10937         typedef enum {
10938                 GST_AUTOPLUG_SELECT_TRY,
10939                 GST_AUTOPLUG_SELECT_EXPOSE,
10940                 GST_AUTOPLUG_SELECT_SKIP
10941         } GstAutoplugSelectResult;
10942
10943         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10944         mm_player_t* player = (mm_player_t*)data;
10945
10946         gchar* factory_name = NULL;
10947         gchar* caps_str = NULL;
10948         const gchar* klass = NULL;
10949         gint idx = 0;
10950
10951         factory_name = GST_OBJECT_NAME(factory);
10952         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10953         caps_str = gst_caps_to_string(caps);
10954
10955         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10956
10957         /* store type string */
10958         if (player->type == NULL) {
10959                 player->type = gst_caps_to_string(caps);
10960                 __mmplayer_update_content_type_info(player);
10961         }
10962
10963         /* filtering exclude keyword */
10964         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10965                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10966                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10967                                         factory_name, player->ini.exclude_element_keyword[idx]);
10968
10969                         result = GST_AUTOPLUG_SELECT_SKIP;
10970                         goto DONE;
10971                 }
10972         }
10973
10974         /* exclude webm format */
10975         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10976          * because webm format is not supportable.
10977          * If webm is disabled in "autoplug-continue", there is no state change
10978          * failure or error because the decodebin will expose the pad directly.
10979          * It make MSL invoke _prepare_async_callback.
10980          * So, we need to disable webm format in "autoplug-select" */
10981         if (caps_str && strstr(caps_str, "webm")) {
10982                 LOGW("webm is not supported");
10983                 result = GST_AUTOPLUG_SELECT_SKIP;
10984                 goto DONE;
10985         }
10986
10987         /* check factory class for filtering */
10988         /* NOTE : msl don't need to use image plugins.
10989          * So, those plugins should be skipped for error handling.
10990          */
10991         if (g_strrstr(klass, "Codec/Decoder/Image")) {
10992                 LOGD("skipping [%s] by not required\n", factory_name);
10993                 result = GST_AUTOPLUG_SELECT_SKIP;
10994                 goto DONE;
10995         }
10996
10997         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10998                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10999                 // TO CHECK : subtitle if needed, add subparse exception.
11000                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11001                 result = GST_AUTOPLUG_SELECT_SKIP;
11002                 goto DONE;
11003         }
11004
11005         if (g_strrstr(factory_name, "mpegpsdemux")) {
11006                 LOGD("skipping PS container - not support\n");
11007                 result = GST_AUTOPLUG_SELECT_SKIP;
11008                 goto DONE;
11009         }
11010
11011         if (g_strrstr(factory_name, "mssdemux"))
11012                 player->smooth_streaming = TRUE;
11013
11014         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11015                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11016                 gint stype = 0;
11017                 gint width = 0;
11018                 GstStructure *str = NULL;
11019                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11020
11021                 /* don't make video because of not required */
11022                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11023                         (player->set_mode.media_packet_video_stream == FALSE)) {
11024                         LOGD("no video because it's not required. -> return expose");
11025                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11026                         goto DONE;
11027                 }
11028
11029                 /* get w/h for omx state-tune */
11030                 /* FIXME: deprecated? */
11031                 str = gst_caps_get_structure(caps, 0);
11032                 gst_structure_get_int(str, "width", &width);
11033
11034                 if (width != 0) {
11035                         if (player->v_stream_caps) {
11036                                 gst_caps_unref(player->v_stream_caps);
11037                                 player->v_stream_caps = NULL;
11038                         }
11039
11040                         player->v_stream_caps = gst_caps_copy(caps);
11041                         LOGD("take caps for video state tune");
11042                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11043                 }
11044         }
11045
11046         if (g_strrstr(klass, "Codec/Decoder")) {
11047                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11048                         LOGD("skipping %s codec", factory_name);
11049                         result = GST_AUTOPLUG_SELECT_SKIP;
11050                         goto DONE;
11051                 }
11052         }
11053
11054 DONE:
11055         MMPLAYER_FREEIF(caps_str);
11056
11057         return result;
11058 }
11059
11060 static void
11061 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11062 gpointer data)
11063 {
11064         //mm_player_t* player = (mm_player_t*)data;
11065         GstCaps* caps = NULL;
11066
11067         LOGD("[Decodebin2] pad-removed signal\n");
11068
11069         caps = gst_pad_query_caps(new_pad, NULL);
11070         if (caps) {
11071                 gchar* caps_str = NULL;
11072                 caps_str = gst_caps_to_string(caps);
11073
11074                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11075
11076                 MMPLAYER_FREEIF(caps_str);
11077                 gst_caps_unref(caps);
11078         }
11079 }
11080
11081 static void
11082 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11083 {
11084         mm_player_t* player = (mm_player_t*)data;
11085         GstIterator *iter = NULL;
11086         GValue item = { 0, };
11087         GstPad *pad = NULL;
11088         gboolean done = FALSE;
11089         gboolean is_all_drained = TRUE;
11090
11091         MMPLAYER_FENTER();
11092         MMPLAYER_RETURN_IF_FAIL(player);
11093
11094         LOGD("__mmplayer_gst_decode_drained");
11095
11096         if (player->use_deinterleave == TRUE) {
11097                 LOGD("group playing mode.");
11098                 return;
11099         }
11100
11101         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11102                 LOGW("Fail to get cmd lock");
11103                 return;
11104         }
11105
11106         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11107                 !__mmplayer_verify_next_play_path(player)) {
11108                 LOGD("decoding is finished.");
11109                 __mmplayer_reset_gapless_state(player);
11110                 MMPLAYER_CMD_UNLOCK(player);
11111                 return;
11112         }
11113
11114         player->gapless.reconfigure = TRUE;
11115
11116         /* check decodebin src pads whether they received EOS or not */
11117         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11118
11119         while (!done) {
11120                 switch (gst_iterator_next(iter, &item)) {
11121                 case GST_ITERATOR_OK:
11122                         pad = g_value_get_object(&item);
11123                         if (pad && !GST_PAD_IS_EOS(pad)) {
11124                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11125                                 is_all_drained = FALSE;
11126                                 break;
11127                         }
11128                         g_value_reset(&item);
11129                         break;
11130                 case GST_ITERATOR_RESYNC:
11131                         gst_iterator_resync(iter);
11132                         break;
11133                 case GST_ITERATOR_ERROR:
11134                 case GST_ITERATOR_DONE:
11135                         done = TRUE;
11136                         break;
11137                 }
11138         }
11139         g_value_unset(&item);
11140         gst_iterator_free(iter);
11141
11142         if (!is_all_drained) {
11143                 LOGD("Wait util the all pads get EOS.");
11144                 MMPLAYER_CMD_UNLOCK(player);
11145                 MMPLAYER_FLEAVE();
11146                 return;
11147         }
11148
11149         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11150         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11151
11152         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11153         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11154         __mmplayer_deactivate_old_path(player);
11155         MMPLAYER_CMD_UNLOCK(player);
11156
11157         MMPLAYER_FLEAVE();
11158 }
11159
11160 static void
11161 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11162 {
11163         mm_player_t* player = (mm_player_t*)data;
11164         const gchar* klass = NULL;
11165         gchar* factory_name = NULL;
11166
11167         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11168         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11169
11170         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11171
11172         if (__mmplayer_add_dump_buffer_probe(player, element))
11173                 LOGD("add buffer probe");
11174
11175         //<-
11176         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11177                 gchar* selected = NULL;
11178                 selected = g_strdup(GST_ELEMENT_NAME(element));
11179                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11180         }
11181         //-> temp code
11182
11183         if (g_strrstr(klass, "Parser")) {
11184                 gchar* selected = NULL;
11185
11186                 selected = g_strdup(factory_name);
11187                 player->parsers = g_list_append(player->parsers, selected);
11188         }
11189
11190         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11191                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11192                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11193
11194                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11195                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11196
11197                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11198                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11199                                                 "max-video-width", player->adaptive_info.limit.width,
11200                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11201
11202         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11203                 /* FIXIT : first value will be overwritten if there's more
11204                  * than 1 demuxer/parser
11205                  */
11206
11207                 //LOGD("plugged element is demuxer. take it\n");
11208                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11209                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11210
11211                 /*Added for multi audio support */ // Q. del?
11212                 if (g_strrstr(klass, "Demux")) {
11213                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11214                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11215                 }
11216         }
11217
11218         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11219                 int surface_type = 0;
11220
11221                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11222         }
11223
11224         // to support trust-zone only
11225         if (g_strrstr(factory_name, "asfdemux")) {
11226                 LOGD("set file-location %s\n", player->profile.uri);
11227                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11228
11229                 if (player->video_hub_download_mode == TRUE)
11230                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11231         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11232                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11233                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11234         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11235                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11236                         (__mmplayer_is_only_mp3_type(player->type))) {
11237                         LOGD("[mpegaudioparse] set streaming pull mode.");
11238                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11239                 }
11240         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11241                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11242         }
11243
11244         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11245                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11246                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11247
11248                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11249                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11250
11251                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11252                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11253                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11254                         (MMPLAYER_IS_DASH_STREAMING(player)))) {
11255                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11256                         __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11257                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11258                 }
11259
11260         }
11261
11262         return;
11263 }
11264
11265 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11266 {
11267         MMPLAYER_FENTER();
11268         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11269
11270         if (MMPLAYER_IS_STREAMING(player))
11271                 return FALSE;
11272
11273         /* This callback can be set to music player only. */
11274         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11275                 LOGW("audio callback is not supported for video");
11276                 return FALSE;
11277         }
11278
11279         if (player->audio_stream_cb) {
11280                 GstPad *pad = NULL;
11281
11282                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11283
11284                 if (!pad) {
11285                         LOGE("failed to get sink pad from audiosink to probe data\n");
11286                         return FALSE;
11287                 }
11288                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11289                         __mmplayer_audio_stream_probe, player, NULL);
11290
11291                 gst_object_unref(pad);
11292
11293                 pad = NULL;
11294         } else {
11295                 LOGE("There is no audio callback to configure.\n");
11296                 return FALSE;
11297         }
11298
11299         MMPLAYER_FLEAVE();
11300
11301         return TRUE;
11302 }
11303
11304 static void
11305 __mmplayer_release_misc(mm_player_t* player)
11306 {
11307         int i;
11308         bool cur_mode = player->set_mode.rich_audio;
11309         MMPLAYER_FENTER();
11310
11311         MMPLAYER_RETURN_IF_FAIL(player);
11312
11313         player->video_stream_cb = NULL;
11314         player->video_stream_cb_user_param = NULL;
11315         player->video_stream_prerolled = FALSE;
11316
11317         player->audio_stream_cb = NULL;
11318         player->audio_stream_render_cb_ex = NULL;
11319         player->audio_stream_cb_user_param = NULL;
11320         player->audio_stream_sink_sync = false;
11321
11322         player->video_stream_changed_cb = NULL;
11323         player->video_stream_changed_cb_user_param = NULL;
11324
11325         player->audio_stream_changed_cb = NULL;
11326         player->audio_stream_changed_cb_user_param = NULL;
11327
11328         player->sent_bos = FALSE;
11329         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11330
11331         player->doing_seek = FALSE;
11332
11333         player->total_bitrate = 0;
11334         player->total_maximum_bitrate = 0;
11335
11336         player->not_found_demuxer = 0;
11337
11338         player->last_position = 0;
11339         player->duration = 0;
11340         player->http_content_size = 0;
11341         player->not_supported_codec = MISSING_PLUGIN_NONE;
11342         player->can_support_codec = FOUND_PLUGIN_NONE;
11343         player->pending_seek.is_pending = FALSE;
11344         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11345         player->pending_seek.pos = 0;
11346         player->msg_posted = FALSE;
11347         player->has_many_types = FALSE;
11348         player->max_audio_channels = 0;
11349         player->video_share_api_delta = 0;
11350         player->video_share_clock_delta = 0;
11351         player->is_subtitle_force_drop = FALSE;
11352         player->play_subtitle = FALSE;
11353         player->adjust_subtitle_pos = 0;
11354         player->last_multiwin_status = FALSE;
11355         player->has_closed_caption = FALSE;
11356         player->set_mode.media_packet_video_stream = FALSE;
11357         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11358         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11359         /* recover mode */
11360         player->set_mode.rich_audio = cur_mode;
11361
11362         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11363                 player->bitrate[i] = 0;
11364                 player->maximum_bitrate[i] = 0;
11365         }
11366
11367         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11368
11369         /* remove media stream cb(appsrc cb) */
11370         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11371                 player->media_stream_buffer_status_cb[i] = NULL;
11372                 player->media_stream_seek_data_cb[i] = NULL;
11373                 player->buffer_cb_user_param[i] = NULL;
11374                 player->seek_cb_user_param[i] = NULL;
11375         }
11376         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11377
11378         /* free memory related to audio effect */
11379         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11380
11381         if (player->adaptive_info.var_list) {
11382                 g_list_free_full(player->adaptive_info.var_list, g_free);
11383                 player->adaptive_info.var_list = NULL;
11384         }
11385
11386         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11387         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11388         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11389
11390         /* Reset video360 settings to their defaults in case if the pipeline is to be
11391          * re-created.
11392          * */
11393         player->video360_metadata.is_spherical = -1;
11394         player->is_openal_plugin_used = FALSE;
11395
11396         player->is_content_spherical = FALSE;
11397         player->is_video360_enabled = TRUE;
11398         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11399         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11400         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11401         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11402         player->video360_zoom = 1.0f;
11403         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11404         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11405
11406         player->sound.rg_enable = false;
11407
11408         MMPLAYER_FLEAVE();
11409 }
11410
11411 static void
11412 __mmplayer_release_misc_post(mm_player_t* player)
11413 {
11414         char *original_uri = NULL;
11415         MMPLAYER_FENTER();
11416
11417         /* player->pipeline is already released before. */
11418
11419         MMPLAYER_RETURN_IF_FAIL(player);
11420
11421         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11422
11423         /* clean found parsers */
11424         if (player->parsers) {
11425                 GList *parsers = player->parsers;
11426                 for (; parsers; parsers = g_list_next(parsers)) {
11427                         gchar *name = parsers->data;
11428                         MMPLAYER_FREEIF(name);
11429                 }
11430                 g_list_free(player->parsers);
11431                 player->parsers = NULL;
11432         }
11433
11434         /* clean found audio decoders */
11435         if (player->audio_decoders) {
11436                 GList *a_dec = player->audio_decoders;
11437                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11438                         gchar *name = a_dec->data;
11439                         MMPLAYER_FREEIF(name);
11440                 }
11441                 g_list_free(player->audio_decoders);
11442                 player->audio_decoders = NULL;
11443         }
11444
11445         /* clean the uri list except original uri */
11446         if (player->uri_info.uri_list) {
11447                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11448
11449                 if (player->attrs) {
11450                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11451                         LOGD("restore original uri = %s\n", original_uri);
11452
11453                         if (mmf_attrs_commit(player->attrs))
11454                                 LOGE("failed to commit the original uri.\n");
11455                 }
11456
11457                 GList *uri_list = player->uri_info.uri_list;
11458                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11459                         gchar *uri = uri_list->data;
11460                         MMPLAYER_FREEIF(uri);
11461                 }
11462                 g_list_free(player->uri_info.uri_list);
11463                 player->uri_info.uri_list = NULL;
11464         }
11465
11466         /* clear the audio stream buffer list */
11467         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11468
11469         /* clear the video stream bo list */
11470         __mmplayer_video_stream_destroy_bo_list(player);
11471         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11472
11473         if (player->profile.input_mem.buf) {
11474                 free(player->profile.input_mem.buf);
11475                 player->profile.input_mem.buf = NULL;
11476         }
11477         player->profile.input_mem.len = 0;
11478         player->profile.input_mem.offset = 0;
11479
11480         player->uri_info.uri_idx = 0;
11481         MMPLAYER_FLEAVE();
11482 }
11483
11484 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11485 {
11486         GstElement *element = NULL;
11487         GstPad *sinkpad;
11488
11489         LOGD("creating %s to plug\n", name);
11490
11491         element = gst_element_factory_make(name, NULL);
11492         if (!element) {
11493                 LOGE("failed to create queue\n");
11494                 return NULL;
11495         }
11496
11497         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11498                 LOGE("failed to set state READY to %s\n", name);
11499                 gst_object_unref(element);
11500                 return NULL;
11501         }
11502
11503         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11504                 LOGE("failed to add %s\n", name);
11505                 gst_object_unref(element);
11506                 return NULL;
11507         }
11508
11509         sinkpad = gst_element_get_static_pad(element, "sink");
11510
11511         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11512                 LOGE("failed to link %s\n", name);
11513                 gst_object_unref(sinkpad);
11514                 gst_object_unref(element);
11515                 return NULL;
11516         }
11517
11518         LOGD("linked %s to pipeline successfully\n", name);
11519
11520         gst_object_unref(sinkpad);
11521
11522         return element;
11523 }
11524
11525 gboolean
11526 __mmplayer_check_subtitle(mm_player_t* player)
11527 {
11528         MMHandleType attrs = 0;
11529         char *subtitle_uri = NULL;
11530
11531         MMPLAYER_FENTER();
11532
11533         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11534
11535         /* get subtitle attribute */
11536         attrs = MMPLAYER_GET_ATTRS(player);
11537         if (!attrs)
11538                 return FALSE;
11539
11540         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11541         if (!subtitle_uri || !strlen(subtitle_uri))
11542                 return FALSE;
11543
11544         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11545         player->is_external_subtitle_present = TRUE;
11546
11547         MMPLAYER_FLEAVE();
11548
11549         return TRUE;
11550 }
11551
11552 static gboolean
11553 __mmplayer_can_extract_pcm(mm_player_t* player)
11554 {
11555         MMHandleType attrs = 0;
11556         gboolean sound_extraction = FALSE;
11557
11558         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11559
11560         attrs = MMPLAYER_GET_ATTRS(player);
11561         if (!attrs) {
11562                 LOGE("fail to get attributes.");
11563                 return FALSE;
11564         }
11565
11566         /* get sound_extraction property */
11567         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11568
11569         if (!sound_extraction) {
11570                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11571                 return FALSE;
11572         }
11573
11574         return TRUE;
11575 }
11576
11577 static gboolean
11578 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11579 {
11580         LOGD("\n");
11581         MMMessageParamType msg_param;
11582         gchar *msg_src_element = NULL;
11583         GstStructure *s = NULL;
11584         guint error_id = 0;
11585         gchar *error_string = NULL;
11586
11587         MMPLAYER_FENTER();
11588
11589         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11590         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11591
11592         s = gst_structure_copy(gst_message_get_structure(message));
11593
11594
11595         if (!gst_structure_get_uint(s, "error_id", &error_id))
11596                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11597
11598         switch (error_id) {
11599         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11600                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11601                 break;
11602         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11603                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11604                 break;
11605         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11606                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11607                 break;
11608         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11609                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11610                 break;
11611         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11612                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11613                 break;
11614         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11615                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11616                 break;
11617         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11618                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11619                 break;
11620         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11621                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11622                 break;
11623         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11624                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11625                 break;
11626         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11627                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11628                 break;
11629         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11630                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11631                 break;
11632         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11633                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11634                 break;
11635         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11636                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11637                 break;
11638         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11639                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11640                 break;
11641         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11642                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11643                 break;
11644         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11645                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11646                 break;
11647         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11648                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11649                 break;
11650         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11651                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11652                 break;
11653         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11654                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11655                 break;
11656         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11657                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11658                 break;
11659         case MMPLAYER_STREAMING_ERROR_GONE:
11660                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11661                 break;
11662         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11663                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11664                 break;
11665         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11666                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11667                 break;
11668         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11669                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11670                 break;
11671         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11672                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11673                 break;
11674         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11675                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11676                 break;
11677         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11678                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11679                 break;
11680         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11681                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11682                 break;
11683         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11684                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11685                 break;
11686         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11687                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11688                 break;
11689         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11690                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11691                 break;
11692         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11693                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11694                 break;
11695         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11696                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11697                 break;
11698         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11699                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11700                 break;
11701         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11702                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11703                 break;
11704         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11705                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11706                 break;
11707         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11708                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11709                 break;
11710         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11711                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11712                 break;
11713         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11714                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11715                 break;
11716         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11717                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11718                 break;
11719         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11720                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11721                 break;
11722         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11723                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11724                 break;
11725         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11726                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11727                 break;
11728         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11729                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11730                 break;
11731         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11732                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11733                 break;
11734         default:
11735                 {
11736                         gst_structure_free(s);
11737                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11738                 }
11739         }
11740
11741         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11742         if (error_string)
11743                 msg_param.data = (void *) error_string;
11744
11745         if (message->src) {
11746                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11747
11748                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11749                         msg_src_element, msg_param.code, (char*)msg_param.data);
11750         }
11751
11752         /* post error to application */
11753         if (!player->msg_posted) {
11754                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11755
11756                 /* don't post more if one was sent already */
11757                 player->msg_posted = TRUE;
11758         } else
11759                 LOGD("skip error post because it's sent already.\n");
11760
11761         gst_structure_free(s);
11762         MMPLAYER_FLEAVE();
11763         g_free(error_string);
11764
11765         return TRUE;
11766
11767 }
11768
11769 static void
11770 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11771 {
11772         MMPLAYER_RETURN_IF_FAIL(player);
11773
11774         /* post now if delay is zero */
11775         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11776                 LOGD("eos delay is zero. posting EOS now\n");
11777                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11778
11779                 if (player->set_mode.pcm_extraction)
11780                         __mmplayer_cancel_eos_timer(player);
11781
11782                 return;
11783         }
11784
11785         /* cancel if existing */
11786         __mmplayer_cancel_eos_timer(player);
11787
11788         /* init new timeout */
11789         /* NOTE : consider give high priority to this timer */
11790         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11791
11792         player->eos_timer = g_timeout_add(delay_in_ms,
11793                 __mmplayer_eos_timer_cb, player);
11794
11795         player->context.global_default = g_main_context_default();
11796         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11797
11798         /* check timer is valid. if not, send EOS now */
11799         if (player->eos_timer == 0) {
11800                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11801                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11802         }
11803 }
11804
11805 static void
11806 __mmplayer_cancel_eos_timer(mm_player_t* player)
11807 {
11808         MMPLAYER_RETURN_IF_FAIL(player);
11809
11810         if (player->eos_timer) {
11811                 LOGD("cancel eos timer");
11812                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11813                 player->eos_timer = 0;
11814         }
11815
11816         return;
11817 }
11818
11819 static gboolean
11820 __mmplayer_eos_timer_cb(gpointer u_data)
11821 {
11822         mm_player_t* player = NULL;
11823         MMHandleType attrs = 0;
11824         int count = 0;
11825
11826         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11827
11828         player = (mm_player_t*) u_data;
11829         attrs = MMPLAYER_GET_ATTRS(player);
11830
11831         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11832
11833         if (count == -1) {
11834                 gint ret_value = 0;
11835                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11836                 if (ret_value != MM_ERROR_NONE)
11837                         LOGE("seeking to 0 failed in repeat play");
11838         } else {
11839                 /* posting eos */
11840                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11841         }
11842
11843         /* we are returning FALSE as we need only one posting */
11844         return FALSE;
11845 }
11846
11847 /* sending event to one of sinkelements */
11848 static gboolean
11849 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11850 {
11851         GstEvent * event2 = NULL;
11852         GList *sinks = NULL;
11853         gboolean res = FALSE;
11854         MMPLAYER_FENTER();
11855
11856         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11857         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11858
11859         /* While adding subtitles in live feeds seek is getting called.
11860            Adding defensive check in framework layer.*/
11861         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11862                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11863                         LOGE("Should not send seek event during live playback");
11864                         return TRUE;
11865                 }
11866         }
11867
11868         if (player->play_subtitle)
11869                 event2 = gst_event_copy((const GstEvent *)event);
11870
11871         sinks = player->sink_elements;
11872         while (sinks) {
11873                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11874
11875                 if (GST_IS_ELEMENT(sink)) {
11876                         /* keep ref to the event */
11877                         gst_event_ref(event);
11878
11879                         if ((res = gst_element_send_event(sink, event))) {
11880                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11881                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11882
11883                                 /* rtsp case, asyn_done is not called after seek during pause state */
11884                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11885                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11886                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11887                                                         LOGD("RTSP seek completed, after pause state..\n");
11888                                                         player->doing_seek = FALSE;
11889                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11890                                                 }
11891
11892                                         }
11893                                 }
11894
11895                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11896                                         sinks = g_list_next(sinks);
11897                                         continue;
11898                                 } else {
11899                                         break;
11900                                 }
11901                         }
11902
11903                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11904                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11905                 }
11906
11907                 sinks = g_list_next(sinks);
11908         }
11909
11910         /* Note : Textbin is not linked to the video or audio bin.
11911          * It needs to send the event to the text sink seperatelly.
11912          */
11913          if (player->play_subtitle && player->pipeline) {
11914                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11915
11916                 if (GST_IS_ELEMENT(text_sink)) {
11917                         /* keep ref to the event */
11918                         gst_event_ref(event2);
11919
11920                         if ((res = gst_element_send_event(text_sink, event2)))
11921                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11922                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11923                         else
11924                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11925                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11926
11927                         gst_event_unref(event2);
11928                 }
11929          }
11930
11931         gst_event_unref(event);
11932
11933         MMPLAYER_FLEAVE();
11934
11935         return res;
11936 }
11937
11938 static void
11939 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11940 {
11941         MMPLAYER_FENTER();
11942
11943         MMPLAYER_RETURN_IF_FAIL(player);
11944         MMPLAYER_RETURN_IF_FAIL(sink);
11945
11946         player->sink_elements =
11947                 g_list_append(player->sink_elements, sink);
11948
11949         MMPLAYER_FLEAVE();
11950 }
11951
11952 static void
11953 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11954 {
11955         MMPLAYER_FENTER();
11956
11957         MMPLAYER_RETURN_IF_FAIL(player);
11958         MMPLAYER_RETURN_IF_FAIL(sink);
11959
11960         player->sink_elements =
11961                         g_list_remove(player->sink_elements, sink);
11962
11963         MMPLAYER_FLEAVE();
11964 }
11965
11966 static gboolean
11967 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11968                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11969                         gint64 cur, GstSeekType stop_type, gint64 stop)
11970 {
11971         GstEvent* event = NULL;
11972         gboolean result = FALSE;
11973
11974         MMPLAYER_FENTER();
11975
11976         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11977
11978         if (player->pipeline && player->pipeline->textbin)
11979                 __mmplayer_drop_subtitle(player, FALSE);
11980
11981         event = gst_event_new_seek(rate, format, flags, cur_type,
11982                 cur, stop_type, stop);
11983
11984         result = __gst_send_event_to_sink(player, event);
11985
11986         MMPLAYER_FLEAVE();
11987
11988         return result;
11989 }
11990
11991 /* NOTE : be careful with calling this api. please refer to below glib comment
11992  * glib comment : Note that there is a bug in GObject that makes this function much
11993  * less useful than it might seem otherwise. Once gobject is disposed, the callback
11994  * will no longer be called, but, the signal handler is not currently disconnected.
11995  * If the instance is itself being freed at the same time than this doesn't matter,
11996  * since the signal will automatically be removed, but if instance persists,
11997  * then the signal handler will leak. You should not remove the signal yourself
11998  * because in a future versions of GObject, the handler will automatically be
11999  * disconnected.
12000  *
12001  * It's possible to work around this problem in a way that will continue to work
12002  * with future versions of GObject by checking that the signal handler is still
12003  * connected before disconnected it:
12004  *
12005  *  if (g_signal_handler_is_connected(instance, id))
12006  *    g_signal_handler_disconnect(instance, id);
12007  */
12008 static void
12009 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12010 {
12011         GList* sig_list = NULL;
12012         MMPlayerSignalItem* item = NULL;
12013
12014         MMPLAYER_FENTER();
12015
12016         MMPLAYER_RETURN_IF_FAIL(player);
12017
12018         LOGD("release signals type : %d", type);
12019
12020         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12021                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12022                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12023                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12024                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12025                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12026                 return;
12027         }
12028
12029         sig_list = player->signals[type];
12030
12031         for (; sig_list; sig_list = sig_list->next) {
12032                 item = sig_list->data;
12033
12034                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12035                         if (g_signal_handler_is_connected(item->obj, item->sig))
12036                                 g_signal_handler_disconnect(item->obj, item->sig);
12037                 }
12038
12039                 MMPLAYER_FREEIF(item);
12040         }
12041
12042         g_list_free(player->signals[type]);
12043         player->signals[type] = NULL;
12044
12045         MMPLAYER_FLEAVE();
12046
12047         return;
12048 }
12049
12050 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12051 {
12052         mm_player_t* player = 0;
12053         int prev_display_surface_type = 0;
12054         void *prev_display_overlay = NULL;
12055         const gchar *klass = NULL;
12056         gchar *cur_videosink_name = NULL;
12057         int ret = 0;
12058         int i = 0;
12059         int num_of_dec = 2; /* DEC1, DEC2 */
12060
12061         MMPLAYER_FENTER();
12062
12063         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12064         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12065
12066         player = MM_PLAYER_CAST(handle);
12067
12068         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12069                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12070                 MMPLAYER_FLEAVE();
12071                 return MM_ERROR_INVALID_ARGUMENT;
12072         }
12073
12074         /* load previous attributes */
12075         if (player->attrs) {
12076                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12077                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12078                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12079                 if (prev_display_surface_type == surface_type) {
12080                         LOGD("incoming display surface type is same as previous one, do nothing..");
12081                         MMPLAYER_FLEAVE();
12082                         return MM_ERROR_NONE;
12083                 }
12084         } else {
12085                 LOGE("failed to load attributes");
12086                 MMPLAYER_FLEAVE();
12087                 return MM_ERROR_PLAYER_INTERNAL;
12088         }
12089
12090         /* check videosink element is created */
12091         if (!player->pipeline || !player->pipeline->videobin ||
12092                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12093                 LOGD("videosink element is not yet ready");
12094
12095                 /* videobin is not created yet, so we just set attributes related to display surface */
12096                 LOGD("store display attribute for given surface type(%d)", surface_type);
12097                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12098                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12099                 if (mmf_attrs_commit(player->attrs)) {
12100                         LOGE("failed to commit attribute");
12101                         MMPLAYER_FLEAVE();
12102                         return MM_ERROR_PLAYER_INTERNAL;
12103                 }
12104                 MMPLAYER_FLEAVE();
12105                 return MM_ERROR_NONE;
12106         } else {
12107                 /* get player command status */
12108                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12109                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12110                         MMPLAYER_FLEAVE();
12111                         return MM_ERROR_PLAYER_INVALID_STATE;
12112                 }
12113
12114                 /* surface change */
12115                 for (i = 0 ; i < num_of_dec ; i++) {
12116                         if (player->pipeline->mainbin &&
12117                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12118                                 GstElementFactory *decfactory;
12119                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12120
12121                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12122                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12123                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12124                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12125                                                 if (ret) {
12126                                                         goto ERROR_CASE;
12127                                                 } else {
12128                                                         LOGW("success to changing display surface(%d)", surface_type);
12129                                                         MMPLAYER_FLEAVE();
12130                                                         return MM_ERROR_NONE;
12131                                                 }
12132                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12133                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12134                                                 if (ret) {
12135                                                         goto ERROR_CASE;
12136                                                 } else {
12137                                                         LOGW("success to changing display surface(%d)", surface_type);
12138                                                         MMPLAYER_FLEAVE();
12139                                                         return MM_ERROR_NONE;
12140                                                 }
12141                                         } else {
12142                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12143                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12144                                                 goto ERROR_CASE;
12145                                         }
12146                                 }
12147                         }
12148                 }
12149         }
12150
12151 ERROR_CASE:
12152         /* rollback to previous attributes */
12153         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12154         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12155         if (mmf_attrs_commit(player->attrs)) {
12156                 LOGE("failed to commit attributes to rollback");
12157                 MMPLAYER_FLEAVE();
12158                 return MM_ERROR_PLAYER_INTERNAL;
12159         }
12160         MMPLAYER_FLEAVE();
12161         return ret;
12162 }
12163
12164 /* NOTE : It does not support some use cases, eg using colorspace converter */
12165 int
12166 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12167 {
12168         GstPad *src_pad_dec = NULL;
12169         GstPad *sink_pad_videosink = NULL;
12170         GstPad *sink_pad_videobin = NULL;
12171         GstClock *clock = NULL;
12172         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12173         int ret = MM_ERROR_NONE;
12174         gboolean is_audiobin_created = TRUE;
12175
12176         MMPLAYER_FENTER();
12177
12178         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12179         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12180         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12181
12182         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12183         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12184
12185         /* get information whether if audiobin is created */
12186         if (!player->pipeline->audiobin ||
12187                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12188                 LOGW("audiobin is null, this video content may not have audio data");
12189                 is_audiobin_created = FALSE;
12190         }
12191
12192         /* get current state of player */
12193         previous_state = MMPLAYER_CURRENT_STATE(player);
12194         LOGD("previous state(%d)", previous_state);
12195
12196
12197         /* get src pad of decoder and block it */
12198         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12199         if (!src_pad_dec) {
12200                 LOGE("failed to get src pad from decode in mainbin");
12201                 return MM_ERROR_PLAYER_INTERNAL;
12202         }
12203
12204         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12205                 LOGW("trying to block pad(video)");
12206 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12207                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12208                         NULL, NULL, NULL);
12209                 {
12210                         LOGE("failed to set block pad(video)");
12211                         return MM_ERROR_PLAYER_INTERNAL;
12212                 }
12213                 LOGW("pad is blocked(video)");
12214         } else {
12215                 /* no data flows, so no need to do pad_block */
12216                 if (player->doing_seek)
12217                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12218
12219                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12220         }
12221
12222         /* remove pad */
12223         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12224                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12225                 LOGE("failed to remove previous ghost_pad for videobin");
12226                 return MM_ERROR_PLAYER_INTERNAL;
12227         }
12228
12229         /* change state of videobin to NULL */
12230         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12231         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12232         if (ret != GST_STATE_CHANGE_SUCCESS) {
12233                 LOGE("failed to change state of videobin to NULL");
12234                 return MM_ERROR_PLAYER_INTERNAL;
12235         }
12236
12237         /* unlink between decoder and videobin and remove previous videosink from videobin */
12238         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12239         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12240                 LOGE("failed to remove former videosink from videobin");
12241                 return MM_ERROR_PLAYER_INTERNAL;
12242         }
12243
12244         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12245
12246         /* create a new videosink and add it to videobin */
12247         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12248         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12249                 LOGE("failed to create videosink element\n");
12250                 MMPLAYER_FLEAVE();
12251                 return MM_ERROR_PLAYER_INTERNAL;
12252         }
12253         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12254         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12255         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12256
12257         /* save attributes */
12258         if (player->attrs) {
12259                 /* set a new display surface type */
12260                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12261                 /* set a new diplay overlay */
12262                 switch (surface_type) {
12263                 case MM_DISPLAY_SURFACE_OVERLAY:
12264                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12265                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12266                         break;
12267                 default:
12268                         LOGE("invalid type(%d) for changing display surface", surface_type);
12269                         MMPLAYER_FLEAVE();
12270                         return MM_ERROR_INVALID_ARGUMENT;
12271                 }
12272                 if (mmf_attrs_commit(player->attrs)) {
12273                         LOGE("failed to commit");
12274                         MMPLAYER_FLEAVE();
12275                         return MM_ERROR_PLAYER_INTERNAL;
12276                 }
12277         } else {
12278                 LOGE("player->attrs is null, failed to save attributes");
12279                 MMPLAYER_FLEAVE();
12280                 return MM_ERROR_PLAYER_INTERNAL;
12281         }
12282
12283         /* update video param */
12284         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12285                 LOGE("failed to update video param");
12286                 return MM_ERROR_PLAYER_INTERNAL;
12287         }
12288
12289         /* change state of videobin to READY */
12290         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12291         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12292         if (ret != GST_STATE_CHANGE_SUCCESS) {
12293                 LOGE("failed to change state of videobin to READY");
12294                 return MM_ERROR_PLAYER_INTERNAL;
12295         }
12296
12297         /* change ghostpad */
12298         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12299         if (!sink_pad_videosink) {
12300                 LOGE("failed to get sink pad from videosink element");
12301                 return MM_ERROR_PLAYER_INTERNAL;
12302         }
12303         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12304         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12305                 LOGE("failed to set active to ghost_pad");
12306                 return MM_ERROR_PLAYER_INTERNAL;
12307         }
12308         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12309                 LOGE("failed to change ghostpad for videobin");
12310                 return MM_ERROR_PLAYER_INTERNAL;
12311         }
12312         gst_object_unref(sink_pad_videosink);
12313
12314         /* link decoder with videobin */
12315         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12316         if (!sink_pad_videobin) {
12317                 LOGE("failed to get sink pad from videobin");
12318                 return MM_ERROR_PLAYER_INTERNAL;
12319         }
12320         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12321                 LOGE("failed to link");
12322                 return MM_ERROR_PLAYER_INTERNAL;
12323         }
12324         gst_object_unref(sink_pad_videobin);
12325
12326         /* clock setting for a new videosink plugin */
12327         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12328                         so we set it from audiosink plugin or pipeline(system clock) */
12329         if (!is_audiobin_created) {
12330                 LOGW("audiobin is not created, get clock from pipeline..");
12331                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12332         } else {
12333                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12334         }
12335         if (clock) {
12336                 GstClockTime now;
12337                 GstClockTime base_time;
12338                 LOGD("set the clock to videosink");
12339                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12340                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12341                 if (clock) {
12342                         LOGD("got clock of videosink");
12343                         now = gst_clock_get_time(clock);
12344                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12345                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12346                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12347                 } else {
12348                         LOGE("failed to get clock of videosink after setting clock");
12349                         return MM_ERROR_PLAYER_INTERNAL;
12350                 }
12351         } else
12352                 LOGW("failed to get clock, maybe it is the time before first playing");
12353
12354         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12355                 /* change state of videobin to PAUSED */
12356                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12357                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12358                 if (ret != GST_STATE_CHANGE_FAILURE) {
12359                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12360                 } else {
12361                         LOGE("failed to change state of videobin to PLAYING");
12362                         return MM_ERROR_PLAYER_INTERNAL;
12363                 }
12364
12365                 /* release blocked and unref src pad of video decoder */
12366                 #if 0
12367                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12368                         LOGE("failed to set pad blocked FALSE(video)");
12369                         return MM_ERROR_PLAYER_INTERNAL;
12370                 }
12371                 #endif
12372                 LOGW("pad is unblocked(video)");
12373         } else {
12374                 if (player->doing_seek)
12375                         LOGW("not completed seek(%d)", player->doing_seek);
12376                 /* change state of videobin to PAUSED */
12377                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12378                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12379                 if (ret != GST_STATE_CHANGE_FAILURE) {
12380                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12381                 } else {
12382                         LOGE("failed to change state of videobin to PLAYING");
12383                         return MM_ERROR_PLAYER_INTERNAL;
12384                 }
12385
12386                 /* already skipped pad block */
12387                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12388         }
12389
12390         /* do get/set position for new videosink plugin */
12391         {
12392                 gint64 position = 0;
12393
12394                 LOGD("do get/set position for new videosink plugin");
12395                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12396                         LOGE("failed to get position");
12397                         return MM_ERROR_PLAYER_INTERNAL;
12398                 }
12399 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12400                 /* accurate seek */
12401                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12402                         LOGE("failed to set position");
12403                         return MM_ERROR_PLAYER_INTERNAL;
12404                 }
12405 #else
12406                 /* key unit seek */
12407                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12408                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12409                                                         GST_SEEK_TYPE_SET, position,
12410                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12411                 if (!ret) {
12412                         LOGE("failed to set position");
12413                         return MM_ERROR_PLAYER_INTERNAL;
12414                 }
12415 #endif
12416         }
12417
12418         if (src_pad_dec)
12419                 gst_object_unref(src_pad_dec);
12420         LOGD("success to change sink");
12421
12422         MMPLAYER_FLEAVE();
12423
12424         return MM_ERROR_NONE;
12425 }
12426
12427
12428 /* Note : if silent is true, then subtitle would not be displayed. :*/
12429 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12430 {
12431         mm_player_t* player = (mm_player_t*) hplayer;
12432
12433         MMPLAYER_FENTER();
12434
12435         /* check player handle */
12436         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12437
12438         player->set_mode.subtitle_off = silent;
12439
12440         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12441
12442         MMPLAYER_FLEAVE();
12443
12444         return MM_ERROR_NONE;
12445 }
12446
12447 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12448 {
12449         MMPlayerGstElement* mainbin = NULL;
12450         MMPlayerGstElement* textbin = NULL;
12451         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12452         GstState current_state = GST_STATE_VOID_PENDING;
12453         GstState element_state = GST_STATE_VOID_PENDING;
12454         GstState element_pending_state = GST_STATE_VOID_PENDING;
12455         gint64 time = 0;
12456         GstEvent *event = NULL;
12457         int result = MM_ERROR_NONE;
12458
12459         GstClock *curr_clock = NULL;
12460         GstClockTime base_time, start_time, curr_time;
12461
12462
12463         MMPLAYER_FENTER();
12464
12465         /* check player handle */
12466         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12467                                                                 player->pipeline &&
12468                                                                 player->pipeline->mainbin &&
12469                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12470
12471         mainbin = player->pipeline->mainbin;
12472         textbin = player->pipeline->textbin;
12473
12474         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12475
12476         // sync clock with current pipeline
12477         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12478         curr_time = gst_clock_get_time(curr_clock);
12479
12480         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12481         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12482
12483         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12484                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12485
12486         if (current_state > GST_STATE_READY) {
12487                 // sync state with current pipeline
12488                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12489                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12490                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12491
12492                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12493                 if (GST_STATE_CHANGE_FAILURE == ret) {
12494                         LOGE("fail to state change.\n");
12495                         result = MM_ERROR_PLAYER_INTERNAL;
12496                         goto ERROR;
12497                 }
12498         }
12499
12500         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12501         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12502
12503         if (curr_clock) {
12504                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12505                 gst_object_unref(curr_clock);
12506         }
12507
12508         // seek to current position
12509         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12510                 result = MM_ERROR_PLAYER_INVALID_STATE;
12511                 LOGE("gst_element_query_position failed, invalid state\n");
12512                 goto ERROR;
12513         }
12514
12515         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12516         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);
12517         if (event) {
12518                 __gst_send_event_to_sink(player, event);
12519         } else {
12520                 result = MM_ERROR_PLAYER_INTERNAL;
12521                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12522                 goto ERROR;
12523         }
12524
12525         /* sync state with current pipeline */
12526         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12527         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12528         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12529
12530         return MM_ERROR_NONE;
12531
12532 ERROR:
12533         /* release text pipeline resource */
12534         player->textsink_linked = 0;
12535
12536         /* release signal */
12537         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12538
12539         /* release textbin with it's childs */
12540         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12541         MMPLAYER_FREEIF(player->pipeline->textbin);
12542         player->pipeline->textbin = NULL;
12543
12544         /* release subtitle elem */
12545         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12546         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12547
12548         return result;
12549 }
12550
12551 static int
12552 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12553 {
12554         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12555         GstState current_state = GST_STATE_VOID_PENDING;
12556
12557         MMHandleType attrs = 0;
12558         MMPlayerGstElement* mainbin = NULL;
12559         MMPlayerGstElement* textbin = NULL;
12560
12561         gchar* subtitle_uri = NULL;
12562         int result = MM_ERROR_NONE;
12563         const gchar *charset = NULL;
12564
12565         MMPLAYER_FENTER();
12566
12567         /* check player handle */
12568         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12569                                                                 player->pipeline &&
12570                                                                 player->pipeline->mainbin &&
12571                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12572         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12573
12574         mainbin = player->pipeline->mainbin;
12575         textbin = player->pipeline->textbin;
12576
12577         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12578         if (current_state < GST_STATE_READY) {
12579                 result = MM_ERROR_PLAYER_INVALID_STATE;
12580                 LOGE("Pipeline is not in proper state\n");
12581                 goto EXIT;
12582         }
12583
12584         attrs = MMPLAYER_GET_ATTRS(player);
12585         if (!attrs) {
12586                 LOGE("cannot get content attribute\n");
12587                 result = MM_ERROR_PLAYER_INTERNAL;
12588                 goto EXIT;
12589         }
12590
12591         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12592         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12593                 LOGE("subtitle uri is not proper filepath\n");
12594                 result = MM_ERROR_PLAYER_INVALID_URI;
12595                 goto EXIT;
12596         }
12597
12598         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12599                 LOGE("failed to get storage info of subtitle path");
12600                 result = MM_ERROR_PLAYER_INVALID_URI;
12601                 goto EXIT;
12602         }
12603
12604         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12605         LOGD("new subtitle file path is [%s]\n", filepath);
12606
12607         if (!strcmp(filepath, subtitle_uri)) {
12608                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12609                 goto EXIT;
12610         } else {
12611                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12612                 if (mmf_attrs_commit(player->attrs)) {
12613                         LOGE("failed to commit.\n");
12614                         goto EXIT;
12615                 }
12616         }
12617
12618         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12619         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12620         player->subtitle_language_list = NULL;
12621         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12622
12623         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12624         if (ret != GST_STATE_CHANGE_SUCCESS) {
12625                 LOGE("failed to change state of textbin to READY");
12626                 result = MM_ERROR_PLAYER_INTERNAL;
12627                 goto EXIT;
12628         }
12629
12630         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12631         if (ret != GST_STATE_CHANGE_SUCCESS) {
12632                 LOGE("failed to change state of subparse to READY");
12633                 result = MM_ERROR_PLAYER_INTERNAL;
12634                 goto EXIT;
12635         }
12636
12637         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12638         if (ret != GST_STATE_CHANGE_SUCCESS) {
12639                 LOGE("failed to change state of filesrc to READY");
12640                 result = MM_ERROR_PLAYER_INTERNAL;
12641                 goto EXIT;
12642         }
12643
12644         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12645
12646         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12647
12648         charset = util_get_charset(filepath);
12649         if (charset) {
12650                 LOGD("detected charset is %s\n", charset);
12651                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12652         }
12653
12654         result = _mmplayer_sync_subtitle_pipeline(player);
12655
12656 EXIT:
12657         MMPLAYER_FLEAVE();
12658         return result;
12659 }
12660
12661 /* API to switch between external subtitles */
12662 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12663 {
12664         int result = MM_ERROR_NONE;
12665         mm_player_t* player = (mm_player_t*)hplayer;
12666         char *path = NULL;
12667
12668         MMPLAYER_FENTER();
12669
12670         /* check player handle */
12671         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12672
12673         /* filepath can be null in idle state */
12674         if (filepath) {
12675                 /* check file path */
12676                 if ((path = strstr(filepath, "file://")))
12677                         result = util_exist_file_path(path + 7);
12678                 else
12679                         result = util_exist_file_path(filepath);
12680
12681                 if (result != MM_ERROR_NONE) {
12682                         LOGE("invalid subtitle path 0x%X", result);
12683                         return result; /* file not found or permission denied */
12684                 }
12685         }
12686
12687         if (!player->pipeline) {
12688                 /* IDLE state */
12689                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12690                 if (mmf_attrs_commit(player->attrs)) {
12691                         LOGE("failed to commit");       /* subtitle path will not be created */
12692                         return MM_ERROR_PLAYER_INTERNAL;
12693                 }
12694         } else {
12695                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12696                 /* check filepath */
12697                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12698
12699                 if (!__mmplayer_check_subtitle(player)) {
12700                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12701                         if (mmf_attrs_commit(player->attrs)) {
12702                                 LOGE("failed to commit");
12703                                 return MM_ERROR_PLAYER_INTERNAL;
12704                         }
12705
12706                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12707                                 LOGE("fail to create text pipeline");
12708                                 return MM_ERROR_PLAYER_INTERNAL;
12709                         }
12710
12711                         result = _mmplayer_sync_subtitle_pipeline(player);
12712                 } else {
12713                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12714                 }
12715
12716                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12717                 player->is_external_subtitle_added_now = TRUE;
12718
12719                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12720                 if (!player->subtitle_language_list) {
12721                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12722                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12723                                 LOGW("subtitle language list is not updated yet");
12724                 }
12725                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12726         }
12727
12728         MMPLAYER_FLEAVE();
12729         return result;
12730 }
12731
12732 static int
12733 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12734 {
12735         int result = MM_ERROR_NONE;
12736         gchar* change_pad_name = NULL;
12737         GstPad* sinkpad = NULL;
12738         MMPlayerGstElement* mainbin = NULL;
12739         enum MainElementID elemId = MMPLAYER_M_NUM;
12740         GstCaps* caps = NULL;
12741         gint total_track_num = 0;
12742
12743         MMPLAYER_FENTER();
12744
12745         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12746                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12747
12748         LOGD("Change Track(%d) to %d\n", type, index);
12749
12750         mainbin = player->pipeline->mainbin;
12751
12752         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12753                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12754         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12755                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12756         } else {
12757                 /* Changing Video Track is not supported. */
12758                 LOGE("Track Type Error\n");
12759                 goto EXIT;
12760         }
12761
12762         if (mainbin[elemId].gst == NULL) {
12763                 result = MM_ERROR_PLAYER_NO_OP;
12764                 LOGD("Req track doesn't exist\n");
12765                 goto EXIT;
12766         }
12767
12768         total_track_num = player->selector[type].total_track_num;
12769         if (total_track_num <= 0) {
12770                 result = MM_ERROR_PLAYER_NO_OP;
12771                 LOGD("Language list is not available \n");
12772                 goto EXIT;
12773         }
12774
12775         if ((index < 0) || (index >= total_track_num)) {
12776                 result = MM_ERROR_INVALID_ARGUMENT;
12777                 LOGD("Not a proper index : %d \n", index);
12778                 goto EXIT;
12779         }
12780
12781         /*To get the new pad from the selector*/
12782         change_pad_name = g_strdup_printf("sink_%u", index);
12783         if (change_pad_name == NULL) {
12784                 result = MM_ERROR_PLAYER_INTERNAL;
12785                 LOGD("Pad does not exists\n");
12786                 goto EXIT;
12787         }
12788
12789         LOGD("new active pad name: %s\n", change_pad_name);
12790
12791         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12792         if (sinkpad == NULL) {
12793                 LOGD("sinkpad is NULL");
12794                 result = MM_ERROR_PLAYER_INTERNAL;
12795                 goto EXIT;
12796         }
12797
12798         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12799         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12800
12801         caps = gst_pad_get_current_caps(sinkpad);
12802         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12803
12804         if (sinkpad)
12805                 gst_object_unref(sinkpad);
12806
12807         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12808                 __mmplayer_set_audio_attrs(player, caps);
12809
12810 EXIT:
12811
12812         MMPLAYER_FREEIF(change_pad_name);
12813         return result;
12814 }
12815
12816 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12817 {
12818         int result = MM_ERROR_NONE;
12819         mm_player_t* player = NULL;
12820         MMPlayerGstElement* mainbin = NULL;
12821
12822         gint current_active_index = 0;
12823
12824         GstState current_state = GST_STATE_VOID_PENDING;
12825         GstEvent* event = NULL;
12826         gint64 time = 0;
12827
12828         MMPLAYER_FENTER();
12829
12830         player = (mm_player_t*)hplayer;
12831         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12832
12833         if (!player->pipeline) {
12834                 LOGE("Track %d pre setting -> %d\n", type, index);
12835
12836                 player->selector[type].active_pad_index = index;
12837                 goto EXIT;
12838         }
12839
12840         mainbin = player->pipeline->mainbin;
12841
12842         current_active_index = player->selector[type].active_pad_index;
12843
12844         /*If index is same as running index no need to change the pad*/
12845         if (current_active_index == index)
12846                 goto EXIT;
12847
12848         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12849                 result = MM_ERROR_PLAYER_INVALID_STATE;
12850                 goto EXIT;
12851         }
12852
12853         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12854         if (current_state < GST_STATE_PAUSED) {
12855                 result = MM_ERROR_PLAYER_INVALID_STATE;
12856                 LOGW("Pipeline not in porper state\n");
12857                 goto EXIT;
12858         }
12859
12860         result = __mmplayer_change_selector_pad(player, type, index);
12861         if (result != MM_ERROR_NONE) {
12862                 LOGE("change selector pad error\n");
12863                 goto EXIT;
12864         }
12865
12866         player->selector[type].active_pad_index = index;
12867
12868         if (current_state == GST_STATE_PLAYING) {
12869                 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);
12870                 if (event) {
12871                         __gst_send_event_to_sink(player, event);
12872                 } else {
12873                         result = MM_ERROR_PLAYER_INTERNAL;
12874                         goto EXIT;
12875                 }
12876         }
12877
12878 EXIT:
12879         return result;
12880 }
12881
12882 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12883 {
12884         mm_player_t* player = (mm_player_t*) hplayer;
12885
12886         MMPLAYER_FENTER();
12887
12888         /* check player handle */
12889         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12890
12891         *silent = player->set_mode.subtitle_off;
12892
12893         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12894
12895         MMPLAYER_FLEAVE();
12896
12897         return MM_ERROR_NONE;
12898 }
12899
12900 gboolean
12901 __is_ms_buff_src(mm_player_t* player)
12902 {
12903         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12904
12905         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12906 }
12907
12908 gboolean
12909 __has_suffix(mm_player_t* player, const gchar* suffix)
12910 {
12911         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12912         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12913
12914         gboolean ret = FALSE;
12915         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12916         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12917
12918         if (g_str_has_suffix(player->profile.uri, suffix))
12919                 ret = TRUE;
12920
12921         MMPLAYER_FREEIF(t_url);
12922         MMPLAYER_FREEIF(t_suffix);
12923
12924         return ret;
12925 }
12926
12927 int
12928 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12929 {
12930         mm_player_t* player = (mm_player_t*) hplayer;
12931
12932         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12933
12934         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12935                 MMPLAYER_PRINT_STATE(player);
12936                 LOGE("wrong-state : can't set the download mode to parse");
12937                 return MM_ERROR_PLAYER_INVALID_STATE;
12938         }
12939
12940         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12941         player->video_hub_download_mode = mode;
12942
12943         return MM_ERROR_NONE;
12944 }
12945
12946 int
12947 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12948 {
12949         mm_player_t* player = (mm_player_t*) hplayer;
12950
12951         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12952
12953         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12954         player->sync_handler = enable;
12955
12956         return MM_ERROR_NONE;
12957 }
12958
12959 int
12960 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12961                                                                                 gint64 video_time, gint64 media_clock, gint64 audio_time)
12962 {
12963         mm_player_t* player = (mm_player_t*) hplayer;
12964         MMPlayerGstElement* mainbin = NULL;
12965         GstClockTime start_time_audio = 0, start_time_video = 0;
12966         GstClockTimeDiff base_time = 0, new_base_time = 0;
12967         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12968         gint64 api_delta = 0;
12969         gint64 position = 0, position_delta = 0;
12970         gint64 adj_base_time = 0;
12971         GstClock *curr_clock = NULL;
12972         GstClockTime curr_time = 0;
12973         gboolean query_ret = TRUE;
12974         int result = MM_ERROR_NONE;
12975
12976         MMPLAYER_FENTER();
12977
12978         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12979         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12980         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12981
12982         /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12983                                                                         clock, clock_delta, video_time, media_clock, audio_time); */
12984
12985         if ((video_time < 0) || (player->doing_seek)) {
12986                 LOGD("skip setting master clock. %lld", video_time);
12987                 goto EXIT;
12988         }
12989
12990         mainbin = player->pipeline->mainbin;
12991
12992         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12993         curr_time = gst_clock_get_time(curr_clock);
12994
12995         current_state = MMPLAYER_CURRENT_STATE(player);
12996
12997         if (current_state == MM_PLAYER_STATE_PLAYING)
12998                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12999
13000         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13001                 (!query_ret)) {
13002                 position = player->last_position;
13003                 LOGD("query fail. %"G_GINT64_FORMAT, position);
13004         }
13005
13006         clock *= GST_USECOND;
13007         clock_delta *= GST_USECOND;
13008
13009         api_delta = clock - curr_time;
13010         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13011                 player->video_share_api_delta = api_delta;
13012         else
13013                 clock_delta += (api_delta - player->video_share_api_delta);
13014
13015         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13016                 player->video_share_clock_delta = (gint64)clock_delta;
13017
13018                 position_delta = (position/GST_USECOND) - video_time;
13019                 position_delta *= GST_USECOND;
13020
13021                 adj_base_time = position_delta;
13022                 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13023
13024         } else {
13025                 gint64 new_play_time = 0;
13026                 gint64 network_delay = 0;
13027
13028                 video_time *= GST_USECOND;
13029
13030                 network_delay = clock_delta - player->video_share_clock_delta;
13031                 new_play_time = video_time + network_delay;
13032
13033                 adj_base_time = position - new_play_time;
13034
13035                 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13036                          "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13037                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13038         }
13039
13040         /* Adjust Current Stream Time with base_time of sink
13041          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13042          * 2. Set new base time
13043          *    if adj_base_time is positive value, the stream time will be decreased.
13044          * 3. If seek event is occurred, the start time will be reset. */
13045         if ((player->pipeline->audiobin) &&
13046                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13047                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13048
13049                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13050                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13051                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13052                 }
13053
13054                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13055         }
13056
13057         if ((player->pipeline->videobin) &&
13058                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13059                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13060
13061                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13062                         LOGD("video sink : gst_element_set_start_time -> NONE");
13063                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13064                 }
13065
13066                 // if videobin exist, get base_time from videobin.
13067                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13068         }
13069
13070         new_base_time = base_time + adj_base_time;
13071
13072         if ((player->pipeline->audiobin) &&
13073                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13074                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13075
13076         if ((player->pipeline->videobin) &&
13077                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13078                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13079
13080 EXIT:
13081         MMPLAYER_FLEAVE();
13082
13083         return result;
13084 }
13085
13086 int
13087 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13088 {
13089         mm_player_t* player = (mm_player_t*) hplayer;
13090         MMPlayerGstElement* mainbin = NULL;
13091         GstClock *curr_clock = NULL;
13092         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13093         gint64 position = 0;
13094         gboolean query_ret = TRUE;
13095
13096         MMPLAYER_FENTER();
13097
13098         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13099         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13100         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13101
13102         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13103         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13104         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13105
13106         mainbin = player->pipeline->mainbin;
13107
13108         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13109
13110         current_state = MMPLAYER_CURRENT_STATE(player);
13111
13112         if (current_state != MM_PLAYER_STATE_PAUSED)
13113                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13114
13115         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13116                 (!query_ret))
13117                 position = player->last_position;
13118
13119         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13120
13121         LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13122
13123         if (curr_clock)
13124                 gst_object_unref(curr_clock);
13125
13126         MMPLAYER_FLEAVE();
13127
13128         return MM_ERROR_NONE;
13129 }
13130
13131 static gboolean
13132 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13133 {
13134         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13135         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13136
13137         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13138         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13139
13140         int idx = 0;
13141
13142         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13143                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13144                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13145                         mm_player_dump_t *dump_s;
13146                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13147
13148                         if (dump_s == NULL) {
13149                                 LOGE("malloc fail");
13150                                 return FALSE;
13151                         }
13152
13153                         dump_s->dump_element_file = NULL;
13154                         dump_s->dump_pad = NULL;
13155                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13156
13157                         if (dump_s->dump_pad) {
13158                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13159                                 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]);
13160                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13161                                 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);
13162                                 /* add list for removed buffer probe and close FILE */
13163                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13164                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13165                                 return TRUE;
13166                         } else {
13167                                 g_free(dump_s);
13168                                 dump_s = NULL;
13169                                 LOGE("failed to get %s sink pad added", factory_name);
13170                         }
13171
13172
13173                 }
13174         }
13175         return FALSE;
13176 }
13177
13178 static GstPadProbeReturn
13179 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13180 {
13181         FILE *dump_data = (FILE *) u_data;
13182 //      int written = 0;
13183         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13184         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13185
13186         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13187
13188         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13189
13190 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13191
13192         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13193
13194         return GST_PAD_PROBE_OK;
13195 }
13196
13197 static void
13198 __mmplayer_release_dump_list(GList *dump_list)
13199 {
13200         if (dump_list) {
13201                 GList *d_list = dump_list;
13202                 for (; d_list; d_list = g_list_next(d_list)) {
13203                         mm_player_dump_t *dump_s = d_list->data;
13204                         if (dump_s->dump_pad) {
13205                                 if (dump_s->probe_handle_id)
13206                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13207                         }
13208                         if (dump_s->dump_element_file) {
13209                                 fclose(dump_s->dump_element_file);
13210                                 dump_s->dump_element_file = NULL;
13211                         }
13212                         MMPLAYER_FREEIF(dump_s);
13213                 }
13214                 g_list_free(dump_list);
13215                 dump_list = NULL;
13216         }
13217 }
13218
13219 int
13220 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13221 {
13222         mm_player_t* player = (mm_player_t*) hplayer;
13223
13224         MMPLAYER_FENTER();
13225
13226         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13227         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13228
13229         *exist = player->has_closed_caption;
13230
13231         MMPLAYER_FLEAVE();
13232
13233         return MM_ERROR_NONE;
13234 }
13235
13236 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13237 {
13238         MMPLAYER_FENTER();
13239         if (buffer) {
13240                 // LOGD("unref internal gst buffer %p", buffer);
13241                 gst_buffer_unref((GstBuffer *)buffer);
13242                 buffer = NULL;
13243         }
13244         MMPLAYER_FLEAVE();
13245 }
13246
13247 void
13248 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13249 {
13250         mm_player_t *player  = (mm_player_t*)user_data;
13251         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13252         guint64 current_level_bytes = 0;
13253
13254         MMPLAYER_RETURN_IF_FAIL(player);
13255
13256         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13257
13258         LOGI("app-src: feed audio(%llu)", current_level_bytes);
13259         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13260
13261         if (player->media_stream_buffer_status_cb[type])
13262                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13263         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13264
13265 }
13266
13267 void
13268 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13269 {
13270         mm_player_t *player  = (mm_player_t*)user_data;
13271         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13272         guint64 current_level_bytes = 0;
13273
13274         MMPLAYER_RETURN_IF_FAIL(player);
13275
13276         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13277
13278         LOGI("app-src: feed video(%llu)", current_level_bytes);
13279
13280         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13281         if (player->media_stream_buffer_status_cb[type])
13282                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13283         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13284 }
13285
13286 void
13287 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13288 {
13289         mm_player_t *player  = (mm_player_t*)user_data;
13290         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13291         guint64 current_level_bytes = 0;
13292
13293         MMPLAYER_RETURN_IF_FAIL(player);
13294
13295         LOGI("app-src: feed subtitle");
13296
13297         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13298
13299         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13300         if (player->media_stream_buffer_status_cb[type])
13301                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13302
13303         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13304 }
13305
13306 void
13307 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13308 {
13309         mm_player_t *player  = (mm_player_t*)user_data;
13310         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13311         guint64 current_level_bytes = 0;
13312
13313         MMPLAYER_RETURN_IF_FAIL(player);
13314
13315         LOGI("app-src: audio buffer is full");
13316
13317         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13318
13319         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13320
13321         if (player->media_stream_buffer_status_cb[type])
13322                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13323
13324         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13325 }
13326
13327 void
13328 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13329 {
13330         mm_player_t *player  = (mm_player_t*)user_data;
13331         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13332         guint64 current_level_bytes = 0;
13333
13334         MMPLAYER_RETURN_IF_FAIL(player);
13335
13336         LOGI("app-src: video buffer is full");
13337
13338         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13339
13340         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13341         if (player->media_stream_buffer_status_cb[type])
13342                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13343
13344         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13345 }
13346
13347 gboolean
13348 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13349 {
13350         mm_player_t *player  = (mm_player_t*)user_data;
13351         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13352
13353         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13354
13355         LOGD("app-src: seek audio data %llu", position);
13356         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13357
13358         if (player->media_stream_seek_data_cb[type])
13359                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13360         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13361
13362         return TRUE;
13363 }
13364
13365 gboolean
13366 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13367 {
13368         mm_player_t *player  = (mm_player_t*)user_data;
13369         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13370
13371         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13372
13373         LOGD("app-src: seek video data %llu", position);
13374         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13375         if (player->media_stream_seek_data_cb[type])
13376                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13377         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13378
13379         return TRUE;
13380 }
13381
13382 gboolean
13383 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13384 {
13385         mm_player_t *player  = (mm_player_t*)user_data;
13386         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13387
13388         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13389
13390         LOGD("app-src: seek subtitle data");
13391         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13392
13393         if (player->media_stream_seek_data_cb[type])
13394                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13395         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13396
13397         return TRUE;
13398 }
13399
13400 int
13401 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13402 {
13403         mm_player_t* player = (mm_player_t*) hplayer;
13404
13405         MMPLAYER_FENTER();
13406
13407         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13408
13409         player->pcm_samplerate = samplerate;
13410         player->pcm_channel = channel;
13411
13412         MMPLAYER_FLEAVE();
13413         return MM_ERROR_NONE;
13414 }
13415
13416 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13417 {
13418         mm_player_t* player = (mm_player_t*) hplayer;
13419
13420         MMPLAYER_FENTER();
13421
13422         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13423         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13424
13425         if (MMPLAYER_IS_STREAMING(player))
13426                 *timeout = player->ini.live_state_change_timeout;
13427         else
13428                 *timeout = player->ini.localplayback_state_change_timeout;
13429
13430         LOGD("timeout = %d\n", *timeout);
13431
13432         MMPLAYER_FLEAVE();
13433         return MM_ERROR_NONE;
13434 }
13435
13436 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13437 {
13438         mm_player_t* player = (mm_player_t*) hplayer;
13439
13440         MMPLAYER_FENTER();
13441
13442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13443         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13444
13445         *num = player->video_num_buffers;
13446         *extra_num = player->video_extra_num_buffers;
13447
13448         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13449
13450         MMPLAYER_FLEAVE();
13451         return MM_ERROR_NONE;
13452 }
13453
13454 static void
13455 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13456 {
13457         int i = 0;
13458         MMPLAYER_FENTER();
13459         MMPLAYER_RETURN_IF_FAIL(player);
13460
13461         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13462
13463                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13464                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13465                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13466                         player->storage_info[i].id = -1;
13467                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13468
13469                         if (path_type != MMPLAYER_PATH_MAX)
13470                                 break;
13471                 }
13472         }
13473
13474         MMPLAYER_FLEAVE();
13475 }
13476
13477 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13478 {
13479         int ret = MM_ERROR_NONE;
13480         mm_player_t* player = (mm_player_t*)hplayer;
13481         MMMessageParamType msg_param = {0, };
13482
13483         MMPLAYER_FENTER();
13484         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13485
13486         LOGW("state changed storage %d:%d", id, state);
13487
13488         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13489                 return MM_ERROR_NONE;
13490
13491         /* FIXME: text path should be handled seperately. */
13492         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13493                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13494                 LOGW("external storage is removed");
13495
13496                 if (player->msg_posted == FALSE) {
13497                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13498                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13499                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13500                         player->msg_posted = TRUE;
13501                 }
13502
13503                 /* unrealize the player */
13504                 ret = _mmplayer_unrealize(hplayer);
13505                 if (ret != MM_ERROR_NONE)
13506                         LOGE("failed to unrealize");
13507         }
13508
13509         MMPLAYER_FLEAVE();
13510         return ret;
13511 }
13512
13513 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13514 {
13515         int ret = MM_ERROR_NONE;
13516         mm_player_t* player = (mm_player_t*) hplayer;
13517         int idx = 0, total = 0;
13518         gchar *result = NULL, *tmp = NULL;
13519
13520         MMPLAYER_FENTER();
13521         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13522         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13523
13524         total = *num = g_list_length(player->adaptive_info.var_list);
13525         if (total <= 0) {
13526                 LOGW("There is no stream variant info.");
13527                 return ret;
13528         }
13529
13530         result = g_strdup("");
13531         for (idx = 0 ; idx < total ; idx++) {
13532                 VariantData *v_data = NULL;
13533                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13534
13535                 if (v_data) {
13536                         gchar data[64] = {0};
13537                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13538
13539                         tmp = g_strconcat(result, data, NULL);
13540                         g_free(result);
13541                         result = tmp;
13542                 } else {
13543                         LOGW("There is no variant data in %d", idx);
13544                         (*num)--;
13545                 }
13546         }
13547
13548         *var_info = (char *)result;
13549
13550         LOGD("variant info %d:%s", *num, *var_info);
13551         MMPLAYER_FLEAVE();
13552         return ret;
13553 }
13554
13555 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13556 {
13557         int ret = MM_ERROR_NONE;
13558         mm_player_t* player = (mm_player_t*) hplayer;
13559
13560         MMPLAYER_FENTER();
13561         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13562
13563         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13564
13565         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13566         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13567         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13568
13569         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13570                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13571                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13572                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13573
13574                 /* FIXME: seek to current position for applying new variant limitation */
13575         }
13576
13577         MMPLAYER_FLEAVE();
13578         return ret;
13579
13580 }
13581
13582 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13583 {
13584         int ret = MM_ERROR_NONE;
13585         mm_player_t* player = (mm_player_t*) hplayer;
13586
13587         MMPLAYER_FENTER();
13588         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13589         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13590
13591         *bandwidth = player->adaptive_info.limit.bandwidth;
13592         *width = player->adaptive_info.limit.width;
13593         *height = player->adaptive_info.limit.height;
13594
13595         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13596
13597         MMPLAYER_FLEAVE();
13598         return ret;
13599 }
13600
13601 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13602 {
13603         int ret = MM_ERROR_NONE;
13604         mm_player_t* player = (mm_player_t*) hplayer;
13605
13606         MMPLAYER_FENTER();
13607         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13608
13609         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13610                 LOGW("buffer_ms will not be applied.");
13611
13612
13613         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13614
13615         if (player->streamer == NULL) {
13616                 player->streamer = __mm_player_streaming_create();
13617                 __mm_player_streaming_initialize(player->streamer);
13618         }
13619
13620         if (buffer_ms >= 0)
13621                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13622
13623         if (rebuffer_ms >= 0)
13624                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13625
13626         MMPLAYER_FLEAVE();
13627         return ret;
13628
13629 }
13630
13631 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13632 {
13633         int ret = MM_ERROR_NONE;
13634         mm_player_t* player = (mm_player_t*) hplayer;
13635
13636         MMPLAYER_FENTER();
13637         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13639
13640         if (player->streamer == NULL) {
13641                 player->streamer = __mm_player_streaming_create();
13642                 __mm_player_streaming_initialize(player->streamer);
13643         }
13644
13645         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13646         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13647
13648         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13649
13650         MMPLAYER_FLEAVE();
13651         return ret;
13652 }
13653
13654 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13655 {
13656 #define IDX_FIRST_SW_CODEC 0
13657         mm_player_t* player = (mm_player_t*) hplayer;
13658         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13659         MMHandleType attrs = 0;
13660
13661         MMPLAYER_FENTER();
13662         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13663
13664         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13665                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13666                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13667
13668         switch (stream_type) {
13669         case MM_PLAYER_STREAM_TYPE_AUDIO:
13670                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13671                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13672                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13673                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13674                         LOGE("There is no a codec for codec_type %d", codec_type);
13675                         return MM_ERROR_PLAYER_NO_OP;
13676                 }
13677         break;
13678         case MM_PLAYER_STREAM_TYPE_VIDEO:
13679                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13680                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13681                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13682                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13683                         LOGE("There is no v codec for codec_type %d", codec_type);
13684                         return MM_ERROR_PLAYER_NO_OP;
13685                 }
13686
13687         break;
13688         default:
13689                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13690                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13691         break;
13692         }
13693
13694         LOGD("update %s codec_type to %d", attr_name, codec_type);
13695
13696         attrs = MMPLAYER_GET_ATTRS(player);
13697         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13698
13699         if (mmf_attrs_commit(player->attrs)) {
13700                 LOGE("failed to commit codec_type attributes");
13701                 return MM_ERROR_PLAYER_INTERNAL;
13702         }
13703
13704         MMPLAYER_FLEAVE();
13705         return MM_ERROR_NONE;
13706 }
13707
13708 int
13709 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13710 {
13711         mm_player_t* player = (mm_player_t*) hplayer;
13712         GstElement* rg_vol_element = NULL;
13713
13714         MMPLAYER_FENTER();
13715
13716         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13717
13718         player->sound.rg_enable = enabled;
13719
13720         /* just hold rgvolume enable value if pipeline is not ready */
13721         if (!player->pipeline || !player->pipeline->audiobin) {
13722                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13723                 return MM_ERROR_NONE;
13724         }
13725
13726         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13727
13728         if (!rg_vol_element) {
13729                 LOGD("rgvolume element is not created");
13730                 return MM_ERROR_PLAYER_INTERNAL;
13731         }
13732
13733         if (enabled)
13734                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13735         else
13736                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13737
13738         MMPLAYER_FLEAVE();
13739
13740         return MM_ERROR_NONE;
13741 }
13742
13743 int
13744 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13745 {
13746         mm_player_t* player = (mm_player_t*) hplayer;
13747         GstElement* rg_vol_element = NULL;
13748         gboolean enable = FALSE;
13749
13750         MMPLAYER_FENTER();
13751
13752         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13753         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13754
13755         /* just hold enable_rg value if pipeline is not ready */
13756         if (!player->pipeline || !player->pipeline->audiobin) {
13757                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13758                 *enabled = player->sound.rg_enable;
13759                 return MM_ERROR_NONE;
13760         }
13761
13762         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13763
13764         if (!rg_vol_element) {
13765                 LOGD("rgvolume element is not created");
13766                 return MM_ERROR_PLAYER_INTERNAL;
13767         }
13768
13769         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13770         *enabled = enable;
13771
13772         MMPLAYER_FLEAVE();
13773
13774         return MM_ERROR_NONE;
13775 }