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