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