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