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