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