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