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