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