[0.6.225] set text track info
[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);
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);
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);
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);
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);
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);
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);
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));
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                         /* free avsysaudiosink
4356                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4357                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4358                         */
4359                         MMPLAYER_FREEIF(audiobin);
4360                         MMPLAYER_FREEIF(videobin);
4361                         MMPLAYER_FREEIF(textbin);
4362                         MMPLAYER_FREEIF(mainbin);
4363                 }
4364
4365                 if (tag_list)
4366                         gst_tag_list_unref(tag_list);
4367
4368                 MMPLAYER_FREEIF(player->pipeline);
4369         }
4370         MMPLAYER_FREEIF(player->album_art);
4371
4372         if (player->type_caps) {
4373                 gst_caps_unref(player->type_caps);
4374                 player->type_caps = NULL;
4375         }
4376
4377         if (player->v_stream_caps) {
4378                 gst_caps_unref(player->v_stream_caps);
4379                 player->v_stream_caps = NULL;
4380         }
4381
4382         if (player->a_stream_caps) {
4383                 gst_caps_unref(player->a_stream_caps);
4384                 player->a_stream_caps = NULL;
4385         }
4386
4387         if (player->s_stream_caps) {
4388                 gst_caps_unref(player->s_stream_caps);
4389                 player->s_stream_caps = NULL;
4390         }
4391         _mmplayer_track_destroy(player);
4392
4393         if (player->sink_elements)
4394                 g_list_free(player->sink_elements);
4395         player->sink_elements = NULL;
4396
4397         if (player->bufmgr) {
4398                 tbm_bufmgr_deinit(player->bufmgr);
4399                 player->bufmgr = NULL;
4400         }
4401
4402         LOGW("finished destroy pipeline");
4403
4404         MMPLAYER_FLEAVE();
4405
4406         return ret;
4407 }
4408
4409 static int
4410 __mmplayer_gst_realize(mmplayer_t *player)
4411 {
4412         gint timeout = 0;
4413         int ret = MM_ERROR_NONE;
4414
4415         MMPLAYER_FENTER();
4416
4417         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4418
4419         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4420
4421         ret = __mmplayer_gst_create_pipeline(player);
4422         if (ret) {
4423                 LOGE("failed to create pipeline");
4424                 return ret;
4425         }
4426
4427         /* set pipeline state to READY */
4428         /* NOTE : state change to READY must be performed sync. */
4429         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4430         ret = _mmplayer_gst_set_state(player,
4431                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4432
4433         if (ret != MM_ERROR_NONE) {
4434                 /* return error if failed to set state */
4435                 LOGE("failed to set READY state");
4436                 return ret;
4437         }
4438
4439         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4440
4441         /* create dot before error-return. for debugging */
4442         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4443
4444         MMPLAYER_FLEAVE();
4445
4446         return ret;
4447 }
4448
4449 static int
4450 __mmplayer_gst_unrealize(mmplayer_t *player)
4451 {
4452         int ret = MM_ERROR_NONE;
4453
4454         MMPLAYER_FENTER();
4455
4456         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4457
4458         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4459         MMPLAYER_PRINT_STATE(player);
4460
4461         /* release miscellaneous information */
4462         __mmplayer_release_misc(player);
4463
4464         /* destroy pipeline */
4465         ret = __mmplayer_gst_destroy_pipeline(player);
4466         if (ret != MM_ERROR_NONE) {
4467                 LOGE("failed to destory pipeline");
4468                 return ret;
4469         }
4470
4471         /* release miscellaneous information.
4472            these info needs to be released after pipeline is destroyed. */
4473         __mmplayer_release_misc_post(player);
4474
4475         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4476
4477         MMPLAYER_FLEAVE();
4478
4479         return ret;
4480 }
4481
4482 static int
4483 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4484 {
4485         MMPLAYER_FENTER();
4486
4487         if (!player) {
4488                 LOGW("set_message_callback is called with invalid player handle");
4489                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4490         }
4491
4492         player->msg_cb = callback;
4493         player->msg_cb_param = user_param;
4494
4495         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4496
4497         MMPLAYER_FLEAVE();
4498
4499         return MM_ERROR_NONE;
4500 }
4501
4502 int
4503 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4504 {
4505         int ret = MM_ERROR_NONE;
4506         char *path = NULL;
4507
4508         MMPLAYER_FENTER();
4509
4510         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4511         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4512         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4513
4514         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4515
4516         if (strstr(uri, "es_buff://")) {
4517                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4518         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4519                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4520         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4521                 gchar *tmp = NULL;
4522                 tmp = g_ascii_strdown(uri, strlen(uri));
4523                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4524                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4525                 else
4526                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4527                 g_free(tmp);
4528         } else if (strstr(uri, "mms://")) {
4529                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4530         } else if ((path = strstr(uri, "mem://"))) {
4531                 ret = __mmplayer_set_mem_uri(data, path, param);
4532         } else {
4533                 ret = __mmplayer_set_file_uri(data, uri);
4534         }
4535
4536         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4537                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4538         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4539                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4540
4541         /* dump parse result */
4542         SECURE_LOGW("incoming uri : %s", uri);
4543         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4544                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4545
4546         MMPLAYER_FLEAVE();
4547
4548         return ret;
4549 }
4550
4551 static gboolean
4552 __mmplayer_can_do_interrupt(mmplayer_t *player)
4553 {
4554         if (!player || !player->pipeline || !player->attrs) {
4555                 LOGW("not initialized");
4556                 goto FAILED;
4557         }
4558
4559         if (player->audio_decoded_cb) {
4560                 LOGW("not support in pcm extraction mode");
4561                 goto FAILED;
4562         }
4563
4564         /* check if seeking */
4565         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4566                 MMMessageParamType msg_param;
4567                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4568                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4569                 player->seek_state = MMPLAYER_SEEK_NONE;
4570                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4571                 goto FAILED;
4572         }
4573
4574         /* check other thread */
4575         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4576                 LOGW("locked already, cmd state : %d", player->cmd);
4577
4578                 /* check application command */
4579                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4580                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4581
4582                         /* lock will be released at mrp_resource_release_cb() */
4583                         MMPLAYER_CMD_LOCK(player);
4584                         goto INTERRUPT;
4585                 }
4586                 LOGW("nothing to do");
4587                 goto FAILED;
4588         } else {
4589                 LOGW("can interrupt immediately");
4590                 goto INTERRUPT;
4591         }
4592
4593 FAILED:    /* with CMD UNLOCKED */
4594         return FALSE;
4595
4596 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4597         return TRUE;
4598 }
4599
4600 static int
4601 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4602                 void *user_data)
4603 {
4604         mmplayer_t *player = NULL;
4605         MMMessageParamType msg = {0, };
4606         gint64 pos = 0;
4607         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4608
4609         MMPLAYER_FENTER();
4610
4611         if (!user_data) {
4612                 LOGE("user_data is null");
4613                 return FALSE;
4614         }
4615         player = (mmplayer_t *)user_data;
4616
4617         if (!__mmplayer_can_do_interrupt(player)) {
4618                 LOGW("no need to interrupt, so leave");
4619                 /* FIXME: there is no way to avoid releasing resource. */
4620                 return FALSE;
4621         }
4622
4623         player->interrupted_by_resource = TRUE;
4624
4625         /* get last play position */
4626         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4627                 msg.union_type = MM_MSG_UNION_TIME;
4628                 msg.time.elapsed = pos;
4629                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4630         } else {
4631                 LOGW("failed to get play position.");
4632         }
4633
4634         LOGD("video resource conflict so, resource will be freed by unrealizing");
4635         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4636                 LOGE("failed to unrealize");
4637
4638         /* lock is called in __mmplayer_can_do_interrupt() */
4639         MMPLAYER_CMD_UNLOCK(player);
4640
4641         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4642                 player->hw_resource[res_idx] = NULL;
4643         }
4644
4645         MMPLAYER_FLEAVE();
4646         return TRUE; /* release all the resources */
4647 }
4648
4649 static void
4650 __mmplayer_initialize_video_roi(mmplayer_t *player)
4651 {
4652         player->video_roi.scale_x = 0.0;
4653         player->video_roi.scale_y = 0.0;
4654         player->video_roi.scale_width = 1.0;
4655         player->video_roi.scale_height = 1.0;
4656 }
4657
4658 int
4659 _mmplayer_create_player(MMHandleType handle)
4660 {
4661         int ret = MM_ERROR_PLAYER_INTERNAL;
4662         bool enabled = false;
4663
4664         mmplayer_t *player = MM_PLAYER_CAST(handle);
4665
4666         MMPLAYER_FENTER();
4667
4668         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4669
4670         /* initialize player state */
4671         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4672         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4673         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4674         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4675
4676         /* check current state */
4677         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4678
4679         /* construct attributes */
4680         player->attrs = _mmplayer_construct_attribute(handle);
4681
4682         if (!player->attrs) {
4683                 LOGE("Failed to construct attributes");
4684                 return ret;
4685         }
4686
4687         /* initialize gstreamer with configured parameter */
4688         if (!__mmplayer_init_gstreamer(player)) {
4689                 LOGE("Initializing gstreamer failed");
4690                 _mmplayer_deconstruct_attribute(handle);
4691                 return ret;
4692         }
4693
4694         /* create lock. note that g_tread_init() has already called in gst_init() */
4695         g_mutex_init(&player->fsink_lock);
4696
4697         /* create update tag lock */
4698         g_mutex_init(&player->update_tag_lock);
4699
4700         /* create gapless play mutex */
4701         g_mutex_init(&player->gapless_play_thread_mutex);
4702
4703         /* create gapless play cond */
4704         g_cond_init(&player->gapless_play_thread_cond);
4705
4706         /* create gapless play thread */
4707         player->gapless_play_thread =
4708                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4709         if (!player->gapless_play_thread) {
4710                 LOGE("failed to create gapless play thread");
4711                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4712                 g_mutex_clear(&player->gapless_play_thread_mutex);
4713                 g_cond_clear(&player->gapless_play_thread_cond);
4714                 goto ERROR;
4715         }
4716
4717         player->bus_msg_q = g_queue_new();
4718         if (!player->bus_msg_q) {
4719                 LOGE("failed to create queue for bus_msg");
4720                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4721                 goto ERROR;
4722         }
4723
4724         ret = _mmplayer_initialize_video_capture(player);
4725         if (ret != MM_ERROR_NONE) {
4726                 LOGE("failed to initialize video capture");
4727                 goto ERROR;
4728         }
4729
4730         /* initialize resource manager */
4731         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4732                 __resource_release_cb, player, &player->resource_manager)
4733                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4734                 LOGE("failed to initialize resource manager");
4735                 ret = MM_ERROR_PLAYER_INTERNAL;
4736                 goto ERROR;
4737         }
4738
4739         /* create video bo lock and cond */
4740         g_mutex_init(&player->video_bo_mutex);
4741         g_cond_init(&player->video_bo_cond);
4742
4743         /* create subtitle info lock and cond */
4744         g_mutex_init(&player->subtitle_info_mutex);
4745         g_cond_init(&player->subtitle_info_cond);
4746
4747         player->streaming_type = STREAMING_SERVICE_NONE;
4748
4749         /* give default value of audio effect setting */
4750         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4751         player->sound.rg_enable = false;
4752         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4753
4754         player->play_subtitle = FALSE;
4755         player->has_closed_caption = FALSE;
4756         player->pending_resume = FALSE;
4757         if (player->ini.dump_element_keyword[0][0] == '\0')
4758                 player->ini.set_dump_element_flag = FALSE;
4759         else
4760                 player->ini.set_dump_element_flag = TRUE;
4761
4762         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4763         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4764         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4765
4766         /* Set video360 settings to their defaults for just-created player.
4767          * */
4768
4769         player->is_360_feature_enabled = FALSE;
4770         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4771                 LOGI("spherical feature info: %d", enabled);
4772                 if (enabled)
4773                         player->is_360_feature_enabled = TRUE;
4774         } else {
4775                 LOGE("failed to get spherical feature info");
4776         }
4777
4778         player->is_content_spherical = FALSE;
4779         player->is_video360_enabled = TRUE;
4780         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4781         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4782         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4783         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4784         player->video360_zoom = 1.0f;
4785         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4786         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4787
4788         __mmplayer_initialize_video_roi(player);
4789
4790         /* set player state to null */
4791         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4792         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4793
4794         MMPLAYER_FLEAVE();
4795
4796         return MM_ERROR_NONE;
4797
4798 ERROR:
4799         /* free lock */
4800         g_mutex_clear(&player->fsink_lock);
4801         /* free update tag lock */
4802         g_mutex_clear(&player->update_tag_lock);
4803         g_queue_free(player->bus_msg_q);
4804         player->bus_msg_q = NULL;
4805         /* free gapless play thread */
4806         if (player->gapless_play_thread) {
4807                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4808                 player->gapless_play_thread_exit = TRUE;
4809                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4810                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4811
4812                 g_thread_join(player->gapless_play_thread);
4813                 player->gapless_play_thread = NULL;
4814
4815                 g_mutex_clear(&player->gapless_play_thread_mutex);
4816                 g_cond_clear(&player->gapless_play_thread_cond);
4817         }
4818
4819         /* release attributes */
4820         _mmplayer_deconstruct_attribute(handle);
4821
4822         MMPLAYER_FLEAVE();
4823
4824         return ret;
4825 }
4826
4827 static gboolean
4828 __mmplayer_init_gstreamer(mmplayer_t *player)
4829 {
4830         static gboolean initialized = FALSE;
4831         static const int max_argc = 50;
4832         gint *argc = NULL;
4833         gchar **argv = NULL;
4834         gchar **argv2 = NULL;
4835         GError *err = NULL;
4836         int i = 0;
4837         int arg_count = 0;
4838
4839         if (initialized) {
4840                 LOGD("gstreamer already initialized.");
4841                 return TRUE;
4842         }
4843
4844         /* alloc */
4845         argc = malloc(sizeof(int));
4846         argv = malloc(sizeof(gchar *) * max_argc);
4847         argv2 = malloc(sizeof(gchar *) * max_argc);
4848
4849         if (!argc || !argv || !argv2)
4850                 goto ERROR;
4851
4852         memset(argv, 0, sizeof(gchar *) * max_argc);
4853         memset(argv2, 0, sizeof(gchar *) * max_argc);
4854
4855         /* add initial */
4856         *argc = 1;
4857         argv[0] = g_strdup("mmplayer");
4858
4859         /* add gst_param */
4860         for (i = 0; i < 5; i++) {
4861                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4862                 if (strlen(player->ini.gst_param[i]) > 0) {
4863                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4864                         (*argc)++;
4865                 }
4866         }
4867
4868         /* we would not do fork for scanning plugins */
4869         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4870         (*argc)++;
4871
4872         /* check disable registry scan */
4873         if (player->ini.skip_rescan) {
4874                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4875                 (*argc)++;
4876         }
4877
4878         /* check disable segtrap */
4879         if (player->ini.disable_segtrap) {
4880                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4881                 (*argc)++;
4882         }
4883
4884         LOGD("initializing gstreamer with following parameter");
4885         LOGD("argc : %d", *argc);
4886         arg_count = *argc;
4887
4888         for (i = 0; i < arg_count; i++) {
4889                 argv2[i] = argv[i];
4890                 LOGD("argv[%d] : %s", i, argv2[i]);
4891         }
4892
4893         /* initializing gstreamer */
4894         if (!gst_init_check(argc, &argv, &err)) {
4895                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4896                 if (err)
4897                         g_error_free(err);
4898
4899                 goto ERROR;
4900         }
4901         /* release */
4902         for (i = 0; i < arg_count; i++) {
4903 #ifdef __DEBUG__
4904                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4905 #endif
4906                 MMPLAYER_FREEIF(argv2[i]);
4907         }
4908
4909         MMPLAYER_FREEIF(argv);
4910         MMPLAYER_FREEIF(argv2);
4911         MMPLAYER_FREEIF(argc);
4912
4913         /* done */
4914         initialized = TRUE;
4915
4916         return TRUE;
4917
4918 ERROR:
4919
4920         /* release */
4921         for (i = 0; i < arg_count; i++) {
4922                 LOGD("free[%d] : %s", i, argv2[i]);
4923                 MMPLAYER_FREEIF(argv2[i]);
4924         }
4925
4926         MMPLAYER_FREEIF(argv);
4927         MMPLAYER_FREEIF(argv2);
4928         MMPLAYER_FREEIF(argc);
4929
4930         return FALSE;
4931 }
4932
4933 static void
4934 __mmplayer_check_async_state_transition(mmplayer_t *player)
4935 {
4936         GstState element_state = GST_STATE_VOID_PENDING;
4937         GstState element_pending_state = GST_STATE_VOID_PENDING;
4938         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4939         GstElement *element = NULL;
4940         gboolean async = FALSE;
4941
4942         /* check player handle */
4943         MMPLAYER_RETURN_IF_FAIL(player &&
4944                                                 player->pipeline &&
4945                                                 player->pipeline->mainbin &&
4946                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4947
4948         if (player->attrs)
4949                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4950
4951         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4952                 LOGD("don't need to check the pipeline state");
4953                 return;
4954         }
4955
4956         MMPLAYER_PRINT_STATE(player);
4957
4958         /* wait for state transition */
4959         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4960         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4961
4962         if (ret == GST_STATE_CHANGE_FAILURE) {
4963                 LOGE(" [%s] state : %s   pending : %s",
4964                         GST_ELEMENT_NAME(element),
4965                         gst_element_state_get_name(element_state),
4966                         gst_element_state_get_name(element_pending_state));
4967
4968                 /* dump state of all element */
4969                 _mmplayer_dump_pipeline_state(player);
4970
4971                 return;
4972         }
4973
4974         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4975         return;
4976 }
4977
4978 int
4979 _mmplayer_destroy(MMHandleType handle)
4980 {
4981         mmplayer_t *player = MM_PLAYER_CAST(handle);
4982
4983         MMPLAYER_FENTER();
4984
4985         /* check player handle */
4986         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987
4988         /* destroy can called at anytime */
4989         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4990
4991         /* check async state transition */
4992         __mmplayer_check_async_state_transition(player);
4993
4994         /* release gapless play thread */
4995         if (player->gapless_play_thread) {
4996                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4997                 player->gapless_play_thread_exit = TRUE;
4998                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4999                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5000
5001                 LOGD("waitting for gapless play thread exit");
5002                 g_thread_join(player->gapless_play_thread);
5003                 g_mutex_clear(&player->gapless_play_thread_mutex);
5004                 g_cond_clear(&player->gapless_play_thread_cond);
5005                 LOGD("gapless play thread released");
5006         }
5007
5008         _mmplayer_release_video_capture(player);
5009
5010         /* de-initialize resource manager */
5011         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5012                         player->resource_manager))
5013                 LOGE("failed to deinitialize resource manager");
5014
5015         /* release miscellaneous information */
5016         __mmplayer_release_misc(player);
5017
5018         /* release pipeline */
5019         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5020                 LOGE("failed to destory pipeline");
5021                 return MM_ERROR_PLAYER_INTERNAL;
5022         }
5023
5024         g_queue_free(player->bus_msg_q);
5025
5026         /* release subtitle info lock and cond */
5027         g_mutex_clear(&player->subtitle_info_mutex);
5028         g_cond_clear(&player->subtitle_info_cond);
5029
5030         __mmplayer_release_dump_list(player->dump_list);
5031
5032         /* release miscellaneous information.
5033            these info needs to be released after pipeline is destroyed. */
5034         __mmplayer_release_misc_post(player);
5035
5036         /* release attributes */
5037         _mmplayer_deconstruct_attribute(handle);
5038
5039         if (player->uri_info.uri_list) {
5040                 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5041                 player->uri_info.uri_list = NULL;
5042         }
5043
5044         /* release lock */
5045         g_mutex_clear(&player->fsink_lock);
5046
5047         /* release lock */
5048         g_mutex_clear(&player->update_tag_lock);
5049
5050         /* release video bo lock and cond */
5051         g_mutex_clear(&player->video_bo_mutex);
5052         g_cond_clear(&player->video_bo_cond);
5053
5054         MMPLAYER_FLEAVE();
5055
5056         return MM_ERROR_NONE;
5057 }
5058
5059 int
5060 _mmplayer_realize(MMHandleType hplayer)
5061 {
5062         mmplayer_t *player = (mmplayer_t *)hplayer;
5063         int ret = MM_ERROR_NONE;
5064         char *uri = NULL;
5065         void *param = NULL;
5066         MMHandleType attrs = 0;
5067
5068         MMPLAYER_FENTER();
5069
5070         /* check player handle */
5071         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5072
5073         /* check current state */
5074         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5075
5076         attrs = MMPLAYER_GET_ATTRS(player);
5077         if (!attrs) {
5078                 LOGE("fail to get attributes.");
5079                 return MM_ERROR_PLAYER_INTERNAL;
5080         }
5081         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5082         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
5083
5084         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5085                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5086
5087                 if (ret != MM_ERROR_NONE) {
5088                         LOGE("failed to parse profile");
5089                         return ret;
5090                 }
5091         }
5092
5093         if (uri && (strstr(uri, "es_buff://"))) {
5094                 if (strstr(uri, "es_buff://push_mode"))
5095                         player->es_player_push_mode = TRUE;
5096                 else
5097                         player->es_player_push_mode = FALSE;
5098         }
5099
5100         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5101                 LOGW("mms protocol is not supported format.");
5102                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5103         }
5104
5105         if (MMPLAYER_IS_STREAMING(player))
5106                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5107         else
5108                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5109
5110         player->smooth_streaming = FALSE;
5111         player->videodec_linked  = 0;
5112         player->audiodec_linked  = 0;
5113         player->textsink_linked = 0;
5114         player->is_external_subtitle_present = FALSE;
5115         player->is_external_subtitle_added_now = FALSE;
5116         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5117         player->video360_metadata.is_spherical = -1;
5118         player->is_openal_plugin_used = FALSE;
5119         player->subtitle_language_list = NULL;
5120         player->is_subtitle_force_drop = FALSE;
5121
5122         _mmplayer_track_initialize(player);
5123         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5124
5125         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5126                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5127
5128                 player->streamer = _mm_player_streaming_create();
5129                 _mm_player_streaming_initialize(player->streamer, TRUE);
5130
5131                 mm_attrs_multiple_get(player->attrs, NULL,
5132                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5133                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5134
5135                 if (prebuffer_ms > 0) {
5136                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5137                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5138                 }
5139
5140                 if (rebuffer_ms > 0) {
5141                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5142                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5143                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5144                 }
5145
5146                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5147                                                                 player->streamer->buffering_req.rebuffer_time);
5148         }
5149
5150         /* realize pipeline */
5151         ret = __mmplayer_gst_realize(player);
5152         if (ret != MM_ERROR_NONE)
5153                 LOGE("fail to realize the player.");
5154
5155         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5156
5157         MMPLAYER_FLEAVE();
5158
5159         return ret;
5160 }
5161
5162 int
5163 _mmplayer_unrealize(MMHandleType hplayer)
5164 {
5165         mmplayer_t *player = (mmplayer_t *)hplayer;
5166         int ret = MM_ERROR_NONE;
5167
5168         MMPLAYER_FENTER();
5169
5170         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5171
5172         MMPLAYER_CMD_UNLOCK(player);
5173         _mmplayer_bus_watcher_remove(player);
5174         /* destroy the gst bus msg thread which is created during realize.
5175            this funct have to be called before getting cmd lock. */
5176         _mmplayer_bus_msg_thread_destroy(player);
5177         MMPLAYER_CMD_LOCK(player);
5178
5179         /* check current state */
5180         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5181
5182         /* check async state transition */
5183         __mmplayer_check_async_state_transition(player);
5184
5185         /* unrealize pipeline */
5186         ret = __mmplayer_gst_unrealize(player);
5187
5188         if (!player->interrupted_by_resource) {
5189                 int rm_ret = MM_ERROR_NONE;
5190                 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5191
5192                 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5193                         rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5194                         if (rm_ret != MM_ERROR_NONE)
5195                                 LOGE("failed to release [%d] resources", res_idx);
5196                 }
5197         }
5198
5199         MMPLAYER_FLEAVE();
5200         return ret;
5201 }
5202
5203 int
5204 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5205 {
5206         mmplayer_t *player = (mmplayer_t *)hplayer;
5207
5208         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209
5210         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5211 }
5212
5213 int
5214 _mmplayer_get_state(MMHandleType hplayer, int *state)
5215 {
5216         mmplayer_t *player = (mmplayer_t *)hplayer;
5217
5218         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5219
5220         *state = MMPLAYER_CURRENT_STATE(player);
5221
5222         return MM_ERROR_NONE;
5223 }
5224
5225 static int
5226 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5227 {
5228         GstElement *vol_element = NULL;
5229         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5230
5231         MMPLAYER_FENTER();
5232         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5233         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5234
5235         /* check pipeline handle */
5236         if (!player->pipeline || !player->pipeline->audiobin) {
5237                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5238
5239                 /* NOTE : stored value will be used in create_audiobin
5240                  * returning MM_ERROR_NONE here makes application to able to
5241                  * set audio volume or mute at anytime.
5242                  */
5243                 return MM_ERROR_NONE;
5244         }
5245
5246         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5247                 volume_elem_id = MMPLAYER_A_SINK;
5248
5249         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5250         if (!vol_element) {
5251                 LOGE("failed to get vol element %d", volume_elem_id);
5252                 return MM_ERROR_PLAYER_INTERNAL;
5253         }
5254
5255         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5256
5257         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5258                 LOGE("there is no '%s' property", prop_name);
5259                 return MM_ERROR_PLAYER_INTERNAL;
5260         }
5261
5262         if (!strcmp(prop_name, "volume")) {
5263                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5264         } else if (!strcmp(prop_name, "mute")) {
5265                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5266         } else {
5267                 LOGE("invalid property %s", prop_name);
5268                 return MM_ERROR_PLAYER_INTERNAL;
5269         }
5270
5271         return MM_ERROR_NONE;
5272 }
5273
5274 int
5275 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5276 {
5277         int ret = MM_ERROR_NONE;
5278         mmplayer_t *player = (mmplayer_t *)hplayer;
5279
5280         MMPLAYER_FENTER();
5281         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282
5283         LOGD("volume = %f", volume);
5284
5285         /* invalid factor range or not */
5286         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5287                 LOGE("Invalid volume value");
5288                 return MM_ERROR_INVALID_ARGUMENT;
5289         }
5290
5291         player->sound.volume = volume;
5292
5293         ret = __mmplayer_gst_set_volume_property(player, "volume");
5294
5295         MMPLAYER_FLEAVE();
5296         return ret;
5297 }
5298
5299 int
5300 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5301 {
5302         mmplayer_t *player = (mmplayer_t *)hplayer;
5303
5304         MMPLAYER_FENTER();
5305
5306         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5308
5309         *volume = player->sound.volume;
5310
5311         LOGD("current vol = %f", *volume);
5312
5313         MMPLAYER_FLEAVE();
5314         return MM_ERROR_NONE;
5315 }
5316
5317 int
5318 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5319 {
5320         int ret = MM_ERROR_NONE;
5321         mmplayer_t *player = (mmplayer_t *)hplayer;
5322
5323         MMPLAYER_FENTER();
5324         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5325
5326         LOGD("mute = %d", mute);
5327
5328         player->sound.mute = mute;
5329
5330         ret = __mmplayer_gst_set_volume_property(player, "mute");
5331
5332         MMPLAYER_FLEAVE();
5333         return ret;
5334 }
5335
5336 int
5337 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5338 {
5339         mmplayer_t *player = (mmplayer_t *)hplayer;
5340
5341         MMPLAYER_FENTER();
5342
5343         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5344         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5345
5346         *mute = player->sound.mute;
5347
5348         LOGD("current mute = %d", *mute);
5349
5350         MMPLAYER_FLEAVE();
5351
5352         return MM_ERROR_NONE;
5353 }
5354
5355 int
5356 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5357 {
5358         mmplayer_t *player = (mmplayer_t *)hplayer;
5359
5360         MMPLAYER_FENTER();
5361
5362         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5363
5364         player->audio_stream_changed_cb = callback;
5365         player->audio_stream_changed_cb_user_param = user_param;
5366         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5367
5368         MMPLAYER_FLEAVE();
5369
5370         return MM_ERROR_NONE;
5371 }
5372
5373 int
5374 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5375 {
5376         mmplayer_t *player = (mmplayer_t *)hplayer;
5377
5378         MMPLAYER_FENTER();
5379
5380         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5381
5382         player->audio_decoded_cb = callback;
5383         player->audio_decoded_cb_user_param = user_param;
5384         player->audio_extract_opt = opt;
5385         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5386
5387         MMPLAYER_FLEAVE();
5388
5389         return MM_ERROR_NONE;
5390 }
5391
5392 int
5393 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5394 {
5395         mmplayer_t *player = (mmplayer_t *)hplayer;
5396
5397         MMPLAYER_FENTER();
5398
5399         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5400
5401         if (callback && !player->bufmgr)
5402                 player->bufmgr = tbm_bufmgr_init(-1);
5403
5404         player->set_mode.video_export = (callback) ? true : false;
5405         player->video_decoded_cb = callback;
5406         player->video_decoded_cb_user_param = user_param;
5407
5408         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5409
5410         MMPLAYER_FLEAVE();
5411
5412         return MM_ERROR_NONE;
5413 }
5414
5415 int
5416 _mmplayer_start(MMHandleType hplayer)
5417 {
5418         mmplayer_t *player = (mmplayer_t *)hplayer;
5419         gint ret = MM_ERROR_NONE;
5420
5421         MMPLAYER_FENTER();
5422
5423         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5424
5425         /* check current state */
5426         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5427
5428         /* start pipeline */
5429         ret = _mmplayer_gst_start(player);
5430         if (ret != MM_ERROR_NONE)
5431                 LOGE("failed to start player.");
5432
5433         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5434                 LOGD("force playing start even during buffering");
5435                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5436         }
5437
5438         MMPLAYER_FLEAVE();
5439
5440         return ret;
5441 }
5442
5443 /* NOTE: post "not supported codec message" to application
5444  * when one codec is not found during AUTOPLUGGING in MSL.
5445  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5446  * And, if any codec is not found, don't send message here.
5447  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5448  */
5449 int
5450 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5451 {
5452         MMMessageParamType msg_param;
5453         memset(&msg_param, 0, sizeof(MMMessageParamType));
5454         gboolean post_msg_direct = FALSE;
5455
5456         MMPLAYER_FENTER();
5457
5458         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459
5460         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5461                         player->not_supported_codec, player->can_support_codec);
5462
5463         if (player->not_found_demuxer) {
5464                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5465                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5466
5467                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5468                 MMPLAYER_FREEIF(msg_param.data);
5469
5470                 return MM_ERROR_NONE;
5471         }
5472
5473         if (player->not_supported_codec) {
5474                 if (player->can_support_codec) {
5475                         // There is one codec to play
5476                         post_msg_direct = TRUE;
5477                 } else {
5478                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5479                                 post_msg_direct = TRUE;
5480                 }
5481
5482                 if (post_msg_direct) {
5483                         MMMessageParamType msg_param;
5484                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5485
5486                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5487                                 LOGW("not found AUDIO codec, posting error code to application.");
5488
5489                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5490                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5491                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5492                                 LOGW("not found VIDEO codec, posting error code to application.");
5493
5494                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5495                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5496                         }
5497
5498                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5499
5500                         MMPLAYER_FREEIF(msg_param.data);
5501
5502                         return MM_ERROR_NONE;
5503                 } else {
5504                         // no any supported codec case
5505                         LOGW("not found any codec, posting error code to application.");
5506
5507                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5508                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5509                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5510                         } else {
5511                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5512                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5513                         }
5514
5515                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5516
5517                         MMPLAYER_FREEIF(msg_param.data);
5518                 }
5519         }
5520
5521         MMPLAYER_FLEAVE();
5522
5523         return MM_ERROR_NONE;
5524 }
5525
5526 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5527 {
5528         GstState element_state = GST_STATE_VOID_PENDING;
5529         GstState element_pending_state = GST_STATE_VOID_PENDING;
5530         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5531         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5532
5533         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5534
5535         MMPLAYER_RECONFIGURE_LOCK(player);
5536         if (!player->gapless.reconfigure) {
5537                 MMPLAYER_RECONFIGURE_UNLOCK(player);
5538                 return;
5539         }
5540
5541         LOGI("reconfigure is under process");
5542         MMPLAYER_RECONFIGURE_WAIT(player);
5543         MMPLAYER_RECONFIGURE_UNLOCK(player);
5544         LOGI("reconfigure is completed.");
5545
5546         result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5547                                 &element_state, &element_pending_state, timeout * GST_SECOND);
5548         if (result == GST_STATE_CHANGE_FAILURE)
5549                 LOGW("failed to get pipeline state in %d sec", timeout);
5550
5551         return;
5552 }
5553
5554 /* NOTE : it should be able to call 'stop' anytime*/
5555 int
5556 _mmplayer_stop(MMHandleType hplayer)
5557 {
5558         mmplayer_t *player = (mmplayer_t *)hplayer;
5559         int ret = MM_ERROR_NONE;
5560
5561         MMPLAYER_FENTER();
5562
5563         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5564
5565         /* check current state */
5566         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5567
5568         /* need to wait till the rebuilding pipeline is completed */
5569         __mmplayer_check_pipeline_reconfigure_state(player);
5570         MMPLAYER_RECONFIGURE_LOCK(player);
5571         __mmplayer_reset_gapless_state(player);
5572         MMPLAYER_RECONFIGURE_UNLOCK(player);
5573
5574         /* NOTE : application should not wait for EOS after calling STOP */
5575         _mmplayer_cancel_eos_timer(player);
5576
5577         /* reset */
5578         player->seek_state = MMPLAYER_SEEK_NONE;
5579
5580         /* stop pipeline */
5581         ret = _mmplayer_gst_stop(player);
5582
5583         if (ret != MM_ERROR_NONE)
5584                 LOGE("failed to stop player.");
5585
5586         MMPLAYER_FLEAVE();
5587
5588         return ret;
5589 }
5590
5591 int
5592 _mmplayer_pause(MMHandleType hplayer)
5593 {
5594         mmplayer_t *player = (mmplayer_t *)hplayer;
5595         gint64 pos_nsec = 0;
5596         gboolean async = FALSE;
5597         gint ret = MM_ERROR_NONE;
5598
5599         MMPLAYER_FENTER();
5600
5601         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5602
5603         /* check current state */
5604         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5605
5606         /* check pipline reconfigure state */
5607         __mmplayer_check_pipeline_reconfigure_state(player);
5608
5609         switch (MMPLAYER_CURRENT_STATE(player)) {
5610         case MM_PLAYER_STATE_READY:
5611                 {
5612                         /* check prepare async or not.
5613                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5614                          */
5615                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5616                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5617
5618                         /* Changing back sync of rtspsrc to async */
5619                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5620                                 LOGD("async prepare working mode for rtsp");
5621                                 async = TRUE;
5622                         }
5623                 }
5624                 break;
5625
5626         case MM_PLAYER_STATE_PLAYING:
5627                 {
5628                         /* NOTE : store current point to overcome some bad operation
5629                         *(returning zero when getting current position in paused state) of some
5630                         * elements
5631                         */
5632                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5633                                 LOGW("getting current position failed in paused");
5634
5635                         player->last_position = pos_nsec;
5636
5637                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5638                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5639                            This causes problem is position calculation during normal pause resume scenarios also.
5640                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5641                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5642                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5643                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5644                         }
5645                 }
5646                 break;
5647         }
5648
5649         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5650                 LOGD("doing async pause in case of ms buff src");
5651                 async = TRUE;
5652         }
5653
5654         /* pause pipeline */
5655         ret = _mmplayer_gst_pause(player, async);
5656
5657         if (ret != MM_ERROR_NONE)
5658                 LOGE("failed to pause player. ret : 0x%x", ret);
5659
5660         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5661                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5662                         LOGE("failed to update display_rotation");
5663         }
5664
5665         MMPLAYER_FLEAVE();
5666
5667         return ret;
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)
7882 {
7883         MMPLAYER_FENTER();
7884
7885         MMPLAYER_RETURN_IF_FAIL(player);
7886         MMPLAYER_RETURN_IF_FAIL(sink);
7887
7888         player->sink_elements = g_list_append(player->sink_elements, sink);
7889
7890         MMPLAYER_FLEAVE();
7891 }
7892
7893 static void
7894 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7895 {
7896         MMPLAYER_FENTER();
7897
7898         MMPLAYER_RETURN_IF_FAIL(player);
7899         MMPLAYER_RETURN_IF_FAIL(sink);
7900
7901         player->sink_elements = g_list_remove(player->sink_elements, sink);
7902
7903         MMPLAYER_FLEAVE();
7904 }
7905
7906 void
7907 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7908         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7909 {
7910         mmplayer_signal_item_t *item = NULL;
7911
7912         MMPLAYER_FENTER();
7913         MMPLAYER_RETURN_IF_FAIL(player);
7914
7915         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7916                 LOGE("invalid signal type [%d]", type);
7917                 return;
7918         }
7919
7920         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7921         if (!item) {
7922                 LOGE("cannot connect signal [%s]", signal);
7923                 return;
7924         }
7925
7926         item->obj = object;
7927         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7928         player->signals[type] = g_list_append(player->signals[type], item);
7929
7930         MMPLAYER_FLEAVE();
7931         return;
7932 }
7933
7934 /* NOTE : be careful with calling this api. please refer to below glib comment
7935  * glib comment : Note that there is a bug in GObject that makes this function much
7936  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7937  * will no longer be called, but, the signal handler is not currently disconnected.
7938  * If the instance is itself being freed at the same time than this doesn't matter,
7939  * since the signal will automatically be removed, but if instance persists,
7940  * then the signal handler will leak. You should not remove the signal yourself
7941  * because in a future versions of GObject, the handler will automatically be
7942  * disconnected.
7943  *
7944  * It's possible to work around this problem in a way that will continue to work
7945  * with future versions of GObject by checking that the signal handler is still
7946  * connected before disconnected it:
7947  *
7948  *  if (g_signal_handler_is_connected(instance, id))
7949  *    g_signal_handler_disconnect(instance, id);
7950  */
7951 static void
7952 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7953 {
7954         GList *sig_list = NULL;
7955         mmplayer_signal_item_t *item = NULL;
7956
7957         MMPLAYER_FENTER();
7958
7959         MMPLAYER_RETURN_IF_FAIL(player);
7960
7961         LOGD("release signals type : %d", type);
7962
7963         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7964                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7965                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7966                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7967                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7968                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7969                 return;
7970         }
7971
7972         sig_list = player->signals[type];
7973
7974         for (; sig_list; sig_list = sig_list->next) {
7975                 item = sig_list->data;
7976
7977                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7978                         if (g_signal_handler_is_connected(item->obj, item->sig))
7979                                 g_signal_handler_disconnect(item->obj, item->sig);
7980                 }
7981
7982                 MMPLAYER_FREEIF(item);
7983         }
7984
7985         g_list_free(player->signals[type]);
7986         player->signals[type] = NULL;
7987
7988         MMPLAYER_FLEAVE();
7989
7990         return;
7991 }
7992
7993 int
7994 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7995 {
7996         mmplayer_t *player = 0;
7997         int prev_display_surface_type = 0;
7998
7999         MMPLAYER_FENTER();
8000
8001         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8002
8003         player = MM_PLAYER_CAST(handle);
8004
8005         /* check video sinkbin is created */
8006         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8007                 LOGW("Videosink is already created");
8008                 return MM_ERROR_NONE;
8009         }
8010
8011         LOGD("videosink element is not yet ready");
8012
8013         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8014                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8015                 MMPLAYER_FLEAVE();
8016                 return MM_ERROR_INVALID_ARGUMENT;
8017         }
8018
8019         /* load previous attributes */
8020         if (player->attrs) {
8021                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8022                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8023                 if (prev_display_surface_type == surface_type) {
8024                         LOGD("incoming display surface type is same as previous one, do nothing..");
8025                         MMPLAYER_FLEAVE();
8026                         return MM_ERROR_NONE;
8027                 }
8028         } else {
8029                 LOGE("failed to load attributes");
8030                 MMPLAYER_FLEAVE();
8031                 return MM_ERROR_PLAYER_INTERNAL;
8032         }
8033
8034         /* videobin is not created yet, so we just set attributes related to display surface */
8035         LOGD("store display attribute for given surface type(%d)", surface_type);
8036         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8037                         "display_overlay", wl_surface_id, NULL);
8038
8039         MMPLAYER_FLEAVE();
8040         return MM_ERROR_NONE;
8041 }
8042
8043 /* Note : if silent is true, then subtitle would not be displayed. :*/
8044 int
8045 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8046 {
8047         mmplayer_t *player = (mmplayer_t *)hplayer;
8048
8049         MMPLAYER_FENTER();
8050
8051         /* check player handle */
8052         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8053
8054         player->set_mode.subtitle_off = silent;
8055
8056         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8057
8058         MMPLAYER_FLEAVE();
8059
8060         return MM_ERROR_NONE;
8061 }
8062
8063 int
8064 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8065 {
8066         mmplayer_gst_element_t *mainbin = NULL;
8067         mmplayer_gst_element_t *textbin = NULL;
8068         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8069         GstState current_state = GST_STATE_VOID_PENDING;
8070         GstState element_state = GST_STATE_VOID_PENDING;
8071         GstState element_pending_state = GST_STATE_VOID_PENDING;
8072         gint64 time = 0;
8073         GstEvent *event = NULL;
8074         int result = MM_ERROR_NONE;
8075
8076         GstClock *curr_clock = NULL;
8077         GstClockTime base_time, start_time, curr_time;
8078
8079
8080         MMPLAYER_FENTER();
8081
8082         /* check player handle */
8083         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8084                                                                 player->pipeline &&
8085                                                                 player->pipeline->mainbin &&
8086                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8087
8088         mainbin = player->pipeline->mainbin;
8089         textbin = player->pipeline->textbin;
8090
8091         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8092
8093         // sync clock with current pipeline
8094         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8095         curr_time = gst_clock_get_time(curr_clock);
8096
8097         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8098         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8099
8100         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8101                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8102
8103         if (current_state > GST_STATE_READY) {
8104                 // sync state with current pipeline
8105                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8106                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8107                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8108
8109                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8110                 if (GST_STATE_CHANGE_FAILURE == ret) {
8111                         LOGE("fail to state change.");
8112                         result = MM_ERROR_PLAYER_INTERNAL;
8113                         goto ERROR;
8114                 }
8115         }
8116         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8117         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8118
8119         if (curr_clock) {
8120                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8121                 gst_object_unref(curr_clock);
8122         }
8123
8124         // seek to current position
8125         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8126                 result = MM_ERROR_PLAYER_INVALID_STATE;
8127                 LOGE("gst_element_query_position failed, invalid state");
8128                 goto ERROR;
8129         }
8130
8131         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8132         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);
8133         if (event) {
8134                 _mmplayer_gst_send_event_to_sink(player, event);
8135         } else {
8136                 result = MM_ERROR_PLAYER_INTERNAL;
8137                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8138                 goto ERROR;
8139         }
8140
8141         /* sync state with current pipeline */
8142         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8143         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8144         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8145
8146         return MM_ERROR_NONE;
8147
8148 ERROR:
8149         /* release text pipeline resource */
8150         player->textsink_linked = 0;
8151
8152         /* release signal */
8153         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8154
8155         /* release textbin with it's childs */
8156         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8157         MMPLAYER_FREEIF(player->pipeline->textbin);
8158         player->pipeline->textbin = NULL;
8159
8160         /* release subtitle elem */
8161         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8162         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8163
8164         return result;
8165 }
8166
8167 static int
8168 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8169 {
8170         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8171         GstState current_state = GST_STATE_VOID_PENDING;
8172
8173         MMHandleType attrs = 0;
8174         mmplayer_gst_element_t *mainbin = NULL;
8175         mmplayer_gst_element_t *textbin = NULL;
8176
8177         gchar *subtitle_uri = NULL;
8178         int result = MM_ERROR_NONE;
8179         const gchar *charset = NULL;
8180
8181         MMPLAYER_FENTER();
8182
8183         /* check player handle */
8184         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8185                                                                 player->pipeline &&
8186                                                                 player->pipeline->mainbin &&
8187                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8188         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8189
8190         mainbin = player->pipeline->mainbin;
8191         textbin = player->pipeline->textbin;
8192
8193         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8194         if (current_state < GST_STATE_READY) {
8195                 result = MM_ERROR_PLAYER_INVALID_STATE;
8196                 LOGE("Pipeline is not in proper state");
8197                 goto EXIT;
8198         }
8199
8200         attrs = MMPLAYER_GET_ATTRS(player);
8201         if (!attrs) {
8202                 LOGE("cannot get content attribute");
8203                 result = MM_ERROR_PLAYER_INTERNAL;
8204                 goto EXIT;
8205         }
8206
8207         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8208         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8209                 LOGE("subtitle uri is not proper filepath");
8210                 result = MM_ERROR_PLAYER_INVALID_URI;
8211                 goto EXIT;
8212         }
8213
8214         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8215                 LOGE("failed to get storage info of subtitle path");
8216                 result = MM_ERROR_PLAYER_INVALID_URI;
8217                 goto EXIT;
8218         }
8219
8220         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8221         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8222
8223         if (!strcmp(filepath, subtitle_uri)) {
8224                 LOGD("subtitle path is not changed");
8225                 goto EXIT;
8226         } else {
8227                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8228                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8229                         LOGE("failed to set attribute");
8230                         goto EXIT;
8231                 }
8232         }
8233
8234         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8235         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8236         player->subtitle_language_list = NULL;
8237         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8238
8239         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8240         if (ret != GST_STATE_CHANGE_SUCCESS) {
8241                 LOGE("failed to change state of textbin to READY");
8242                 result = MM_ERROR_PLAYER_INTERNAL;
8243                 goto EXIT;
8244         }
8245
8246         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8247         if (ret != GST_STATE_CHANGE_SUCCESS) {
8248                 LOGE("failed to change state of subparse to READY");
8249                 result = MM_ERROR_PLAYER_INTERNAL;
8250                 goto EXIT;
8251         }
8252
8253         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8254         if (ret != GST_STATE_CHANGE_SUCCESS) {
8255                 LOGE("failed to change state of filesrc to READY");
8256                 result = MM_ERROR_PLAYER_INTERNAL;
8257                 goto EXIT;
8258         }
8259
8260         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8261
8262         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8263
8264         charset = _mmplayer_get_charset(filepath);
8265         if (charset) {
8266                 LOGD("detected charset is %s", charset);
8267                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8268         }
8269
8270         result = _mmplayer_sync_subtitle_pipeline(player);
8271
8272 EXIT:
8273         MMPLAYER_FLEAVE();
8274         return result;
8275 }
8276
8277 /* API to switch between external subtitles */
8278 int
8279 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8280 {
8281         int result = MM_ERROR_NONE;
8282         mmplayer_t *player = (mmplayer_t *)hplayer;
8283         char *path = NULL;
8284
8285         MMPLAYER_FENTER();
8286
8287         /* check player handle */
8288         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8289
8290         /* filepath can be null in idle state */
8291         if (filepath) {
8292                 /* check file path */
8293                 if ((path = strstr(filepath, "file://")))
8294                         result = _mmplayer_exist_file_path(path + 7);
8295                 else
8296                         result = _mmplayer_exist_file_path(filepath);
8297
8298                 if (result != MM_ERROR_NONE) {
8299                         LOGE("invalid subtitle path 0x%X", result);
8300                         return result; /* file not found or permission denied */
8301                 }
8302         }
8303
8304         if (!player->pipeline) {
8305                 /* IDLE state */
8306                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8307                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8308                         LOGE("failed to set attribute");
8309                         return MM_ERROR_PLAYER_INTERNAL;
8310                 }
8311         } else {
8312                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8313                 /* check filepath */
8314                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8315
8316                 if (!__mmplayer_check_subtitle(player)) {
8317                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8318                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8319                                 LOGE("failed to set attribute");
8320                                 return MM_ERROR_PLAYER_INTERNAL;
8321                         }
8322
8323                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8324                                 LOGE("fail to create text pipeline");
8325                                 return MM_ERROR_PLAYER_INTERNAL;
8326                         }
8327
8328                         result = _mmplayer_sync_subtitle_pipeline(player);
8329                 } else {
8330                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8331                 }
8332
8333                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8334                 player->is_external_subtitle_added_now = TRUE;
8335
8336                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8337                 if (!player->subtitle_language_list) {
8338                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8339                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8340                                 LOGW("subtitle language list is not updated yet");
8341                 }
8342                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8343         }
8344
8345         MMPLAYER_FLEAVE();
8346         return result;
8347 }
8348
8349 static int
8350 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8351 {
8352         guint active_idx = 0;
8353         GstStream *stream = NULL;
8354         GList *streams = NULL;
8355         GstEvent *ev = NULL;
8356         GstCaps *caps = NULL;
8357
8358         LOGD("Switching Streams... type: %d, index: %d", type, index);
8359
8360         player->track[type].active_track_index = index;
8361
8362         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8363                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8364                 if (player->track[i].total_track_num > 0) {
8365                         active_idx = player->track[i].active_track_index;
8366                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8367                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8368                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8369
8370                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8371                                 caps = gst_stream_get_caps(stream);
8372                                 if (caps) {
8373                                         _mmplayer_set_audio_attrs(player, caps);
8374                                         gst_caps_unref(caps);
8375                                 }
8376                         }
8377                 }
8378         }
8379
8380         ev = gst_event_new_select_streams(streams);
8381         gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8382         g_list_free(streams);
8383
8384         return MM_ERROR_NONE;
8385 }
8386
8387 static int
8388 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8389 {
8390         int result = MM_ERROR_NONE;
8391         gchar *change_pad_name = NULL;
8392         GstPad *sinkpad = NULL;
8393         mmplayer_gst_element_t *mainbin = NULL;
8394         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8395         GstCaps *caps = NULL;
8396         gint total_track_num = 0;
8397
8398         MMPLAYER_FENTER();
8399
8400         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8401                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8402
8403         LOGD("Change Track(%d) to %d", type, index);
8404
8405         mainbin = player->pipeline->mainbin;
8406
8407         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8408                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8409         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8410                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8411         } else {
8412                 /* Changing Video Track is not supported. */
8413                 LOGE("Track Type Error");
8414                 goto EXIT;
8415         }
8416
8417         if (mainbin[elem_idx].gst == NULL) {
8418                 result = MM_ERROR_PLAYER_NO_OP;
8419                 LOGD("Req track doesn't exist");
8420                 goto EXIT;
8421         }
8422
8423         total_track_num = player->track[type].total_track_num;
8424         if (total_track_num <= 0) {
8425                 result = MM_ERROR_PLAYER_NO_OP;
8426                 LOGD("Language list is not available");
8427                 goto EXIT;
8428         }
8429
8430         if ((index < 0) || (index >= total_track_num)) {
8431                 result = MM_ERROR_INVALID_ARGUMENT;
8432                 LOGD("Not a proper index : %d", index);
8433                 goto EXIT;
8434         }
8435
8436         /*To get the new pad from the selector*/
8437         change_pad_name = g_strdup_printf("sink_%u", index);
8438         if (change_pad_name == NULL) {
8439                 result = MM_ERROR_PLAYER_INTERNAL;
8440                 LOGD("Pad does not exists");
8441                 goto EXIT;
8442         }
8443
8444         LOGD("new active pad name: %s", change_pad_name);
8445
8446         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8447         if (sinkpad == NULL) {
8448                 LOGD("sinkpad is NULL");
8449                 result = MM_ERROR_PLAYER_INTERNAL;
8450                 goto EXIT;
8451         }
8452
8453         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8454         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8455
8456         caps = gst_pad_get_current_caps(sinkpad);
8457         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8458
8459         if (sinkpad)
8460                 gst_object_unref(sinkpad);
8461
8462         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8463                 _mmplayer_set_audio_attrs(player, caps);
8464
8465         if (caps)
8466                 gst_caps_unref(caps);
8467
8468 EXIT:
8469         MMPLAYER_FREEIF(change_pad_name);
8470         return result;
8471 }
8472
8473 int
8474 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8475 {
8476         int result = MM_ERROR_NONE;
8477         mmplayer_t *player = NULL;
8478         mmplayer_gst_element_t *mainbin = NULL;
8479
8480         gint current_active_index = 0;
8481
8482         GstState current_state = GST_STATE_VOID_PENDING;
8483         gint64 time = 0;
8484
8485         MMPLAYER_FENTER();
8486
8487         player = (mmplayer_t *)hplayer;
8488         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489
8490         if (!player->pipeline) {
8491                 LOGE("Track %d pre setting -> %d", type, index);
8492
8493                 player->track[type].active_track_index = index;
8494                 goto EXIT;
8495         }
8496
8497         mainbin = player->pipeline->mainbin;
8498
8499         current_active_index = player->track[type].active_track_index;
8500
8501         /*If index is same as running index no need to change the pad*/
8502         if (current_active_index == index)
8503                 goto EXIT;
8504
8505         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8506                 result = MM_ERROR_PLAYER_INVALID_STATE;
8507                 goto EXIT;
8508         }
8509
8510         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8511         if (current_state < GST_STATE_PAUSED) {
8512                 result = MM_ERROR_PLAYER_INVALID_STATE;
8513                 LOGW("Pipeline not in porper state");
8514                 goto EXIT;
8515         }
8516
8517         if (MMPLAYER_USE_DECODEBIN(player))
8518                 result = __mmplayer_change_selector_pad(player, type, index);
8519         else
8520                 result = __mmplayer_switch_stream(player, type, index);
8521
8522         if (result != MM_ERROR_NONE) {
8523                 LOGE("failed to change track");
8524                 goto EXIT;
8525         }
8526
8527         player->track[type].active_track_index = index;
8528
8529         if (MMPLAYER_USE_DECODEBIN(player)) {
8530                 GstEvent *event = NULL;
8531                 if (current_state == GST_STATE_PLAYING) {
8532                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8533                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8534                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8535                         if (event) {
8536                                 _mmplayer_gst_send_event_to_sink(player, event);
8537                         } else {
8538                                 result = MM_ERROR_PLAYER_INTERNAL;
8539                                 goto EXIT;
8540                         }
8541                 }
8542         }
8543
8544 EXIT:
8545         return result;
8546 }
8547
8548 int
8549 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8550 {
8551         mmplayer_t *player = (mmplayer_t *)hplayer;
8552
8553         MMPLAYER_FENTER();
8554
8555         /* check player handle */
8556         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8557
8558         *silent = player->set_mode.subtitle_off;
8559
8560         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8561
8562         MMPLAYER_FLEAVE();
8563
8564         return MM_ERROR_NONE;
8565 }
8566
8567 static gboolean
8568 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8569 {
8570         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8571         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8572
8573         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8574         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8575
8576         int idx = 0;
8577
8578         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8579                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8580                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8581                         mmplayer_dump_t *dump_s;
8582                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8583                         if (dump_s == NULL) {
8584                                 LOGE("malloc fail");
8585                                 return FALSE;
8586                         }
8587
8588                         dump_s->dump_element_file = NULL;
8589                         dump_s->dump_pad = NULL;
8590                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8591
8592                         if (dump_s->dump_pad) {
8593                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8594                                 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]);
8595                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8596                                 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);
8597                                 /* add list for removed buffer probe and close FILE */
8598                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8599                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8600                                 return TRUE;
8601                         } else {
8602                                 MMPLAYER_FREEIF(dump_s);
8603                                 LOGE("failed to get %s sink pad added", factory_name);
8604                         }
8605                 }
8606         }
8607         return FALSE;
8608 }
8609
8610 static GstPadProbeReturn
8611 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8612 {
8613         FILE *dump_data = (FILE *)u_data;
8614 //      int written = 0;
8615         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8616         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8617
8618         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8619
8620         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8621 #ifdef __DEBUG__
8622         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8623 #endif
8624         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8625
8626         gst_buffer_unmap(buffer, &probe_info);
8627
8628         return GST_PAD_PROBE_OK;
8629 }
8630
8631 static void
8632 __mmplayer_release_dump_list(GList *dump_list)
8633 {
8634         GList *d_list = dump_list;
8635
8636         if (!d_list)
8637                 return;
8638
8639         for (; d_list; d_list = g_list_next(d_list)) {
8640                 mmplayer_dump_t *dump_s = d_list->data;
8641                 if (dump_s->dump_pad) {
8642                         if (dump_s->probe_handle_id)
8643                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8644                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8645                 }
8646                 if (dump_s->dump_element_file) {
8647                         fclose(dump_s->dump_element_file);
8648                         dump_s->dump_element_file = NULL;
8649                 }
8650                 MMPLAYER_FREEIF(dump_s);
8651         }
8652         g_list_free(dump_list);
8653         dump_list = NULL;
8654 }
8655
8656 int
8657 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8658 {
8659         mmplayer_t *player = (mmplayer_t *)hplayer;
8660
8661         MMPLAYER_FENTER();
8662
8663         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8664         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8665
8666         *exist = (bool)player->has_closed_caption;
8667
8668         MMPLAYER_FLEAVE();
8669
8670         return MM_ERROR_NONE;
8671 }
8672
8673 void
8674 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8675 {
8676         MMPLAYER_FENTER();
8677         if (buffer) {
8678 #ifdef __DEBUG__
8679                 LOGD("unref internal gst buffer %p", buffer);
8680 #endif
8681                 gst_buffer_unref((GstBuffer *)buffer);
8682                 buffer = NULL;
8683         }
8684         MMPLAYER_FLEAVE();
8685 }
8686
8687 int
8688 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8689 {
8690         mmplayer_t *player = (mmplayer_t *)hplayer;
8691
8692         MMPLAYER_FENTER();
8693
8694         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8695         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8696
8697         if (MMPLAYER_IS_STREAMING(player))
8698                 *timeout = (int)player->ini.live_state_change_timeout;
8699         else
8700                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8701
8702         LOGD("timeout = %d", *timeout);
8703
8704         MMPLAYER_FLEAVE();
8705         return MM_ERROR_NONE;
8706 }
8707
8708 static void
8709 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8710 {
8711         int i = 0;
8712         MMPLAYER_FENTER();
8713         MMPLAYER_RETURN_IF_FAIL(player);
8714
8715         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8716
8717                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8718                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8719                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8720                         player->storage_info[i].id = -1;
8721                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8722
8723                         if (path_type != MMPLAYER_PATH_MAX)
8724                                 break;
8725                 }
8726         }
8727
8728         MMPLAYER_FLEAVE();
8729 }
8730
8731 int
8732 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8733 {
8734         int ret = MM_ERROR_NONE;
8735         mmplayer_t *player = (mmplayer_t *)hplayer;
8736         MMMessageParamType msg_param = {0, };
8737
8738         MMPLAYER_FENTER();
8739         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8740
8741         LOGW("state changed storage %d:%d", id, state);
8742
8743         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8744                 return MM_ERROR_NONE;
8745
8746         /* FIXME: text path should be handled seperately. */
8747         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8748                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8749                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8750                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8751                 LOGW("external storage is removed");
8752
8753                 if (player->msg_posted == FALSE) {
8754                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8755                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8756                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8757                         player->msg_posted = TRUE;
8758                 }
8759
8760                 /* unrealize the player */
8761                 ret = _mmplayer_unrealize(hplayer);
8762                 if (ret != MM_ERROR_NONE)
8763                         LOGE("failed to unrealize");
8764         }
8765
8766         MMPLAYER_FLEAVE();
8767         return ret;
8768 }
8769
8770 int
8771 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8772 {
8773         int ret = MM_ERROR_NONE;
8774         mmplayer_t *player = (mmplayer_t *)hplayer;
8775         int idx = 0, total = 0;
8776         gchar *result = NULL, *tmp = NULL;
8777
8778         MMPLAYER_FENTER();
8779         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8780         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8781
8782         total = *num = g_list_length(player->adaptive_info.var_list);
8783         if (total <= 0) {
8784                 LOGW("There is no stream variant info.");
8785                 return ret;
8786         }
8787
8788         result = g_strdup("");
8789         for (idx = 0 ; idx < total ; idx++) {
8790                 stream_variant_t *v_data = NULL;
8791                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8792
8793                 if (v_data) {
8794                         gchar data[64] = {0};
8795                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8796
8797                         tmp = g_strconcat(result, data, NULL);
8798                         g_free(result);
8799                         result = tmp;
8800                 } else {
8801                         LOGW("There is no variant data in %d", idx);
8802                         (*num)--;
8803                 }
8804         }
8805
8806         *var_info = (char *)result;
8807
8808         LOGD("variant info %d:%s", *num, *var_info);
8809         MMPLAYER_FLEAVE();
8810         return ret;
8811 }
8812
8813 int
8814 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8815 {
8816         int ret = MM_ERROR_NONE;
8817         mmplayer_t *player = (mmplayer_t *)hplayer;
8818
8819         MMPLAYER_FENTER();
8820         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8821
8822         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8823
8824         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8825         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8826         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8827
8828         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8829                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8830                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8831                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8832
8833                 /* FIXME: seek to current position for applying new variant limitation */
8834         }
8835
8836         MMPLAYER_FLEAVE();
8837         return ret;
8838
8839 }
8840
8841 int
8842 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8843 {
8844         int ret = MM_ERROR_NONE;
8845         mmplayer_t *player = (mmplayer_t *)hplayer;
8846
8847         MMPLAYER_FENTER();
8848         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8849         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8850
8851         *bandwidth = player->adaptive_info.limit.bandwidth;
8852         *width = player->adaptive_info.limit.width;
8853         *height = player->adaptive_info.limit.height;
8854
8855         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8856
8857         MMPLAYER_FLEAVE();
8858         return ret;
8859 }
8860
8861 int
8862 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8863 {
8864         int ret = MM_ERROR_NONE;
8865         mmplayer_t *player = (mmplayer_t *)hplayer;
8866
8867         MMPLAYER_FENTER();
8868         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8869         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8870         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8871
8872         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8873
8874         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8875                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8876         else /* live case */
8877                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8878
8879         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8880
8881         MMPLAYER_FLEAVE();
8882         return ret;
8883 }
8884
8885 int
8886 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8887 {
8888 #define IDX_FIRST_SW_CODEC 0
8889         mmplayer_t *player = (mmplayer_t *)hplayer;
8890         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8891         const char *attr_name = NULL;
8892         const char *default_type = NULL;
8893         const char *element_hw = NULL;
8894         const char *element_sw = NULL;
8895
8896         MMPLAYER_FENTER();
8897         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8898
8899         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8900
8901         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8902         switch (stream_type) {
8903         case MM_PLAYER_STREAM_TYPE_AUDIO:
8904                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8905                 default_type = player->ini.audiocodec_default_type;
8906                 element_hw = player->ini.audiocodec_element_hw;
8907                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8908                 break;
8909         case MM_PLAYER_STREAM_TYPE_VIDEO:
8910                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8911                 default_type = player->ini.videocodec_default_type;
8912                 element_hw = player->ini.videocodec_element_hw;
8913                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8914                 break;
8915         default:
8916                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8917                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8918                 break;
8919         }
8920
8921         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8922
8923         if (!strcmp(default_type, "sw"))
8924                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8925         else
8926                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8927
8928         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8929                 codec_type = default_codec_type;
8930
8931         /* to support codec selection, codec info have to be added in ini file.
8932            in case of hw codec is selected, filter elements should be applied
8933            depending on the hw capabilities. */
8934         if (codec_type != default_codec_type) {
8935                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8936                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8937                         LOGE("There is no codec for type %d", codec_type);
8938                         return MM_ERROR_PLAYER_NO_OP;
8939                 }
8940
8941                 LOGD("sorting is required");
8942                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8943                         player->need_audio_dec_sorting = TRUE;
8944                 else
8945                         player->need_video_dec_sorting = TRUE;
8946         }
8947
8948         LOGD("update %s codec_type to %d", attr_name, codec_type);
8949         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8950
8951         MMPLAYER_FLEAVE();
8952         return MM_ERROR_NONE;
8953 }
8954
8955 int
8956 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8957 {
8958         mmplayer_t *player = (mmplayer_t *)hplayer;
8959         GstElement *rg_vol_element = NULL;
8960
8961         MMPLAYER_FENTER();
8962
8963         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8964
8965         player->sound.rg_enable = enabled;
8966
8967         /* just hold rgvolume enable value if pipeline is not ready */
8968         if (!player->pipeline || !player->pipeline->audiobin) {
8969                 LOGD("pipeline is not ready. holding rgvolume enable value");
8970                 return MM_ERROR_NONE;
8971         }
8972
8973         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8974
8975         if (!rg_vol_element) {
8976                 LOGD("rgvolume element is not created");
8977                 return MM_ERROR_PLAYER_INTERNAL;
8978         }
8979
8980         if (enabled)
8981                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8982         else
8983                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8984
8985         MMPLAYER_FLEAVE();
8986
8987         return MM_ERROR_NONE;
8988 }
8989
8990 int
8991 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8992 {
8993         mmplayer_t *player = (mmplayer_t *)hplayer;
8994         GstElement *rg_vol_element = NULL;
8995         gboolean enable = FALSE;
8996
8997         MMPLAYER_FENTER();
8998
8999         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9000         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9001
9002         /* just hold enable_rg value if pipeline is not ready */
9003         if (!player->pipeline || !player->pipeline->audiobin) {
9004                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9005                 *enabled = player->sound.rg_enable;
9006                 return MM_ERROR_NONE;
9007         }
9008
9009         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9010
9011         if (!rg_vol_element) {
9012                 LOGD("rgvolume element is not created");
9013                 return MM_ERROR_PLAYER_INTERNAL;
9014         }
9015
9016         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9017         *enabled = (bool)enable;
9018
9019         MMPLAYER_FLEAVE();
9020
9021         return MM_ERROR_NONE;
9022 }
9023
9024 int
9025 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9026 {
9027         mmplayer_t *player = (mmplayer_t *)hplayer;
9028         MMHandleType attrs = 0;
9029         int handle = 0;
9030         int ret = MM_ERROR_NONE;
9031
9032         MMPLAYER_FENTER();
9033
9034         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9035
9036         attrs = MMPLAYER_GET_ATTRS(player);
9037         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9038
9039         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9040         if (!handle) {
9041                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9042                 return MM_ERROR_PLAYER_INTERNAL;
9043         }
9044
9045         player->video_roi.scale_x = scale_x;
9046         player->video_roi.scale_y = scale_y;
9047         player->video_roi.scale_width = scale_width;
9048         player->video_roi.scale_height = scale_height;
9049
9050         /* check video sinkbin is created */
9051         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9052                 return MM_ERROR_NONE;
9053
9054         if (!gst_video_overlay_set_video_roi_area(
9055                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9056                 scale_x, scale_y, scale_width, scale_height))
9057                 ret = MM_ERROR_PLAYER_INTERNAL;
9058         else
9059                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9060                         scale_x, scale_y, scale_width, scale_height);
9061
9062         MMPLAYER_FLEAVE();
9063
9064         return ret;
9065 }
9066
9067 int
9068 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9069 {
9070         mmplayer_t *player = (mmplayer_t *)hplayer;
9071         int ret = MM_ERROR_NONE;
9072
9073         MMPLAYER_FENTER();
9074
9075         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9077
9078         *scale_x = player->video_roi.scale_x;
9079         *scale_y = player->video_roi.scale_y;
9080         *scale_width = player->video_roi.scale_width;
9081         *scale_height = player->video_roi.scale_height;
9082
9083         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9084                 *scale_x, *scale_y, *scale_width, *scale_height);
9085
9086         return ret;
9087 }
9088
9089 int
9090 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9091 {
9092         mmplayer_t *player = (mmplayer_t *)hplayer;
9093
9094         MMPLAYER_FENTER();
9095
9096         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9097
9098         player->client_pid = pid;
9099
9100         LOGD("client pid[%d] %p", pid, player);
9101
9102         MMPLAYER_FLEAVE();
9103
9104         return MM_ERROR_NONE;
9105 }
9106
9107 int
9108 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9109 {
9110         mmplayer_t *player = (mmplayer_t *)hplayer;
9111         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9112         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9113
9114         MMPLAYER_FENTER();
9115
9116         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9117         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9118
9119         *available = true;
9120         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9121
9122         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9123
9124         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9125                 return MM_ERROR_NONE;
9126
9127         /* in case of audio codec default type is HW */
9128         switch(opt) {
9129                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9130                         if (player->ini.support_audio_effect)
9131                                 return MM_ERROR_NONE;
9132                         elem_id = MMPLAYER_A_FILTER;
9133                 break;
9134                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9135                         if (player->ini.support_replaygain_control)
9136                                 return MM_ERROR_NONE;
9137                         elem_id = MMPLAYER_A_RGVOL;
9138                 break;
9139                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9140                         if (player->ini.support_pitch_control)
9141                                 return MM_ERROR_NONE;
9142                         elem_id = MMPLAYER_A_PITCH;
9143                 break;
9144                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9145                         if (player->ini.support_audio_effect)
9146                                 return MM_ERROR_NONE;
9147                 break;
9148                 /* default case handling is not required */
9149         }
9150
9151         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9152                 LOGW("audio control option [%d] is not available", opt);
9153                 *available = false;
9154         } else {
9155                 /* setting pcm exporting option is allowed before READY state */
9156                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9157                         return MM_ERROR_PLAYER_INVALID_STATE;
9158
9159                 /* check whether the audio filter exist or not after READY state,
9160                    because the sw codec could be added during auto-plugging in some cases */
9161                 if (!player->pipeline ||
9162                         !player->pipeline->audiobin ||
9163                         !player->pipeline->audiobin[elem_id].gst) {
9164                         LOGW("there is no audio elem [%d]", elem_id);
9165                         *available = false;
9166                 }
9167         }
9168
9169         LOGD("audio control opt %d, available %d", opt, *available);
9170
9171         MMPLAYER_FLEAVE();
9172
9173         return MM_ERROR_NONE;
9174 }
9175
9176 static gboolean
9177 __mmplayer_update_duration_value(mmplayer_t *player)
9178 {
9179         gboolean ret = FALSE;
9180         gint64 dur_nsec = 0;
9181         LOGD("try to update duration");
9182
9183         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9184                 player->duration = dur_nsec;
9185                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9186                 ret = TRUE;
9187         }
9188
9189         if (player->duration < 0) {
9190                 LOGW("duration is Non-Initialized !!!");
9191                 player->duration = 0;
9192         }
9193
9194         /* update streaming service type */
9195         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9196
9197         /* check duration is OK */
9198         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9199                 /* FIXIT : find another way to get duration here. */
9200                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9201
9202         return ret;
9203 }
9204
9205 static gboolean
9206 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9207 {
9208         /* update audio params
9209         NOTE : We need original audio params and it can be only obtained from src pad of audio
9210         decoder. Below code only valid when we are not using 'resampler' just before
9211         'audioconverter'. */
9212         GstCaps *caps_a = NULL;
9213         GstPad *pad = NULL;
9214         gint samplerate = 0, channels = 0;
9215         GstStructure *p = NULL;
9216         GstElement *aconv = NULL;
9217
9218         LOGD("try to update audio attrs");
9219
9220         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9221
9222         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9223                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9224         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9225                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9226         } else {
9227                 LOGE("there is no audio converter");
9228                 return FALSE;
9229         }
9230
9231         pad = gst_element_get_static_pad(aconv, "sink");
9232
9233         if (!pad) {
9234                 LOGW("failed to get pad from audio converter");
9235                 return FALSE;
9236         }
9237
9238         caps_a = gst_pad_get_current_caps(pad);
9239         if (!caps_a) {
9240                 LOGW("not ready to get audio caps");
9241                 gst_object_unref(pad);
9242                 return FALSE;
9243         }
9244
9245         p = gst_caps_get_structure(caps_a, 0);
9246
9247         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9248
9249         gst_structure_get_int(p, "rate", &samplerate);
9250         gst_structure_get_int(p, "channels", &channels);
9251
9252         mm_player_set_attribute((MMHandleType)player, NULL,
9253                         "content_audio_samplerate", samplerate,
9254                         "content_audio_channels", channels, NULL);
9255
9256         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9257
9258         gst_caps_unref(caps_a);
9259         gst_object_unref(pad);
9260
9261         return TRUE;
9262 }
9263
9264 static gboolean
9265 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9266 {
9267         LOGD("try to update video attrs");
9268
9269         GstCaps *caps_v = NULL;
9270         GstPad *pad = NULL;
9271         gint tmpNu, tmpDe;
9272         gint width, height;
9273         GstStructure *p = NULL;
9274
9275         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9276         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9277
9278         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9279         if (!pad) {
9280                 LOGD("no videosink sink pad");
9281                 return FALSE;
9282         }
9283
9284         caps_v = gst_pad_get_current_caps(pad);
9285         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9286         if (!caps_v && player->v_stream_caps) {
9287                 caps_v = player->v_stream_caps;
9288                 gst_caps_ref(caps_v);
9289         }
9290
9291         if (!caps_v) {
9292                 LOGD("no negitiated caps from videosink");
9293                 gst_object_unref(pad);
9294                 return FALSE;
9295         }
9296
9297         p = gst_caps_get_structure(caps_v, 0);
9298         gst_structure_get_int(p, "width", &width);
9299         gst_structure_get_int(p, "height", &height);
9300
9301         mm_player_set_attribute((MMHandleType)player, NULL,
9302                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9303
9304         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9305
9306         SECURE_LOGD("width : %d     height : %d", width, height);
9307
9308         gst_caps_unref(caps_v);
9309         gst_object_unref(pad);
9310
9311         if (tmpDe > 0) {
9312                 mm_player_set_attribute((MMHandleType)player, NULL,
9313                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9314                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9315         }
9316
9317         return TRUE;
9318 }
9319
9320 static gboolean
9321 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9322 {
9323         gboolean ret = FALSE;
9324         guint64 data_size = 0;
9325         gchar *path = NULL;
9326         struct stat sb;
9327
9328         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9329         if (!player->duration)
9330                 return FALSE;
9331
9332         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9333                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9334                 if (stat(path, &sb) == 0)
9335                         data_size = (guint64)sb.st_size;
9336
9337         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9338                 data_size = player->http_content_size;
9339         }
9340
9341         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9342
9343         if (data_size) {
9344                 guint64 bitrate = 0;
9345                 guint64 msec_dur = 0;
9346
9347                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9348                 if (msec_dur > 0) {
9349                         bitrate = data_size * 8 * 1000 / msec_dur;
9350                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9351                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9352                         mm_player_set_attribute((MMHandleType)player, NULL,
9353                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9354                         ret = TRUE;
9355                 } else {
9356                         LOGD("player duration is less than 0");
9357                 }
9358         }
9359
9360         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9361                 if (player->total_bitrate) {
9362                         mm_player_set_attribute((MMHandleType)player, NULL,
9363                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9364                         ret = TRUE;
9365                 }
9366         }
9367
9368         return ret;
9369 }
9370
9371 static void
9372 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9373 {
9374         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9375         data->uri_type = uri_type;
9376 }
9377
9378 static int
9379 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9380 {
9381         int ret = MM_ERROR_PLAYER_INVALID_URI;
9382         int mem_size = 0;
9383         char *buffer = NULL;
9384         char *seperator = strchr(path, ',');
9385         char ext[100] = {0,}, size[100] = {0,};
9386
9387         if (seperator) {
9388                 if ((buffer = strstr(path, "ext="))) {
9389                         buffer += strlen("ext=");
9390
9391                         if (strlen(buffer)) {
9392                                 strncpy(ext, buffer, 99);
9393
9394                                 if ((seperator = strchr(ext, ','))
9395                                         || (seperator = strchr(ext, ' '))
9396                                         || (seperator = strchr(ext, '\0'))) {
9397                                         seperator[0] = '\0';
9398                                 }
9399                         }
9400                 }
9401
9402                 if ((buffer = strstr(path, "size="))) {
9403                         buffer += strlen("size=");
9404
9405                         if (strlen(buffer) > 0) {
9406                                 strncpy(size, buffer, 99);
9407
9408                                 if ((seperator = strchr(size, ','))
9409                                         || (seperator = strchr(size, ' '))
9410                                         || (seperator = strchr(size, '\0'))) {
9411                                         seperator[0] = '\0';
9412                                 }
9413
9414                                 mem_size = atoi(size);
9415                         }
9416                 }
9417         }
9418
9419         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9420
9421         if (mem_size && param) {
9422                 if (data->input_mem.buf)
9423                         free(data->input_mem.buf);
9424                 data->input_mem.buf = malloc(mem_size);
9425
9426                 if (data->input_mem.buf) {
9427                         memcpy(data->input_mem.buf, param, mem_size);
9428                         data->input_mem.len = mem_size;
9429                         ret = MM_ERROR_NONE;
9430                 } else {
9431                         LOGE("failed to alloc mem %d", mem_size);
9432                         ret = MM_ERROR_PLAYER_INTERNAL;
9433                 }
9434
9435                 data->input_mem.offset = 0;
9436                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9437         }
9438
9439         return ret;
9440 }
9441
9442 static int
9443 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9444 {
9445         gchar *location = NULL;
9446         GError *err = NULL;
9447         char *path = NULL;
9448         int ret = MM_ERROR_NONE;
9449
9450         if ((path = strstr(uri, "file://"))) {
9451                 location = g_filename_from_uri(uri, NULL, &err);
9452                 if (!location || (err != NULL)) {
9453                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9454                                 (err != NULL) ? err->message : "unknown error");
9455                         if (err)
9456                                 g_error_free(err);
9457
9458                         MMPLAYER_FREEIF(location);
9459
9460                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9461                         return MM_ERROR_PLAYER_INVALID_URI;
9462                 }
9463                 LOGD("path from uri: %s", location);
9464         }
9465
9466         path = (location != NULL) ? (location) : ((char *)uri);
9467
9468
9469         ret = _mmplayer_exist_file_path(path);
9470
9471         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9472         if (ret == MM_ERROR_NONE) {
9473                 if (_mmplayer_is_sdp_file(path)) {
9474                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9475                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9476                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9477                 } else {
9478                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9479                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9480                 }
9481         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9482                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9483         } else {
9484                 LOGE("invalid uri, could not play..");
9485                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9486         }
9487
9488         MMPLAYER_FREEIF(location);
9489
9490         return ret;
9491 }
9492
9493 static mmplayer_video_decoded_data_info_t *
9494 __mmplayer_create_stream_from_pad(GstPad *pad)
9495 {
9496         GstCaps *caps = NULL;
9497         GstStructure *structure = NULL;
9498         unsigned int fourcc = 0;
9499         const gchar *string_format = NULL;
9500         mmplayer_video_decoded_data_info_t *stream = NULL;
9501         gint width, height;
9502         MMPixelFormatType format;
9503         GstVideoInfo info;
9504
9505         caps = gst_pad_get_current_caps(pad);
9506         if (!caps) {
9507                 LOGE("Caps is NULL.");
9508                 return NULL;
9509         }
9510
9511 #ifdef __DEBUG__
9512         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9513 #endif
9514         structure = gst_caps_get_structure(caps, 0);
9515         gst_structure_get_int(structure, "width", &width);
9516         gst_structure_get_int(structure, "height", &height);
9517         string_format = gst_structure_get_string(structure, "format");
9518
9519         if (string_format)
9520                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9521         format = _mmplayer_get_pixtype(fourcc);
9522         gst_video_info_from_caps(&info, caps);
9523         gst_caps_unref(caps);
9524
9525         /* moved here */
9526         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9527                 LOGE("Wrong condition!!");
9528                 return NULL;
9529         }
9530
9531         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9532         if (!stream) {
9533                 LOGE("failed to alloc mem for video data");
9534                 return NULL;
9535         }
9536
9537         stream->width = width;
9538         stream->height = height;
9539         stream->format = format;
9540         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9541
9542         return stream;
9543 }
9544
9545 static void
9546 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9547 {
9548         unsigned int pitch = 0;
9549         unsigned int size = 0;
9550         int index = 0;
9551         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9552         tbm_bo bo = NULL;
9553
9554         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9555                 bo = gst_tizen_memory_get_bos(mem, index);
9556                 if (bo)
9557                         stream->bo[index] = tbm_bo_ref(bo);
9558                 else
9559                         LOGE("failed to get bo for index %d", index);
9560         }
9561
9562         for (index = 0; index < stream->plane_num; index++) {
9563                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9564                 stream->stride[index] = pitch;
9565                 if (pitch)
9566                         stream->elevation[index] = size / pitch;
9567                 else
9568                         stream->elevation[index] = stream->height;
9569         }
9570 }
9571
9572 static gboolean
9573 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9574 {
9575         if (stream->format == MM_PIXEL_FORMAT_I420) {
9576                 int ret = TBM_SURFACE_ERROR_NONE;
9577                 tbm_surface_h surface;
9578                 tbm_surface_info_s info;
9579
9580                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9581
9582                 ret = tbm_surface_get_info(surface, &info);
9583                 if (ret != TBM_SURFACE_ERROR_NONE) {
9584                         tbm_surface_destroy(surface);
9585                         return FALSE;
9586                 }
9587
9588                 tbm_surface_destroy(surface);
9589                 stream->stride[0] = info.planes[0].stride;
9590                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9591                 stream->stride[1] = info.planes[1].stride;
9592                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9593                 stream->stride[2] = info.planes[2].stride;
9594                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9595                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9596         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9597                 stream->stride[0] = stream->width * 4;
9598                 stream->elevation[0] = stream->height;
9599                 stream->bo_size = stream->stride[0] * stream->height;
9600         } else {
9601                 LOGE("Not support format %d", stream->format);
9602                 return FALSE;
9603         }
9604
9605         return TRUE;
9606 }
9607
9608 static gboolean
9609 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9610 {
9611         tbm_bo_handle thandle;
9612         gboolean is_mapped;
9613         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9614         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9615         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9616         int i = 0;
9617         int j = 0;
9618         int k = 0;
9619         unsigned char *src = NULL;
9620         unsigned char *dest = NULL;
9621         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9622
9623         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9624         if (!is_mapped) {
9625                 LOGE("fail to gst_memory_map");
9626                 return FALSE;
9627         }
9628
9629         if (!mapinfo.data) {
9630                 LOGE("data pointer is wrong");
9631                 goto ERROR;
9632         }
9633
9634         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9635         if (!stream->bo[0]) {
9636                 LOGE("Fail to tbm_bo_alloc!!");
9637                 goto ERROR;
9638         }
9639
9640         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9641         if (!thandle.ptr) {
9642                 LOGE("thandle pointer is wrong");
9643                 goto ERROR;
9644         }
9645
9646         if (stream->format == MM_PIXEL_FORMAT_I420) {
9647                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9648                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9649                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9650                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9651
9652                 dest_offset[0] = 0;
9653                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9654                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9655
9656                 for (i = 0; i < 3; i++) {
9657                         src = mapinfo.data + src_offset[i];
9658                         dest = thandle.ptr + dest_offset[i];
9659
9660                         if (i > 0)
9661                                 k = 1;
9662
9663                         for (j = 0; j < stream->height >> k; j++) {
9664                                 memcpy(dest, src, stream->width>>k);
9665                                 src += src_stride[i];
9666                                 dest += stream->stride[i];
9667                         }
9668                 }
9669         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9670                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9671         } else {
9672                 LOGE("Not support format %d", stream->format);
9673                 goto ERROR;
9674         }
9675
9676         tbm_bo_unmap(stream->bo[0]);
9677         gst_memory_unmap(mem, &mapinfo);
9678
9679         return TRUE;
9680
9681 ERROR:
9682         if (stream->bo[0])
9683                 tbm_bo_unmap(stream->bo[0]);
9684
9685         if (is_mapped)
9686                 gst_memory_unmap(mem, &mapinfo);
9687
9688         return FALSE;
9689 }
9690
9691 static void
9692 __mmplayer_set_pause_state(mmplayer_t *player)
9693 {
9694         if (player->sent_bos)
9695                 return;
9696
9697         /* rtsp case, get content attrs by GstMessage */
9698         if (MMPLAYER_IS_RTSP_STREAMING(player))
9699                 return;
9700
9701         /* it's first time to update all content attrs. */
9702         _mmplayer_update_content_attrs(player, ATTR_ALL);
9703 }
9704
9705 static void
9706 __mmplayer_set_playing_state(mmplayer_t *player)
9707 {
9708         gchar *audio_codec = NULL;
9709
9710         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9711                 /* initialize because auto resume is done well. */
9712                 player->resumed_by_rewind = FALSE;
9713                 player->playback_rate = 1.0;
9714         }
9715
9716         if (player->sent_bos)
9717                 return;
9718
9719         /* try to get content metadata */
9720
9721         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9722          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9723          * legacy mmfw-player api
9724          */
9725         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9726
9727         if ((player->cmd == MMPLAYER_COMMAND_START)
9728                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9729                 __mmplayer_handle_missed_plugin(player);
9730         }
9731
9732         /* check audio codec field is set or not
9733          * we can get it from typefinder or codec's caps.
9734          */
9735         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9736
9737         /* The codec format can't be sent for audio only case like amr, mid etc.
9738          * Because, parser don't make related TAG.
9739          * So, if it's not set yet, fill it with found data.
9740          */
9741         if (!audio_codec) {
9742                 if (g_strrstr(player->type, "audio/midi"))
9743                         audio_codec = "MIDI";
9744                 else if (g_strrstr(player->type, "audio/x-amr"))
9745                         audio_codec = "AMR";
9746                 else if (g_strrstr(player->type, "audio/mpeg")
9747                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9748                         audio_codec = "AAC";
9749                 else
9750                         audio_codec = "unknown";
9751
9752                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9753                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9754                         LOGE("failed to set attribute");
9755
9756                 LOGD("set audio codec type with caps");
9757         }
9758
9759         return;
9760 }