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