[0.2.222] Add concat element for gapless playback
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <sys/time.h>
36 #include <stdlib.h>
37 #include <dlog.h>
38 #include <gio/gio.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_sound.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
56
57 /*===========================================================================================
58 |                                                                                                                                                                                       |
59 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
60 |                                                                                                                                                                                       |
61 ========================================================================================== */
62
63 /*---------------------------------------------------------------------------
64 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
65 ---------------------------------------------------------------------------*/
66
67 /*---------------------------------------------------------------------------
68 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
69 ---------------------------------------------------------------------------*/
70
71 /*---------------------------------------------------------------------------
72 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
73 ---------------------------------------------------------------------------*/
74
75 /*---------------------------------------------------------------------------
76 |    LOCAL #defines:                                                                                                            |
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
80
81 #define MM_VOLUME_FACTOR_DEFAULT                1.0
82 #define MM_VOLUME_FACTOR_MIN                    0
83 #define MM_VOLUME_FACTOR_MAX                    1.0
84
85 /* Don't need to sleep for sound fadeout
86  * fadeout related 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                 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1363
1364 DONE:
1365 ERROR:
1366
1367         if (caps)
1368                 gst_caps_unref(caps);
1369
1370         if (sinkpad) {
1371                 gst_object_unref(GST_OBJECT(sinkpad));
1372                 sinkpad = NULL;
1373         }
1374
1375         return;
1376 }
1377
1378 static gboolean
1379 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1380 {
1381         GstPad *srcpad = NULL;
1382
1383         MMPLAYER_FENTER();
1384         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1385
1386         LOGD("type %d", type);
1387
1388         if (!combiner) {
1389                 LOGD("there is no %d track", type);
1390                 return TRUE;
1391         }
1392
1393         srcpad = gst_element_get_static_pad(combiner, "src");
1394         if (!srcpad) {
1395                 LOGE("failed to get srcpad from combiner");
1396                 return FALSE;
1397         }
1398
1399         LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1400
1401         __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1402
1403         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1404         if (player->track[type].block_id) {
1405                 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1406                 player->track[type].block_id = 0;
1407         }
1408
1409         if (srcpad) {
1410                 gst_object_unref(GST_OBJECT(srcpad));
1411                 srcpad = NULL;
1412         }
1413
1414         MMPLAYER_FLEAVE();
1415         return TRUE;
1416 }
1417
1418 static void
1419 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1420 {
1421         gint active_index = 0;
1422
1423         MMPLAYER_FENTER();
1424         MMPLAYER_RETURN_IF_FAIL(player);
1425
1426         LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1427
1428         /* change track to active pad */
1429         active_index = player->track[type].active_track_index;
1430         if ((active_index != DEFAULT_TRACK) &&
1431                 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1432                 LOGW("failed to change %d type track to %d", type, active_index);
1433                 player->track[type].active_track_index = DEFAULT_TRACK;
1434                 return;
1435         }
1436
1437         if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1438                 mm_player_set_attribute((MMHandleType)player, NULL,
1439                                 "content_text_track_num", player->track[type].total_track_num,
1440                                 "current_text_track_index", player->track[type].active_track_index, NULL);
1441
1442         MMPLAYER_FLEAVE();
1443         return;
1444 }
1445
1446 static gboolean
1447 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1448 {
1449         MMPLAYER_FENTER();
1450         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1451
1452         if (!audio_selector) {
1453                 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1454
1455                 /* in case the source is changed, output can be changed. */
1456                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1457                         LOGD("remove previous audiobin if it exist");
1458
1459                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1460                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1461
1462                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1463                         MMPLAYER_FREEIF(player->pipeline->audiobin);
1464                 }
1465
1466                 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1467                         _mmplayer_pipeline_complete(NULL, player);
1468
1469                 return TRUE;
1470         }
1471
1472         /* apply the audio track information */
1473         if (MMPLAYER_USE_DECODEBIN(player))
1474                 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1475
1476         /* create audio sink path */
1477         if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1478                 LOGE("failed to create audio sink path");
1479                 return FALSE;
1480         }
1481
1482         MMPLAYER_FLEAVE();
1483         return TRUE;
1484 }
1485
1486 static gboolean
1487 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1488 {
1489         MMPLAYER_FENTER();
1490         MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1491
1492         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1493                 LOGD("text path is not supproted");
1494                 return TRUE;
1495         }
1496
1497         /* apply the text track information */
1498         __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1499
1500         if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1501                 player->has_closed_caption = TRUE;
1502
1503         /* create text decode path */
1504         player->no_more_pad = TRUE;
1505
1506         if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1507                 LOGE("failed to create text sink path");
1508                 return FALSE;
1509         }
1510
1511         MMPLAYER_FLEAVE();
1512         return TRUE;
1513 }
1514
1515 static gboolean
1516 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1517 {
1518         gint64 dur_bytes = 0L;
1519
1520         MMPLAYER_FENTER();
1521         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1522                 player->pipeline->mainbin && player->streamer, FALSE);
1523
1524         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1525                 LOGE("fail to get duration.");
1526
1527         /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1528          * use file information was already set on Q2 when it was created. */
1529         _mm_player_streaming_set_queue2(player->streamer,
1530                                         player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1531                                         TRUE,                                                           /* use_buffering */
1532                                         MUXED_BUFFER_TYPE_MAX,                          /* use previous buffer type setting */
1533                                         ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1534
1535         MMPLAYER_FLEAVE();
1536         return TRUE;
1537 }
1538
1539 void
1540 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1541 {
1542         mmplayer_t *player = NULL;
1543         GstElement *video_selector = NULL;
1544         GstElement *audio_selector = NULL;
1545         GstElement *text_selector = NULL;
1546
1547         MMPLAYER_FENTER();
1548         player = (mmplayer_t *)data;
1549
1550         LOGD("no-more-pad signal handling");
1551
1552         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1553                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1554                 LOGW("player is shutting down");
1555                 goto EXIT;
1556         }
1557
1558         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1559                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1560                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1561                 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1562                         LOGE("failed to set queue2 buffering");
1563                         goto EXIT;
1564                 }
1565         }
1566
1567         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1568         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1569         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1570
1571         if (!video_selector && !audio_selector && !text_selector) {
1572                 LOGW("there is no selector");
1573                 player->no_more_pad = TRUE;
1574                 goto EXIT;
1575         }
1576
1577         /* create video path followed by video-select */
1578         if (video_selector && !audio_selector && !text_selector)
1579                 player->no_more_pad = TRUE;
1580
1581         if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1582                 goto EXIT;
1583
1584         /* create audio path followed by audio-select */
1585         if (audio_selector && !text_selector)
1586                 player->no_more_pad = TRUE;
1587
1588         if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1589                 goto EXIT;
1590
1591         /* create text path followed by text-select */
1592         __mmplayer_create_text_sink_path(player, text_selector);
1593
1594 EXIT:
1595         _mmplayer_set_reconfigure_state(player, FALSE);
1596         MMPLAYER_FLEAVE();
1597 }
1598
1599 static gboolean
1600 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1601 {
1602         gboolean ret = FALSE;
1603         GstElement *pipeline = NULL;
1604         GstPad *sinkpad = NULL;
1605
1606         MMPLAYER_FENTER();
1607         MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1608         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1609
1610         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1611
1612         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1613         if (!sinkpad) {
1614                 LOGE("failed to get pad from sinkbin");
1615                 goto EXIT;
1616         }
1617
1618         if (reusing) {
1619                 /* link only */
1620                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1621                         LOGE("failed to link sinkbin for reusing");
1622                         goto EXIT; /* exit either pass or fail */
1623                 }
1624         } else {
1625                 /* warm up */
1626                 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1627                         LOGE("failed to set state(READY) to sinkbin");
1628                         goto EXIT;
1629                 }
1630
1631                 /* add */
1632                 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1633                         LOGE("failed to add sinkbin to pipeline");
1634                         goto EXIT;
1635                 }
1636
1637                 /* link */
1638                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1639                         LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1640                         goto EXIT;
1641                 }
1642
1643                 /* run */
1644                 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1645                         LOGE("failed to set state(PAUSED) to sinkbin");
1646                         goto EXIT;
1647                 }
1648         }
1649
1650         ret = TRUE;
1651
1652 EXIT:
1653         if (sinkpad)
1654                 gst_object_unref(GST_OBJECT(sinkpad));
1655         sinkpad = NULL;
1656
1657         MMPLAYER_FLEAVE();
1658         return ret;
1659 }
1660
1661 static void
1662 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1663 {
1664         mmplayer_t *player = NULL;
1665         GstCaps *caps = NULL;
1666         gchar *caps_str = NULL;
1667         GstStructure *str = NULL;
1668         const gchar *name = NULL;
1669         GstElement *sinkbin = NULL;
1670         gboolean reusing = FALSE;
1671         gboolean caps_ret = TRUE;
1672         gchar *sink_pad_name = "sink";
1673
1674         /* check handles */
1675         player = (mmplayer_t *)data;
1676
1677         MMPLAYER_FENTER();
1678         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1679         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1680         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1681         if (!caps_ret) {
1682                 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1683                 if (!caps_ret)
1684                         goto ERROR;
1685
1686                 caps = gst_caps_ref(ref_caps);
1687         }
1688
1689         caps_str = gst_caps_to_string(caps);
1690 #ifdef __DEBUG__
1691         LOGD("detected mimetype : %s", name);
1692 #endif
1693         if (strstr(name, "audio")) {
1694                 if (player->pipeline->audiobin == NULL) {
1695                         const gchar *audio_format = gst_structure_get_string(str, "format");
1696                         if (audio_format) {
1697                                 LOGD("original audio format %s", audio_format);
1698                                 mm_player_set_attribute((MMHandleType)player, NULL,
1699                                                 "content_audio_format", audio_format, strlen(audio_format), NULL);
1700                         }
1701
1702                         if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1703                                 LOGE("failed to create audiobin. continuing without audio");
1704                                 goto ERROR;
1705                         }
1706
1707                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1708                         LOGD("creating audiobin success");
1709                 } else {
1710                         reusing = TRUE;
1711                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1712                         LOGD("reusing audiobin");
1713                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1714                 }
1715         } else if (strstr(name, "video")) {
1716                 /* 1. zero copy is updated at _decode_pad_added()
1717                  * 2. NULL surface type is handled in _decode_pad_added() */
1718                 LOGD("zero copy %d", player->set_mode.video_zc);
1719                 if (player->pipeline->videobin == NULL) {
1720                         int surface_type = 0;
1721                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1722                         LOGD("display_surface_type (%d)", surface_type);
1723
1724                         if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1725                                 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1726                                 LOGE("failed to acquire video overlay resource");
1727                                 goto ERROR;
1728                         }
1729
1730                         player->interrupted_by_resource = FALSE;
1731
1732                         if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1733                                 LOGE("failed to create videobin. continuing without video");
1734                                 goto ERROR;
1735                         }
1736
1737                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1738                         LOGD("creating videosink bin success");
1739                 } else {
1740                         reusing = TRUE;
1741                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1742                         LOGD("re-using videobin");
1743                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1744                 }
1745         } else if (strstr(name, "text")) {
1746                 if (player->pipeline->textbin == NULL) {
1747                         if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1748                                 LOGE("failed to create text sink bin. continuing without text");
1749                                 goto ERROR;
1750                         }
1751
1752                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1753                         player->textsink_linked  = 1;
1754                         LOGD("creating textsink bin success");
1755                 } else {
1756                         if (!player->textsink_linked) {
1757                                 LOGD("re-using textbin");
1758                                 reusing = TRUE;
1759                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1760                                 player->textsink_linked  = 1;
1761                         } else {
1762                                 /* linked textbin exist which means that the external subtitle path exist already */
1763                                 LOGW("ignoring internal subtutle since external subtitle is available");
1764                         }
1765                 }
1766                 sink_pad_name = "text_sink";
1767         } else {
1768                 LOGW("unknown mime type %s, ignoring it", name);
1769                 goto ERROR;
1770         }
1771
1772         if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1773                 goto ERROR;
1774
1775         LOGD("[handle: %p] success to create and link sink bin", player);
1776
1777         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1778          * streaming task. if the task blocked, then buffer will not flow to the next element
1779          *(autoplugging element). so this is special hack for streaming. please try to remove it
1780          */
1781         /* dec stream count. we can remove fakesink if it's zero */
1782         if (player->num_dynamic_pad)
1783                 player->num_dynamic_pad--;
1784
1785         LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1786
1787         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1788                 _mmplayer_pipeline_complete(NULL, player);
1789
1790 ERROR:
1791
1792         MMPLAYER_FREEIF(caps_str);
1793
1794         if (caps)
1795                 gst_caps_unref(caps);
1796
1797         return;
1798 }
1799
1800 static gboolean
1801 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1802 {
1803         int required_angle = 0; /* Angle required for straight view */
1804         int rotation_angle = 0;
1805
1806         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1807         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1808
1809         /* Counter clockwise */
1810         switch (orientation) {
1811         case 0:
1812                 required_angle = 0;
1813                 break;
1814         case 90:
1815                 required_angle = 270;
1816                 break;
1817         case 180:
1818                 required_angle = 180;
1819                 break;
1820         case 270:
1821                 required_angle = 90;
1822                 break;
1823         }
1824
1825         rotation_angle = display_angle + required_angle;
1826         if (rotation_angle >= 360)
1827                 rotation_angle -= 360;
1828
1829         /* chech if supported or not */
1830         if (rotation_angle % 90) {
1831                 LOGD("not supported rotation angle = %d", rotation_angle);
1832                 return FALSE;
1833         }
1834
1835         switch (rotation_angle) {
1836         case 0:
1837                 *value = MM_DISPLAY_ROTATION_NONE;
1838                 break;
1839         case 90:
1840                 *value = MM_DISPLAY_ROTATION_90;
1841                 break;
1842         case 180:
1843                 *value = MM_DISPLAY_ROTATION_180;
1844                 break;
1845         case 270:
1846                 *value = MM_DISPLAY_ROTATION_270;
1847                 break;
1848         }
1849
1850         LOGD("setting rotation property value : %d", *value);
1851
1852         return TRUE;
1853 }
1854
1855 int
1856 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1857 {
1858         int display_rotation = 0;
1859         gchar *org_orient = NULL;
1860         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1861
1862         if (!attrs) {
1863                 LOGE("cannot get content attribute");
1864                 return MM_ERROR_PLAYER_INTERNAL;
1865         }
1866
1867         if (display_angle) {
1868                 /* update user roation */
1869                 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1870
1871                 /* Counter clockwise */
1872                 switch (display_rotation) {
1873                 case MM_DISPLAY_ROTATION_NONE:
1874                         *display_angle = 0;
1875                         break;
1876                 case MM_DISPLAY_ROTATION_90:
1877                         *display_angle = 90;
1878                         break;
1879                 case MM_DISPLAY_ROTATION_180:
1880                         *display_angle = 180;
1881                         break;
1882                 case MM_DISPLAY_ROTATION_270:
1883                         *display_angle = 270;
1884                         break;
1885                 default:
1886                         LOGW("wrong angle type : %d", display_rotation);
1887                         break;
1888                 }
1889                 LOGD("check user angle: %d", *display_angle);
1890         }
1891
1892         if (orientation) {
1893                 /* Counter clockwise */
1894                 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1895
1896                 if (org_orient) {
1897                         if (!strcmp(org_orient, "rotate-90"))
1898                                 *orientation = 90;
1899                         else if (!strcmp(org_orient, "rotate-180"))
1900                                 *orientation = 180;
1901                         else if (!strcmp(org_orient, "rotate-270"))
1902                                 *orientation = 270;
1903                         else
1904                                 LOGD("original rotation is %s", org_orient);
1905                 } else {
1906                         LOGD("content_video_orientation get fail");
1907                 }
1908
1909                 LOGD("check orientation: %d", *orientation);
1910         }
1911
1912         return MM_ERROR_NONE;
1913 }
1914
1915 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1916 {
1917         int rotation_value = 0;
1918         int orientations = 0; // current supported angle values are 0, 90, 180, 270
1919         int display_angle = 0;
1920         MMPLAYER_FENTER();
1921
1922         /* check video sinkbin is created */
1923         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1924                 return;
1925
1926         _mmplayer_get_video_angle(player, &display_angle, &orientations);
1927
1928         /* get rotation value to set */
1929         __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1930         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1931         LOGD("set video param : rotate %d", rotation_value);
1932 }
1933
1934 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1935 {
1936         MMHandleType attrs = 0;
1937         int visible = 0;
1938         MMPLAYER_FENTER();
1939
1940         /* check video sinkbin is created */
1941         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1942                 return;
1943
1944         attrs = MMPLAYER_GET_ATTRS(player);
1945         MMPLAYER_RETURN_IF_FAIL(attrs);
1946
1947         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1948         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1949         LOGD("set video param : visible %d", visible);
1950 }
1951
1952 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1953 {
1954         MMHandleType attrs = 0;
1955         int display_method = 0;
1956         MMPLAYER_FENTER();
1957
1958         /* check video sinkbin is created */
1959         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1960                 return;
1961
1962         attrs = MMPLAYER_GET_ATTRS(player);
1963         MMPLAYER_RETURN_IF_FAIL(attrs);
1964
1965         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1966         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1967         LOGD("set video param : method %d", display_method);
1968 }
1969
1970 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1971 {
1972         MMHandleType attrs = 0;
1973         int handle = 0;
1974         MMPLAYER_FENTER();
1975
1976         /* check video sinkbin is created */
1977         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1978                 return;
1979
1980         attrs = MMPLAYER_GET_ATTRS(player);
1981         MMPLAYER_RETURN_IF_FAIL(attrs);
1982
1983         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1984         MMPLAYER_RETURN_IF_FAIL(handle);
1985
1986         gst_video_overlay_set_video_roi_area(
1987                  GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1988                  player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1989         LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1990                 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1991 }
1992
1993 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1994 {
1995         MMHandleType attrs = 0;
1996         int handle = 0;
1997         /*set wl_display*/
1998         int win_roi_x = 0;
1999         int win_roi_y = 0;
2000         int win_roi_width = 0;
2001         int win_roi_height = 0;
2002         MMPLAYER_FENTER();
2003
2004         /* check video sinkbin is created */
2005         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2006                 return;
2007
2008         attrs = MMPLAYER_GET_ATTRS(player);
2009         MMPLAYER_RETURN_IF_FAIL(attrs);
2010
2011         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2012         MMPLAYER_RETURN_IF_FAIL(handle);
2013
2014         /* It should be set after setting window */
2015         mm_attrs_multiple_get(attrs, NULL,
2016                                 "display_win_roi_x", &win_roi_x,
2017                                 "display_win_roi_y", &win_roi_y,
2018                                 "display_win_roi_width", &win_roi_width,
2019                                 "display_win_roi_height", &win_roi_height, NULL);
2020
2021         /* After setting window handle, set display roi area */
2022         gst_video_overlay_set_display_roi_area(
2023                  GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2024                  win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2025         LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2026                 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2027 }
2028
2029 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2030 {
2031         MMHandleType attrs = 0;
2032         int handle = 0;
2033
2034         /* check video sinkbin is created */
2035         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2036                 return;
2037
2038         attrs = MMPLAYER_GET_ATTRS(player);
2039         MMPLAYER_RETURN_IF_FAIL(attrs);
2040
2041         /* common case if using overlay surface */
2042         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2043         MMPLAYER_RETURN_IF_FAIL(handle);
2044
2045         /* default is using wl_surface_id */
2046         LOGD("set video param : wl_surface_id %d", handle);
2047         gst_video_overlay_set_wl_window_wl_surface_id(
2048                         GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2049                         handle);
2050 }
2051
2052 int
2053 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2054 {
2055         gboolean update_all_param = FALSE;
2056
2057         MMPLAYER_FENTER();
2058
2059         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2060                 LOGW("videosink is not ready yet");
2061                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2062         }
2063
2064         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2065                 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2066                 return MM_ERROR_PLAYER_INTERNAL;
2067         }
2068
2069         LOGD("param_name : %s", param_name);
2070         if (!g_strcmp0(param_name, "update_all_param"))
2071                 update_all_param = TRUE;
2072
2073         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2074                 __mmplayer_video_param_set_display_overlay(player);
2075         if (update_all_param || !g_strcmp0(param_name, "display_method"))
2076                 __mmplayer_video_param_set_display_method(player);
2077         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2078                 __mmplayer_video_param_set_display_visible(player);
2079         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2080                 __mmplayer_video_param_set_display_rotation(player);
2081         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2082                 __mmplayer_video_param_set_roi_area(player);
2083         if (update_all_param)
2084                 __mmplayer_video_param_set_video_roi_area(player);
2085
2086
2087         MMPLAYER_FLEAVE();
2088         return MM_ERROR_NONE;
2089 }
2090
2091 int
2092 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2093 {
2094         gboolean disable_overlay = FALSE;
2095         mmplayer_t *player = (mmplayer_t *)hplayer;
2096
2097         MMPLAYER_FENTER();
2098         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2099         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2100                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2101                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2102
2103         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2104                 LOGW("Display control is not supported");
2105                 return MM_ERROR_PLAYER_INTERNAL;
2106         }
2107
2108         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2109
2110         if (audio_only == (bool)disable_overlay) {
2111                 LOGE("It's the same with current setting: (%d)", audio_only);
2112                 return MM_ERROR_NONE;
2113         }
2114
2115         if (audio_only) {
2116                 LOGE("disable overlay");
2117                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2118
2119                 /* release overlay resource */
2120                 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2121                         LOGE("failed to release overlay resource");
2122                         goto ERROR;
2123                 }
2124         } else {
2125                 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2126                         LOGE("failed to acquire video overlay resource");
2127                         goto ERROR;
2128                 }
2129                 player->interrupted_by_resource = FALSE;
2130
2131                 LOGD("enable overlay");
2132                 __mmplayer_video_param_set_display_overlay(player);
2133                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2134         }
2135
2136 ERROR:
2137         MMPLAYER_FLEAVE();
2138         return MM_ERROR_NONE;
2139 }
2140
2141 int
2142 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2143 {
2144         mmplayer_t *player = (mmplayer_t *)hplayer;
2145         gboolean disable_overlay = FALSE;
2146
2147         MMPLAYER_FENTER();
2148
2149         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2150         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2151         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2152                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2153                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2154
2155         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2156                 LOGW("Display control is not supported");
2157                 return MM_ERROR_PLAYER_INTERNAL;
2158         }
2159
2160         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2161
2162         *paudio_only = (bool)disable_overlay;
2163
2164         LOGD("audio_only : %d", *paudio_only);
2165
2166         MMPLAYER_FLEAVE();
2167
2168         return MM_ERROR_NONE;
2169 }
2170
2171 int
2172 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2173 {
2174         GList *bucket = element_bucket;
2175         mmplayer_gst_element_t *element = NULL;
2176         mmplayer_gst_element_t *prv_element = NULL;
2177         GstElement *tee_element = NULL;
2178         gint successful_link_count = 0;
2179
2180         MMPLAYER_FENTER();
2181
2182         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2183
2184         prv_element = (mmplayer_gst_element_t *)bucket->data;
2185         bucket = bucket->next;
2186
2187         for (; bucket; bucket = bucket->next) {
2188                 element = (mmplayer_gst_element_t *)bucket->data;
2189
2190                 if (element && element->gst) {
2191                         if (prv_element && prv_element->gst) {
2192                                 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2193                                         if (tee_element) {
2194                                                 prv_element->gst = tee_element;
2195                                         } else {
2196                                                 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2197                                                         GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2198                                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2199                                                 return -1;
2200                                         }
2201                                 }
2202                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2203                                         LOGD("linking [%s] to [%s] success",
2204                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2205                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2206                                         successful_link_count++;
2207                                         if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2208                                                 LOGD("keep audio-tee element for next audio pipeline branch");
2209                                                 tee_element = prv_element->gst;
2210                                         }
2211                                 } else {
2212                                         LOGD("linking [%s] to [%s] failed",
2213                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2214                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2215                                         return -1;
2216                                 }
2217                         }
2218                 }
2219
2220                 prv_element = element;
2221         }
2222
2223         MMPLAYER_FLEAVE();
2224
2225         return successful_link_count;
2226 }
2227
2228 int
2229 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2230 {
2231         GList *bucket = element_bucket;
2232         mmplayer_gst_element_t *element = NULL;
2233         int successful_add_count = 0;
2234
2235         MMPLAYER_FENTER();
2236
2237         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2238         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2239
2240         for (; bucket; bucket = bucket->next) {
2241                 element = (mmplayer_gst_element_t *)bucket->data;
2242
2243                 if (element && element->gst) {
2244                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2245                                 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed",
2246                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2247                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2248                                 return 0;
2249                         }
2250                         successful_add_count++;
2251                 }
2252         }
2253
2254         MMPLAYER_FLEAVE();
2255
2256         return successful_add_count;
2257 }
2258
2259 static void
2260 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2261 {
2262         mmplayer_t *player = (mmplayer_t *)data;
2263         GstCaps *caps = NULL;
2264         GstStructure *str = NULL;
2265         const char *name;
2266         gboolean caps_ret = TRUE;
2267
2268         MMPLAYER_FENTER();
2269
2270         MMPLAYER_RETURN_IF_FAIL(pad);
2271         MMPLAYER_RETURN_IF_FAIL(unused);
2272         MMPLAYER_RETURN_IF_FAIL(data);
2273
2274         caps = gst_pad_get_current_caps(pad);
2275         if (!caps)
2276                 return;
2277
2278         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2279         if (!caps_ret)
2280                 goto ERROR;
2281
2282         LOGD("name = %s", name);
2283
2284         if (strstr(name, "audio")) {
2285                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2286
2287                 if (player->audio_stream_changed_cb) {
2288                         LOGE("call the audio stream changed cb");
2289                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2290                 }
2291         } else if (strstr(name, "video")) {
2292                 if ((name = gst_structure_get_string(str, "format")))
2293                         player->set_mode.video_zc = name[0] == 'S';
2294
2295                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2296                 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2297         } else {
2298                 LOGW("invalid caps info");
2299         }
2300
2301 ERROR:
2302         if (caps)
2303                 gst_caps_unref(caps);
2304
2305         MMPLAYER_FLEAVE();
2306
2307         return;
2308 }
2309
2310 void
2311 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2312 {
2313         GList *l = NULL;
2314
2315         MMPLAYER_FENTER();
2316         MMPLAYER_RETURN_IF_FAIL(player);
2317
2318         if (player->audio_stream_buff_list) {
2319                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2320                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2321                         if (tmp) {
2322                                 if (send_all) {
2323                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2324                                         __mmplayer_audio_stream_send_data(player, tmp);
2325                                 }
2326                                 MMPLAYER_FREEIF(tmp->pcm_data);
2327                                 MMPLAYER_FREEIF(tmp);
2328                         }
2329                 }
2330                 g_list_free(player->audio_stream_buff_list);
2331                 player->audio_stream_buff_list = NULL;
2332         }
2333
2334         MMPLAYER_FLEAVE();
2335 }
2336
2337 static void
2338 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2339 {
2340         mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2341
2342         MMPLAYER_FENTER();
2343         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2344
2345         audio_stream.bitrate = a_buffer->bitrate;
2346         audio_stream.channel = a_buffer->channel;
2347         audio_stream.channel_mask = a_buffer->channel_mask;
2348         audio_stream.data_size = a_buffer->data_size;
2349         audio_stream.data = a_buffer->pcm_data;
2350         audio_stream.pcm_format = a_buffer->pcm_format;
2351 #ifdef __DEBUG__
2352         LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2353 #endif
2354         player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2355
2356         MMPLAYER_FLEAVE();
2357 }
2358
2359 static void
2360 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2361 {
2362         mmplayer_t *player = (mmplayer_t *)data;
2363         const gchar *pcm_format = NULL;
2364         gint channel = 0;
2365         gint rate = 0;
2366         guint64 channel_mask = 0;
2367         void *a_data = NULL;
2368         gint a_size = 0;
2369         mmplayer_audio_stream_buff_t *a_buffer = NULL;
2370         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2371         GList *l = NULL;
2372
2373         MMPLAYER_FENTER();
2374         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2375
2376         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2377         a_data = mapinfo.data;
2378         a_size = mapinfo.size;
2379
2380         GstCaps *caps = gst_pad_get_current_caps(pad);
2381         GstStructure *structure = gst_caps_get_structure(caps, 0);
2382 #ifdef __DEBUG__
2383         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2384 #endif
2385         pcm_format = gst_structure_get_string(structure, "format");
2386         gst_structure_get_int(structure, "rate", &rate);
2387         gst_structure_get_int(structure, "channels", &channel);
2388         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2389         gst_caps_unref(GST_CAPS(caps));
2390
2391         /* In case of the sync is false, use buffer list.              *
2392          * The num of buffer list depends on the num of audio channels */
2393         if (player->audio_stream_buff_list) {
2394                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2395                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2396                         if (tmp) {
2397                                 if (channel_mask == tmp->channel_mask) {
2398 #ifdef __DEBUG__
2399                                         LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2400 #endif
2401                                         if (tmp->data_size + a_size < tmp->buff_size) {
2402                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2403                                                 tmp->data_size += a_size;
2404                                         } else {
2405                                                 /* send data to client */
2406                                                 __mmplayer_audio_stream_send_data(player, tmp);
2407
2408                                                 if (a_size > tmp->buff_size) {
2409                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2410                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2411                                                         if (tmp->pcm_data == NULL) {
2412                                                                 LOGE("failed to realloc data.");
2413                                                                 goto DONE;
2414                                                         }
2415                                                         tmp->buff_size = a_size;
2416                                                 }
2417                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2418                                                 memcpy(tmp->pcm_data, a_data, a_size);
2419                                                 tmp->data_size = a_size;
2420                                         }
2421                                         goto DONE;
2422                                 }
2423                         } else {
2424                                 LOGE("data is empty in list.");
2425                                 goto DONE;
2426                         }
2427                 }
2428         }
2429
2430         /* create new audio stream data for newly found audio channel */
2431         a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2432         if (a_buffer == NULL) {
2433                 LOGE("failed to alloc data.");
2434                 goto DONE;
2435         }
2436         a_buffer->bitrate = rate;
2437         a_buffer->channel = channel;
2438         a_buffer->channel_mask = channel_mask;
2439         a_buffer->data_size = a_size;
2440         a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2441
2442         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2443                 /* If sync is FALSE, use buffer list to reduce the IPC. */
2444                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2445                 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2446                 if (a_buffer->pcm_data == NULL) {
2447                         LOGE("failed to alloc data.");
2448                         MMPLAYER_FREEIF(a_buffer);
2449                         goto DONE;
2450                 }
2451                 memcpy(a_buffer->pcm_data, a_data, a_size);
2452 #ifdef __DEBUG__
2453                 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2454 #endif
2455                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2456         } else {
2457                 /* If sync is TRUE, send data directly. */
2458                 a_buffer->pcm_data = a_data;
2459                 __mmplayer_audio_stream_send_data(player, a_buffer);
2460                 MMPLAYER_FREEIF(a_buffer);
2461         }
2462
2463 DONE:
2464         gst_buffer_unmap(buffer, &mapinfo);
2465         MMPLAYER_FLEAVE();
2466 }
2467
2468 static void
2469 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2470 {
2471         mmplayer_t *player = (mmplayer_t *)data;
2472         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2473         GstPad *sinkpad = NULL;
2474         GstElement *queue = NULL, *sink = NULL;
2475
2476         MMPLAYER_FENTER();
2477         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2478
2479         queue = gst_element_factory_make("queue", NULL);
2480         if (queue == NULL) {
2481                 LOGD("fail make queue");
2482                 goto ERROR;
2483         }
2484
2485         sink = gst_element_factory_make("fakesink", NULL);
2486         if (sink == NULL) {
2487                 LOGD("fail make fakesink");
2488                 goto ERROR;
2489         }
2490
2491         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2492
2493         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2494                 LOGW("failed to link queue & sink");
2495                 goto ERROR;
2496         }
2497
2498         sinkpad = gst_element_get_static_pad(queue, "sink");
2499
2500         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2501                 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2502                 goto ERROR;
2503         }
2504
2505         LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2506
2507         gst_object_unref(sinkpad);
2508         if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2509                 g_object_set(sink, "sync", TRUE, NULL);
2510         g_object_set(sink, "signal-handoffs", TRUE, NULL);
2511
2512         /* keep the first sink reference only */
2513         if (!audiobin[MMPLAYER_A_SINK].gst) {
2514                 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2515                 audiobin[MMPLAYER_A_SINK].gst = sink;
2516         }
2517
2518
2519         _mmplayer_add_signal_connection(player,
2520                 G_OBJECT(sink),
2521                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2522                 "handoff",
2523                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2524                 (gpointer)player);
2525
2526         __mmplayer_add_sink(player, sink);
2527
2528         if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2529                 LOGE("failed to sync state");
2530                 goto ERROR;
2531         }
2532
2533         if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2534                 LOGE("failed to sync state");
2535                 goto ERROR;
2536         }
2537
2538         MMPLAYER_FLEAVE();
2539         return;
2540
2541 ERROR:
2542         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2543         if (queue) {
2544                 gst_object_unref(GST_OBJECT(queue));
2545                 queue = NULL;
2546         }
2547         if (sink) {
2548                 gst_object_unref(GST_OBJECT(sink));
2549                 sink = NULL;
2550         }
2551         if (sinkpad) {
2552                 gst_object_unref(GST_OBJECT(sinkpad));
2553                 sinkpad = NULL;
2554         }
2555
2556         return;
2557 }
2558
2559 void
2560 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2561 {
2562         mmplayer_t *player = (mmplayer_t *)data;
2563
2564         MMPLAYER_FENTER();
2565         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2566
2567         player->no_more_pad = TRUE;
2568         _mmplayer_pipeline_complete(NULL, player);
2569
2570         MMPLAYER_FLEAVE();
2571         return;
2572 }
2573
2574 void
2575 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2576 {
2577         #define MAX_PROPS_LEN 128
2578         mmplayer_gst_element_t *audiobin = NULL;
2579         gint latency_mode = 0;
2580         gchar *stream_type = NULL;
2581         gchar *latency = NULL;
2582         gint stream_id = 0;
2583         gchar stream_props[MAX_PROPS_LEN] = {0,};
2584         GstStructure *props = NULL;
2585
2586         /* set volume table
2587          * It should be set after player creation through attribute.
2588          * But, it can not be changed during playing.
2589          */
2590         MMPLAYER_FENTER();
2591         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2592
2593         audiobin = player->pipeline->audiobin;
2594
2595         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2596         if (player->sound.mute) {
2597                 LOGD("mute enabled");
2598                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2599         }
2600
2601         mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2602         mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2603
2604         if (!stream_type)
2605                 snprintf(stream_props, sizeof(stream_props) - 1,
2606                                 "props,application.process.id.origin=%d", player->client_pid);
2607         else
2608                 snprintf(stream_props, sizeof(stream_props) - 1,
2609                                 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2610                                 stream_type, stream_id, player->client_pid);
2611
2612         props = gst_structure_from_string(stream_props, NULL);
2613         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2614         LOGI("props result[%s].", stream_props);
2615         gst_structure_free(props);
2616
2617         mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2618
2619         switch (latency_mode) {
2620         case AUDIO_LATENCY_MODE_LOW:
2621                 latency = g_strdup("low");
2622                 break;
2623         case AUDIO_LATENCY_MODE_MID:
2624                 latency = g_strdup("mid");
2625                 break;
2626         case AUDIO_LATENCY_MODE_HIGH:
2627                 latency = g_strdup("high");
2628                 break;
2629         default:
2630                 latency = g_strdup("mid");
2631                 break;
2632         };
2633
2634         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2635
2636         LOGD("audiosink property - latency=%s", latency);
2637
2638         MMPLAYER_FREEIF(latency);
2639
2640         MMPLAYER_FLEAVE();
2641 }
2642
2643 int
2644 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2645 {
2646         mmplayer_gst_element_t *audiobin = NULL;
2647
2648         MMPLAYER_FENTER();
2649         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2650                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2651
2652         audiobin = player->pipeline->audiobin;
2653
2654         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2655         if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2656                 LOGE("failed to create media stream info");
2657                 return MM_ERROR_PLAYER_INTERNAL;
2658         }
2659
2660         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2661
2662         if (player->video360_yaw_radians <= M_PI &&
2663                         player->video360_yaw_radians >= -M_PI &&
2664                         player->video360_pitch_radians <= M_PI_2 &&
2665                         player->video360_pitch_radians >= -M_PI_2) {
2666                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2667                                 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2668                                 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2669         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2670                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2671                                 "source-orientation-y", player->video360_metadata.init_view_heading,
2672                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2673         }
2674
2675         MMPLAYER_FLEAVE();
2676         return MM_ERROR_NONE;
2677 }
2678
2679 static int
2680 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2681 {
2682         mmplayer_gst_element_t *audiobin = NULL;
2683         GstPad *sink_pad = NULL;
2684         GstCaps *acaps = NULL;
2685         gint channels = 0;
2686         int pitch_control = 0;
2687         double pitch_value = 1.0;
2688
2689         MMPLAYER_FENTER();
2690         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2691                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2692
2693         audiobin = player->pipeline->audiobin;
2694
2695         LOGD("make element for normal audio playback");
2696
2697         /* audio bin structure for playback. {} means optional.
2698            optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2699
2700          * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2701                         {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2702          */
2703
2704         /* for pitch control */
2705         mm_attrs_multiple_get(player->attrs, NULL,
2706                                 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2707                                 MM_PLAYER_PITCH_VALUE, &pitch_value,
2708                                 NULL);
2709
2710         LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2711         if (pitch_control && (player->videodec_linked == 0)) {
2712                 GstElementFactory *factory;
2713
2714                 factory = gst_element_factory_find("pitch");
2715                 if (factory) {
2716                         gst_object_unref(factory);
2717
2718                         /* converter */
2719                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2720
2721                         /* pitch */
2722                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2723                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2724                 } else {
2725                         LOGW("there is no pitch element");
2726                 }
2727         }
2728
2729         /* converter */
2730         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2731
2732         /* replaygain volume */
2733         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2734         if (player->sound.rg_enable)
2735                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2736         else
2737                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2738
2739         /* resampler */
2740         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", *bucket, player);
2741
2742         if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2743                 /* currently, only openalsink uses volume element */
2744                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2745                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2746
2747                 if (player->sound.mute) {
2748                         LOGD("mute enabled");
2749                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2750                 }
2751         }
2752
2753         mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2754
2755         /* audio effect element. if audio effect is enabled */
2756         if ((strcmp(player->ini.audioeffect_element, ""))
2757                 && (channels <= 2)
2758                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2759                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2760
2761                 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2762
2763                 if ((!player->bypass_audio_effect)
2764                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2765                         if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2766                                 if (!_mmplayer_audio_effect_custom_apply(player))
2767                                         LOGI("apply audio effect(custom) setting success");
2768                         }
2769                 }
2770
2771                 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2772                         && (player->set_mode.rich_audio)) {
2773                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2774                 }
2775         }
2776
2777         /* create audio sink */
2778         LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2779                         player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2780                         player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2781
2782         /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2783         if (player->is_360_feature_enabled &&
2784                 player->is_content_spherical &&
2785                 channels == 4 &&
2786                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2787                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2788                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2789
2790                 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2791
2792                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2793
2794                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2795                 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2796                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2797                 gst_caps_unref(acaps);
2798
2799                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2800
2801                 player->is_openal_plugin_used = TRUE;
2802         } else {
2803                 if (player->is_360_feature_enabled && player->is_content_spherical)
2804                         LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2805                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2806         }
2807
2808         if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2809                 (player->videodec_linked && player->ini.use_system_clock)) {
2810                 LOGD("system clock will be used.");
2811                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2812         }
2813
2814         if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2815                 __mmplayer_gst_set_pulsesink_property(player);
2816         } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2817                 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2818                         goto ERROR;
2819         }
2820
2821         /* qos on */
2822         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2823         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2824
2825         sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2826         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2827                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2828         gst_object_unref(GST_OBJECT(sink_pad));
2829
2830         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2831
2832         MMPLAYER_FLEAVE();
2833         return MM_ERROR_NONE;
2834
2835 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2836         MMPLAYER_FLEAVE();
2837         return MM_ERROR_PLAYER_INTERNAL;
2838 }
2839
2840 static int
2841 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2842 {
2843         mmplayer_gst_element_t *audiobin = NULL;
2844         enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2845
2846         gchar *dst_format = NULL;
2847         int dst_len = 0;
2848         int dst_samplerate = 0;
2849         int dst_channels = 0;
2850         GstCaps *caps = NULL;
2851         char *caps_str = NULL;
2852
2853         MMPLAYER_FENTER();
2854         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2855                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2856
2857         audiobin = player->pipeline->audiobin;
2858
2859         LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2860
2861         /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2862
2863            [case 1] extract interleave audio pcm without playback
2864                                 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2865                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2866
2867                                 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2868
2869            [case 2] deinterleave for each channel without playback
2870                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2871                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2872
2873                                 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2874                                                                                                                                                    - fakesink (sync or not)
2875                                                                                                                                                    - ...      (sync or not)
2876
2877            [case 3] [case 1(sync only)] + playback
2878                                 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2879
2880                                 * src - ... - tee - queue1 - playback path
2881                                                                   - queue2 - [case1 pipeline with sync]
2882
2883            [case 4] [case 2(sync only)] + playback
2884                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2885
2886                                 * src - ... - tee - queue1 - playback path
2887                                                                   - queue2 - [case2 pipeline with sync]
2888
2889          */
2890
2891         /* 1. create tee and playback path
2892               'tee' should be added at first to copy the decoded stream
2893          */
2894         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2895                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2896                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2897
2898                 /* tee - path 1 : for playback path */
2899                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2900                 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2901
2902                 /* tee - path 2 : for extract path */
2903                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2904                 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2905         }
2906
2907         /* if there is tee, 'tee - path 2' is linked here */
2908         /* converter */
2909         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2910
2911         /* resampler */
2912         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER,  player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2913
2914         /* 2. decide the extract pcm format */
2915         mm_attrs_multiple_get(player->attrs, NULL,
2916                                 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2917                                 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2918                                 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2919                                 NULL);
2920
2921         LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2922                         dst_format, dst_len, dst_samplerate, dst_channels);
2923
2924         if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2925                 mm_attrs_multiple_get(player->attrs, NULL,
2926                                         "content_audio_format", &dst_format, &dst_len, /* get string and len */
2927                                         "content_audio_samplerate", &dst_samplerate,
2928                                         "content_audio_channels", &dst_channels,
2929                                         NULL);
2930
2931                 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2932                                 dst_format, dst_len, dst_samplerate, dst_channels);
2933
2934                 /* If there is no enough information, set it to platform default value. */
2935                 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2936                         LOGD("set platform default format");
2937                         dst_format = DEFAULT_PCM_OUT_FORMAT;
2938                 }
2939                 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2940                 if (dst_channels <= 0)   dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2941         }
2942
2943         /* 3. create capsfilter */
2944         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2945         caps = gst_caps_new_simple("audio/x-raw",
2946                         "format", G_TYPE_STRING, dst_format,
2947                         "rate", G_TYPE_INT, dst_samplerate,
2948                         "channels", G_TYPE_INT, dst_channels,
2949                         NULL);
2950
2951         caps_str = gst_caps_to_string(caps);
2952         LOGD("new caps : %s", caps_str);
2953
2954         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2955
2956         /* clean */
2957         gst_caps_unref(caps);
2958         MMPLAYER_FREEIF(caps_str);
2959
2960         /* 4-1. create deinterleave to extract pcm for each channel */
2961         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2962                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2963                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2964
2965                 /* audiosink will be added after getting signal for each channel */
2966                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2967                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2968                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2969                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2970                 player->no_more_pad = FALSE;
2971         } else {
2972         /* 4-2. create fakesink to extract interlevaed pcm */
2973                 LOGD("add audio fakesink for interleaved audio");
2974                 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2975                 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2976                         g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2977                 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2978
2979                 _mmplayer_add_signal_connection(player,
2980                         G_OBJECT(audiobin[extract_sink_id].gst),
2981                         MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2982                         "handoff",
2983                         G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2984                         (gpointer)player);
2985
2986                 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2987         }
2988
2989         MMPLAYER_FLEAVE();
2990         return MM_ERROR_NONE;
2991
2992 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2993         MMPLAYER_FLEAVE();
2994         return MM_ERROR_PLAYER_INTERNAL;
2995 }
2996
2997 static int
2998 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2999 {
3000         int ret = MM_ERROR_NONE;
3001         mmplayer_gst_element_t *audiobin = NULL;
3002         GList *element_bucket = NULL;
3003
3004         MMPLAYER_FENTER();
3005         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3006                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3007
3008         audiobin = player->pipeline->audiobin;
3009
3010         if (player->build_audio_offload) { /* skip all the audio filters */
3011                 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3012
3013                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3014                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3015                                 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3016
3017                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3018                 goto DONE;
3019         }
3020
3021         /* FIXME: need to mention the supportable condition at API reference */
3022         if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3023                 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3024         else
3025                 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3026
3027         if (ret != MM_ERROR_NONE)
3028                 goto ERROR;
3029 DONE:
3030         LOGD("success to make audio bin element");
3031         *bucket = element_bucket;
3032
3033         MMPLAYER_FLEAVE();
3034         return MM_ERROR_NONE;
3035
3036 ERROR:
3037         LOGE("failed to make audio bin element");
3038         g_list_free(element_bucket);
3039
3040         *bucket = NULL;
3041         MMPLAYER_FLEAVE();
3042         return MM_ERROR_PLAYER_INTERNAL;
3043 }
3044
3045 static int
3046 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3047 {
3048         mmplayer_gst_element_t *first_element = NULL;
3049         mmplayer_gst_element_t *audiobin = NULL;
3050         GstPad *pad = NULL;
3051         GstPad *ghostpad = NULL;
3052         GList *element_bucket = NULL;
3053         int i = 0;
3054
3055         MMPLAYER_FENTER();
3056         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3057
3058         /* alloc handles */
3059         audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3060         if (!audiobin) {
3061                 LOGE("failed to allocate memory for audiobin");
3062                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3063         }
3064
3065         /* create bin */
3066         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3067         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3068         if (!audiobin[MMPLAYER_A_BIN].gst) {
3069                 LOGE("failed to create audiobin");
3070                 goto ERROR;
3071         }
3072
3073         /* take it */
3074         player->pipeline->audiobin = audiobin;
3075
3076         /* create audio filters and audiosink */
3077         if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3078                 goto ERROR;
3079
3080         /* adding created elements to bin */
3081         LOGD("adding created elements to bin");
3082         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3083                 goto ERROR;
3084
3085         /* linking elements in the bucket by added order. */
3086         LOGD("Linking elements in the bucket by added order.");
3087         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3088                 goto ERROR;
3089
3090         /* get first element's sinkpad for creating ghostpad */
3091         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3092         if (!first_element) {
3093                 LOGE("failed to get first elem");
3094                 goto ERROR;
3095         }
3096
3097         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3098         if (!pad) {
3099                 LOGE("failed to get pad from first element of audiobin");
3100                 goto ERROR;
3101         }
3102
3103         ghostpad = gst_ghost_pad_new("sink", pad);
3104         if (!ghostpad) {
3105                 LOGE("failed to create ghostpad");
3106                 goto ERROR;
3107         }
3108
3109         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3110                 LOGE("failed to add ghostpad to audiobin");
3111                 goto ERROR;
3112         }
3113
3114         gst_object_unref(pad);
3115
3116         g_list_free(element_bucket);
3117         MMPLAYER_FLEAVE();
3118
3119         return MM_ERROR_NONE;
3120
3121 ERROR:
3122         LOGD("ERROR : releasing audiobin");
3123
3124         if (pad)
3125                 gst_object_unref(GST_OBJECT(pad));
3126
3127         if (ghostpad)
3128                 gst_object_unref(GST_OBJECT(ghostpad));
3129
3130         if (element_bucket)
3131                 g_list_free(element_bucket);
3132
3133         /* release element which are not added to bin */
3134         for (i = 1; i < MMPLAYER_A_NUM; i++) {
3135                 /* NOTE : skip bin */
3136                 if (audiobin[i].gst) {
3137                         GstObject *parent = NULL;
3138                         parent = gst_element_get_parent(audiobin[i].gst);
3139
3140                         if (!parent) {
3141                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3142                                 audiobin[i].gst = NULL;
3143                         } else
3144                                 gst_object_unref(GST_OBJECT(parent));
3145                 }
3146         }
3147
3148         /* release audiobin with it's childs */
3149         if (audiobin[MMPLAYER_A_BIN].gst)
3150                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3151
3152         MMPLAYER_FREEIF(audiobin);
3153
3154         player->pipeline->audiobin = NULL;
3155
3156         return MM_ERROR_PLAYER_INTERNAL;
3157 }
3158
3159 static guint32
3160 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3161 {
3162         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3163 }
3164
3165 int
3166 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3167 {
3168         int ret = MM_ERROR_NONE;
3169         GList *l = NULL;
3170         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3171         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3172
3173         MMPLAYER_VIDEO_BO_LOCK(player);
3174
3175         if (player->video_bo_list) {
3176                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3177                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3178                         if (tmp && tmp->bo == bo) {
3179                                 tmp->used = FALSE;
3180                                 LOGD("release bo %p", bo);
3181                                 tbm_bo_unref(tmp->bo);
3182                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3183                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
3184                                 return ret;
3185                         }
3186                 }
3187         } else {
3188                 /* hw codec is running or the list was reset for DRC. */
3189                 LOGW("there is no bo list.");
3190         }
3191         MMPLAYER_VIDEO_BO_UNLOCK(player);
3192
3193         LOGW("failed to find bo %p", bo);
3194         return ret;
3195 }
3196 static void
3197 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3198 {
3199         if (!tmp)
3200                 return;
3201
3202         if (tmp->bo)
3203                 tbm_bo_unref(tmp->bo);
3204         g_free(tmp);
3205 }
3206
3207 static void
3208 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3209 {
3210         MMPLAYER_FENTER();
3211         MMPLAYER_RETURN_IF_FAIL(player);
3212
3213         MMPLAYER_VIDEO_BO_LOCK(player);
3214         if (player->video_bo_list) {
3215                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3216                 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3217                 player->video_bo_list = NULL;
3218         }
3219         player->video_bo_size = 0;
3220         MMPLAYER_VIDEO_BO_UNLOCK(player);
3221
3222         MMPLAYER_FLEAVE();
3223         return;
3224 }
3225
3226 static void *
3227 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3228 {
3229         GList *l = NULL;
3230         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3231         gboolean ret = TRUE;
3232
3233         /* check DRC, if it is, destroy the prev bo list to create again */
3234         if (player->video_bo_size != size) {
3235                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3236                 __mmplayer_video_stream_destroy_bo_list(player);
3237                 player->video_bo_size = size;
3238         }
3239
3240         MMPLAYER_VIDEO_BO_LOCK(player);
3241
3242         if ((!player->video_bo_list) ||
3243                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3244
3245                 /* create bo list */
3246                 int idx = 0;
3247                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3248
3249                 if (player->video_bo_list) {
3250                         /* if bo list did not created all, try it again. */
3251                         idx = g_list_length(player->video_bo_list);
3252                         LOGD("bo list exist(len: %d)", idx);
3253                 }
3254
3255                 for (; idx < player->ini.num_of_video_bo; idx++) {
3256                         mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3257                         if (!bo_info) {
3258                                 LOGE("Fail to alloc bo_info.");
3259                                 break;
3260                         }
3261                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3262                         if (!bo_info->bo) {
3263                                 LOGE("Fail to tbm_bo_alloc.");
3264                                 MMPLAYER_FREEIF(bo_info);
3265                                 break;
3266                         }
3267                         bo_info->used = FALSE;
3268                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3269                 }
3270
3271                 /* update video num buffers */
3272                 LOGD("video_num_buffers : %d", idx);
3273                 mm_player_set_attribute((MMHandleType)player, NULL,
3274                                 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3275                                 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3276                                 NULL);
3277
3278                 if (idx == 0) {
3279                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3280                         return NULL;
3281                 }
3282         }
3283
3284         while (TRUE) {
3285                 /* get bo from list*/
3286                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3287                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3288                         if (tmp && (tmp->used == FALSE)) {
3289                                 LOGD("found bo %p to use", tmp->bo);
3290                                 tmp->used = TRUE;
3291                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3292                                 return tbm_bo_ref(tmp->bo);
3293                         }
3294                 }
3295                 if (!ret) {
3296                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3297                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3298                         return NULL;
3299                 }
3300
3301                 if (player->ini.video_bo_timeout <= 0) {
3302                         MMPLAYER_VIDEO_BO_WAIT(player);
3303                 } else {
3304                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3305                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3306                 }
3307                 continue;
3308         }
3309 }
3310
3311 static void
3312 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3313 {
3314         mmplayer_t *player = (mmplayer_t *)data;
3315         MMPLAYER_FENTER();
3316         MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3317
3318         /* send prerolled pkt */
3319         player->video_stream_prerolled = false;
3320
3321         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3322
3323         /* not to send prerolled pkt again */
3324         player->video_stream_prerolled = true;
3325 }
3326
3327 static void
3328 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3329 {
3330         mmplayer_t *player = (mmplayer_t *)data;
3331         mmplayer_video_decoded_data_info_t *stream = NULL;
3332         GstMemory *mem = NULL;
3333
3334         MMPLAYER_FENTER();
3335         MMPLAYER_RETURN_IF_FAIL(player);
3336         MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3337
3338         if (player->video_stream_prerolled) {
3339                 player->video_stream_prerolled = false;
3340                 LOGD("skip the prerolled pkt not to send it again");
3341                 return;
3342         }
3343
3344         /* clear stream data structure */
3345         stream = __mmplayer_create_stream_from_pad(pad);
3346         if (!stream) {
3347                 LOGE("failed to alloc stream");
3348                 return;
3349         }
3350
3351         _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3352
3353         /* set size and timestamp */
3354         mem = gst_buffer_peek_memory(buffer, 0);
3355         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3356         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3357
3358         /* check zero-copy */
3359         if (player->set_mode.video_zc &&
3360                 player->set_mode.video_export &&
3361                 gst_is_tizen_memory(mem)) {
3362                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3363                 stream->internal_buffer = gst_buffer_ref(buffer);
3364         } else { /* sw codec */
3365                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3366                         goto ERROR;
3367
3368                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3369                         goto ERROR;
3370         }
3371
3372         if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3373                 LOGE("failed to send video decoded data.");
3374                 goto ERROR;
3375         }
3376
3377         return;
3378
3379 ERROR:
3380         LOGE("release video stream resource.");
3381         if (gst_is_tizen_memory(mem)) {
3382                 int i = 0;
3383                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3384                         if (stream->bo[i])
3385                                 tbm_bo_unref(stream->bo[i]);
3386                 }
3387
3388                 /* unref gst buffer */
3389                 if (stream->internal_buffer)
3390                         gst_buffer_unref(stream->internal_buffer);
3391         } else {
3392                 if (stream->bo[0])
3393                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3394         }
3395         MMPLAYER_FREEIF(stream);
3396         return;
3397 }
3398
3399 static void
3400 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3401 {
3402         mmplayer_gst_element_t *videobin = NULL;
3403
3404         MMPLAYER_FENTER();
3405         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3406
3407         videobin = player->pipeline->videobin;
3408
3409         /* Set spatial media metadata and/or user settings to the element.
3410          * */
3411         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3412                         "projection-type", player->video360_metadata.projection_type, NULL);
3413
3414         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3415                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3416
3417         if (player->video360_metadata.full_pano_width_pixels &&
3418                         player->video360_metadata.full_pano_height_pixels &&
3419                         player->video360_metadata.cropped_area_image_width &&
3420                         player->video360_metadata.cropped_area_image_height) {
3421                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3422                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3423                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3424                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3425                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3426                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3427                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3428                                 NULL);
3429         }
3430
3431         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3432                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3433                                 "horizontal-fov", player->video360_horizontal_fov,
3434                                 "vertical-fov", player->video360_vertical_fov, NULL);
3435         }
3436
3437         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3438                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439                                 "zoom", 1.0f / player->video360_zoom, NULL);
3440         }
3441
3442         if (player->video360_yaw_radians <= M_PI &&
3443                         player->video360_yaw_radians >= -M_PI &&
3444                         player->video360_pitch_radians <= M_PI_2 &&
3445                         player->video360_pitch_radians >= -M_PI_2) {
3446                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3447                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3448                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3449         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3450                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3451                                 "pose-yaw", player->video360_metadata.init_view_heading,
3452                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3453         }
3454
3455         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3456                         "passthrough", !player->is_video360_enabled, NULL);
3457
3458
3459         MMPLAYER_FLEAVE();
3460 }
3461
3462 static int
3463 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3464 {
3465         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3466         GList *element_bucket = NULL;
3467
3468         MMPLAYER_FENTER();
3469         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3470
3471         /* create video360 filter */
3472         if (player->is_360_feature_enabled && player->is_content_spherical) {
3473                 LOGD("create video360 element");
3474                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3475                 __mmplayer_gst_set_video360_property(player);
3476                 goto EXIT;
3477         }
3478
3479         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3480                 LOGD("skip creating the videoconv and rotator");
3481                 return MM_ERROR_NONE;
3482         }
3483
3484         /* in case of sw codec & overlay surface type, except 360 playback.
3485          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3486         LOGD("create video converter: %s", video_csc);
3487         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3488
3489 EXIT:
3490         *bucket = element_bucket;
3491         MMPLAYER_FLEAVE();
3492         return MM_ERROR_NONE;
3493
3494 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3495         g_list_free(element_bucket);
3496
3497         *bucket = NULL;
3498         MMPLAYER_FLEAVE();
3499         return MM_ERROR_PLAYER_INTERNAL;
3500 }
3501
3502 static gchar *
3503 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3504 {
3505         gchar *factory_name = NULL;
3506
3507         switch (surface_type) {
3508         case MM_DISPLAY_SURFACE_OVERLAY:
3509                 if (strlen(player->ini.videosink_element_overlay) > 0)
3510                         factory_name = player->ini.videosink_element_overlay;
3511                 break;
3512         case MM_DISPLAY_SURFACE_REMOTE:
3513         case MM_DISPLAY_SURFACE_NULL:
3514                 if (strlen(player->ini.videosink_element_fake) > 0)
3515                         factory_name = player->ini.videosink_element_fake;
3516                 break;
3517         default:
3518                 LOGE("unidentified surface type");
3519                 break;
3520         }
3521
3522         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3523         return factory_name;
3524 }
3525
3526 static int
3527 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3528 {
3529         gchar *factory_name = NULL;
3530         mmplayer_gst_element_t *videobin = NULL;
3531         MMHandleType attrs;
3532         int gapless = 0;
3533
3534         MMPLAYER_FENTER();
3535         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3536
3537         videobin = player->pipeline->videobin;
3538         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3539
3540         attrs = MMPLAYER_GET_ATTRS(player);
3541         if (!attrs) {
3542                 LOGE("cannot get content attribute");
3543                 return MM_ERROR_PLAYER_INTERNAL;
3544         }
3545
3546         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3547                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3548                 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3549                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3550                                 "use-tbm", use_tbm, NULL);
3551                 }
3552
3553                 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3554                         return MM_ERROR_PLAYER_INTERNAL;
3555
3556                 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3557
3558         } else {
3559                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3560                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3561         }
3562
3563         mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3564         if (gapless > 0) {
3565                 LOGD("disable last-sample");
3566                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3567         }
3568
3569         if (player->set_mode.video_export) {
3570                 int enable = 0;
3571                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3572                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3573                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3574
3575                 _mmplayer_add_signal_connection(player,
3576                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3577                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3578                                                                 "handoff",
3579                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3580                                                                 (gpointer)player);
3581
3582                 _mmplayer_add_signal_connection(player,
3583                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3584                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3585                                                                 "preroll-handoff",
3586                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3587                                                                 (gpointer)player);
3588         }
3589
3590         if (videobin[MMPLAYER_V_SINK].gst) {
3591                 GstPad *sink_pad = NULL;
3592                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3593                 if (sink_pad) {
3594                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3595                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3596                         gst_object_unref(GST_OBJECT(sink_pad));
3597                 } else {
3598                         LOGE("failed to get sink pad from videosink");
3599                 }
3600         }
3601
3602         return MM_ERROR_NONE;
3603 }
3604
3605 /**
3606  * VIDEO BIN
3607  * - video overlay surface(arm/x86) : tizenwlsink
3608  */
3609 static int
3610 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3611 {
3612         GstPad *pad = NULL;
3613         GList *element_bucket = NULL;
3614         mmplayer_gst_element_t *first_element = NULL;
3615         mmplayer_gst_element_t *videobin = NULL;
3616         gchar *videosink_factory_name = NULL;
3617
3618         MMPLAYER_FENTER();
3619         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3620
3621         /* alloc handles */
3622         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3623         if (!videobin)
3624                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3625
3626         player->pipeline->videobin = videobin;
3627
3628         /* create bin */
3629         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3630         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3631         if (!videobin[MMPLAYER_V_BIN].gst) {
3632                 LOGE("failed to create videobin");
3633                 goto ERROR;
3634         }
3635
3636         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3637                 goto ERROR;
3638
3639         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3640         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3641
3642         /* additional setting for sink plug-in */
3643         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3644                 LOGE("failed to set video property");
3645                 goto ERROR;
3646         }
3647
3648         /* store it as it's sink element */
3649         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3650
3651         /* adding created elements to bin */
3652         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3653                 LOGE("failed to add elements");
3654                 goto ERROR;
3655         }
3656
3657         /* Linking elements in the bucket by added order */
3658         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659                 LOGE("failed to link elements");
3660                 goto ERROR;
3661         }
3662
3663         /* get first element's sinkpad for creating ghostpad */
3664         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3665         if (!first_element) {
3666                 LOGE("failed to get first element from bucket");
3667                 goto ERROR;
3668         }
3669
3670         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3671         if (!pad) {
3672                 LOGE("failed to get pad from first element");
3673                 goto ERROR;
3674         }
3675
3676         /* create ghostpad */
3677         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3678         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3679                 LOGE("failed to add ghostpad to videobin");
3680                 goto ERROR;
3681         }
3682         gst_object_unref(pad);
3683
3684         /* done. free allocated variables */
3685         g_list_free(element_bucket);
3686
3687         MMPLAYER_FLEAVE();
3688
3689         return MM_ERROR_NONE;
3690
3691 ERROR:
3692         LOGE("ERROR : releasing videobin");
3693         g_list_free(element_bucket);
3694
3695         if (pad)
3696                 gst_object_unref(GST_OBJECT(pad));
3697
3698         /* release videobin with it's childs */
3699         if (videobin[MMPLAYER_V_BIN].gst)
3700                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3701
3702         MMPLAYER_FREEIF(videobin);
3703         player->pipeline->videobin = NULL;
3704
3705         return MM_ERROR_PLAYER_INTERNAL;
3706 }
3707
3708 static int
3709 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3710 {
3711         GList *element_bucket = NULL;
3712         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3713
3714         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3715         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3716         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3717                                                         "signal-handoffs", FALSE,
3718                                                         NULL);
3719
3720         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3721         _mmplayer_add_signal_connection(player,
3722                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3723                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3724                                                         "handoff",
3725                                                         G_CALLBACK(__mmplayer_update_subtitle),
3726                                                         (gpointer)player);
3727
3728         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3729                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3730
3731         if (!player->play_subtitle) {
3732                 LOGD("add textbin sink as sink element of whole pipeline.");
3733                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3734         }
3735
3736         /* adding created elements to bin */
3737         LOGD("adding created elements to bin");
3738         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3739                 LOGE("failed to add elements");
3740                 goto ERROR;
3741         }
3742
3743         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3744         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3745         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3746
3747         /* linking elements in the bucket by added order. */
3748         LOGD("Linking elements in the bucket by added order.");
3749         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3750                 LOGE("failed to link elements");
3751                 goto ERROR;
3752         }
3753
3754         /* done. free allocated variables */
3755         g_list_free(element_bucket);
3756
3757         if (textbin[MMPLAYER_T_QUEUE].gst) {
3758                 GstPad *pad = NULL;
3759                 GstPad *ghostpad = NULL;
3760
3761                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3762                 if (!pad) {
3763                         LOGE("failed to get sink pad of text queue");
3764                         goto ERROR;
3765                 }
3766
3767                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3768                 gst_object_unref(pad);
3769
3770                 if (!ghostpad) {
3771                         LOGE("failed to create ghostpad of textbin");
3772                         goto ERROR;
3773                 }
3774
3775                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3776                         LOGE("failed to add ghostpad to textbin");
3777                         gst_object_unref(ghostpad);
3778                         goto ERROR;
3779                 }
3780         }
3781
3782         return MM_ERROR_NONE;
3783
3784 ERROR:
3785         g_list_free(element_bucket);
3786
3787         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3788                 LOGE("remove textbin sink from sink list");
3789                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3790         }
3791
3792         /* release element at __mmplayer_gst_create_text_sink_bin */
3793         return MM_ERROR_PLAYER_INTERNAL;
3794 }
3795
3796 static int
3797 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3798 {
3799         mmplayer_gst_element_t *textbin = NULL;
3800         GList *element_bucket = NULL;
3801         int surface_type = 0;
3802         gint i = 0;
3803
3804         MMPLAYER_FENTER();
3805
3806         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3807
3808         /* alloc handles */
3809         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3810         if (!textbin) {
3811                 LOGE("failed to allocate memory for textbin");
3812                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3813         }
3814
3815         /* create bin */
3816         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3817         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3818         if (!textbin[MMPLAYER_T_BIN].gst) {
3819                 LOGE("failed to create textbin");
3820                 goto ERROR;
3821         }
3822
3823         /* take it */
3824         player->pipeline->textbin = textbin;
3825
3826         /* fakesink */
3827         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3828         LOGD("surface type for subtitle : %d", surface_type);
3829         switch (surface_type) {
3830         case MM_DISPLAY_SURFACE_OVERLAY:
3831         case MM_DISPLAY_SURFACE_NULL:
3832         case MM_DISPLAY_SURFACE_REMOTE:
3833                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3834                         LOGE("failed to make plain text elements");
3835                         goto ERROR;
3836                 }
3837                 break;
3838         default:
3839                 goto ERROR;
3840                 break;
3841         }
3842
3843         MMPLAYER_FLEAVE();
3844
3845         return MM_ERROR_NONE;
3846
3847 ERROR:
3848
3849         LOGD("ERROR : releasing textbin");
3850
3851         g_list_free(element_bucket);
3852
3853         /* release signal */
3854         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3855
3856         /* release element which are not added to bin */
3857         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3858                 /* NOTE : skip bin */
3859                 if (textbin[i].gst) {
3860                         GstObject *parent = NULL;
3861                         parent = gst_element_get_parent(textbin[i].gst);
3862
3863                         if (!parent) {
3864                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3865                                 textbin[i].gst = NULL;
3866                         } else {
3867                                 gst_object_unref(GST_OBJECT(parent));
3868                         }
3869                 }
3870         }
3871
3872         /* release textbin with it's childs */
3873         if (textbin[MMPLAYER_T_BIN].gst)
3874                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3875
3876         MMPLAYER_FREEIF(textbin);
3877         player->pipeline->textbin = NULL;
3878
3879         MMPLAYER_FLEAVE();
3880         return MM_ERROR_PLAYER_INTERNAL;
3881 }
3882
3883 static int
3884 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3885 {
3886         mmplayer_gst_element_t *mainbin = NULL;
3887         mmplayer_gst_element_t *textbin = NULL;
3888         MMHandleType attrs = 0;
3889         GstElement *subsrc = NULL;
3890         GstElement *subparse = NULL;
3891         gchar *subtitle_uri = NULL;
3892         const gchar *charset = NULL;
3893         GstPad *pad = NULL;
3894
3895         MMPLAYER_FENTER();
3896
3897         /* get mainbin */
3898         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3899                                                                 player->pipeline &&
3900                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3901
3902         mainbin = player->pipeline->mainbin;
3903
3904         attrs = MMPLAYER_GET_ATTRS(player);
3905         if (!attrs) {
3906                 LOGE("cannot get content attribute");
3907                 return MM_ERROR_PLAYER_INTERNAL;
3908         }
3909
3910         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3911         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3912                 LOGE("subtitle uri is not proper filepath.");
3913                 return MM_ERROR_PLAYER_INVALID_URI;
3914         }
3915
3916         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3917                 LOGE("failed to get storage info of subtitle path");
3918                 return MM_ERROR_PLAYER_INVALID_URI;
3919         }
3920
3921         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3922
3923         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3924         player->subtitle_language_list = NULL;
3925         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3926
3927         /* create the subtitle source */
3928         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3929         if (!subsrc) {
3930                 LOGE("failed to create filesrc element");
3931                 goto ERROR;
3932         }
3933         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3934
3935         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3936         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3937
3938         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3939                 LOGW("failed to add queue");
3940                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3941                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3942                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3943                 goto ERROR;
3944         }
3945
3946         /* subparse */
3947         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3948         if (!subparse) {
3949                 LOGE("failed to create subparse element");
3950                 goto ERROR;
3951         }
3952
3953         charset = _mmplayer_get_charset(subtitle_uri);
3954         if (charset) {
3955                 LOGD("detected charset is %s", charset);
3956                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3957         }
3958
3959         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3960         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3961
3962         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3963                 LOGW("failed to add subparse");
3964                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3965                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3966                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3967                 goto ERROR;
3968         }
3969
3970         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3971                 LOGW("failed to link subsrc and subparse");
3972                 goto ERROR;
3973         }
3974
3975         player->play_subtitle = TRUE;
3976         player->adjust_subtitle_pos = 0;
3977
3978         LOGD("play subtitle using subtitle file");
3979
3980         if (player->pipeline->textbin == NULL) {
3981                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3982                         LOGE("failed to create text sink bin. continuing without text");
3983                         goto ERROR;
3984                 }
3985
3986                 textbin = player->pipeline->textbin;
3987
3988                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3989                         LOGW("failed to add textbin");
3990
3991                         /* release signal */
3992                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3993
3994                         /* release textbin with it's childs */
3995                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3996                         MMPLAYER_FREEIF(player->pipeline->textbin);
3997                         player->pipeline->textbin = textbin = NULL;
3998                         goto ERROR;
3999                 }
4000
4001                 LOGD("link text input selector and textbin ghost pad");
4002
4003                 player->textsink_linked = 1;
4004                 player->external_text_idx = 0;
4005                 LOGI("textsink is linked");
4006         } else {
4007                 textbin = player->pipeline->textbin;
4008                 LOGD("text bin has been created. reuse it.");
4009                 player->external_text_idx = 1;
4010         }
4011
4012         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4013                 LOGW("failed to link subparse and textbin");
4014                 goto ERROR;
4015         }
4016
4017         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4018         if (!pad) {
4019                 LOGE("failed to get sink pad from textsink to probe data");
4020                 goto ERROR;
4021         }
4022
4023         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4024                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4025
4026         gst_object_unref(pad);
4027         pad = NULL;
4028
4029         /* create dot. for debugging */
4030         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4031         MMPLAYER_FLEAVE();
4032
4033         return MM_ERROR_NONE;
4034
4035 ERROR:
4036         /* release text pipeline resource */
4037         player->textsink_linked = 0;
4038
4039         /* release signal */
4040         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4041
4042         if (player->pipeline->textbin) {
4043                 LOGE("remove textbin");
4044
4045                 /* release textbin with it's childs */
4046                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4047                 MMPLAYER_FREEIF(player->pipeline->textbin);
4048                 player->pipeline->textbin = NULL;
4049
4050         }
4051
4052         /* release subtitle elem */
4053         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4054         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4055
4056         return MM_ERROR_PLAYER_INTERNAL;
4057 }
4058
4059 gboolean
4060 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4061 {
4062         mmplayer_t *player = (mmplayer_t *)data;
4063         MMMessageParamType msg = {0, };
4064         GstClockTime duration = 0;
4065         gpointer text = NULL;
4066         guint text_size = 0;
4067         gboolean ret = TRUE;
4068         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4069
4070         MMPLAYER_FENTER();
4071
4072         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4073         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4074
4075         if (player->is_subtitle_force_drop) {
4076                 LOGW("subtitle is dropped forcedly.");
4077                 return ret;
4078         }
4079
4080         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4081         text = mapinfo.data;
4082         text_size = mapinfo.size;
4083
4084         if (player->set_mode.subtitle_off) {
4085                 LOGD("subtitle is OFF.");
4086                 return TRUE;
4087         }
4088
4089         if (!text || (text_size == 0)) {
4090                 LOGD("There is no subtitle to be displayed.");
4091                 return TRUE;
4092         }
4093
4094         msg.data = (void *)text;
4095
4096         duration = GST_BUFFER_DURATION(buffer);
4097
4098         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4099                 if (player->duration > GST_BUFFER_PTS(buffer))
4100                         duration = player->duration - GST_BUFFER_PTS(buffer);
4101                 else
4102                         duration = 0;
4103                 LOGI("subtitle duration is invalid, subtitle duration change "
4104                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4105         }
4106         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4107
4108         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4109
4110         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4111         gst_buffer_unmap(buffer, &mapinfo);
4112
4113         MMPLAYER_FLEAVE();
4114
4115         return ret;
4116 }
4117
4118 static GstPadProbeReturn
4119 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4120 {
4121         mmplayer_t *player = (mmplayer_t *)u_data;
4122         GstClockTime cur_timestamp = 0;
4123         gint64 adjusted_timestamp = 0;
4124         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4125
4126         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4127
4128         if (player->set_mode.subtitle_off) {
4129                 LOGD("subtitle is OFF.");
4130                 return TRUE;
4131         }
4132
4133         if (player->adjust_subtitle_pos == 0) {
4134                 LOGD("nothing to do");
4135                 return TRUE;
4136         }
4137
4138         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4139         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4140
4141         if (adjusted_timestamp < 0) {
4142                 LOGD("adjusted_timestamp under zero");
4143                 MMPLAYER_FLEAVE();
4144                 return FALSE;
4145         }
4146
4147         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4148         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4149                                 GST_TIME_ARGS(cur_timestamp),
4150                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4151
4152         return GST_PAD_PROBE_OK;
4153 }
4154
4155 static int
4156 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4157 {
4158         MMPLAYER_FENTER();
4159
4160         /* check player and subtitlebin are created */
4161         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4162         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4163
4164         if (position == 0) {
4165                 LOGD("nothing to do");
4166                 MMPLAYER_FLEAVE();
4167                 return MM_ERROR_NONE;
4168         }
4169
4170         /* check current postion */
4171         player->adjust_subtitle_pos = position;
4172
4173         LOGD("save adjust_subtitle_pos in player");
4174
4175         MMPLAYER_FLEAVE();
4176
4177         return MM_ERROR_NONE;
4178 }
4179
4180 /**
4181  * This function is to create  audio or video pipeline for playing.
4182  *
4183  * @param       player          [in]    handle of player
4184  *
4185  * @return      This function returns zero on success.
4186  * @remark
4187  * @see
4188  */
4189 static int
4190 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4191 {
4192         int ret = MM_ERROR_NONE;
4193         mmplayer_gst_element_t *mainbin = NULL;
4194         MMHandleType attrs = 0;
4195
4196         MMPLAYER_FENTER();
4197         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4198
4199         /* get profile attribute */
4200         attrs = MMPLAYER_GET_ATTRS(player);
4201         if (!attrs) {
4202                 LOGE("failed to get content attribute");
4203                 goto INIT_ERROR;
4204         }
4205
4206         /* create pipeline handles */
4207         if (player->pipeline) {
4208                 LOGE("pipeline should be released before create new one");
4209                 goto INIT_ERROR;
4210         }
4211
4212         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4213
4214         /* create mainbin */
4215         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4216         if (mainbin == NULL)
4217                 goto INIT_ERROR;
4218
4219         /* create pipeline */
4220         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4221         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4222         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4223                 LOGE("failed to create pipeline");
4224                 g_free(mainbin);
4225                 goto INIT_ERROR;
4226         }
4227
4228         player->pipeline->mainbin = mainbin;
4229
4230         /* create the source and decoder elements */
4231         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4232                 ret = _mmplayer_gst_build_es_pipeline(player);
4233         } else {
4234                 if (MMPLAYER_USE_DECODEBIN(player))
4235                         ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4236                 else
4237                         ret = _mmplayer_gst_build_pipeline_with_src(player);
4238         }
4239
4240         if (ret != MM_ERROR_NONE) {
4241                 LOGE("failed to create some elements");
4242                 goto INIT_ERROR;
4243         }
4244
4245         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4246         if (__mmplayer_check_subtitle(player)
4247                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4248                 LOGE("failed to create text pipeline");
4249
4250         /* add bus watch */
4251         ret = _mmplayer_gst_add_bus_watch(player);
4252         if (ret != MM_ERROR_NONE) {
4253                 LOGE("failed to add bus watch");
4254                 goto INIT_ERROR;
4255         }
4256
4257         MMPLAYER_FLEAVE();
4258         return MM_ERROR_NONE;
4259
4260 INIT_ERROR:
4261         _mmplayer_bus_watcher_remove(player);
4262         __mmplayer_gst_destroy_pipeline(player);
4263         return MM_ERROR_PLAYER_INTERNAL;
4264 }
4265
4266 static void
4267 __mmplayer_reset_gapless_state(mmplayer_t *player)
4268 {
4269         MMPLAYER_FENTER();
4270         MMPLAYER_RETURN_IF_FAIL(player
4271                 && player->pipeline
4272                 && player->pipeline->audiobin
4273                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4274
4275         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4276
4277         MMPLAYER_FLEAVE();
4278         return;
4279 }
4280
4281 static int
4282 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4283 {
4284         gint timeout = 0;
4285         int ret = MM_ERROR_NONE;
4286
4287         MMPLAYER_FENTER();
4288
4289         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4290
4291         /* cleanup stuffs */
4292         MMPLAYER_FREEIF(player->type);
4293         player->no_more_pad = FALSE;
4294         player->num_dynamic_pad = 0;
4295
4296         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4297         player->subtitle_language_list = NULL;
4298         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4299
4300         MMPLAYER_RECONFIGURE_LOCK(player);
4301         __mmplayer_reset_gapless_state(player);
4302         MMPLAYER_RECONFIGURE_UNLOCK(player);
4303
4304         if (player->streamer) {
4305                 _mm_player_streaming_initialize(player->streamer, FALSE);
4306                 _mm_player_streaming_destroy(player->streamer);
4307                 player->streamer = NULL;
4308         }
4309
4310         /* cleanup unlinked mime type */
4311         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4312         MMPLAYER_FREEIF(player->unlinked_video_mime);
4313         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4314
4315         /* cleanup running stuffs */
4316         _mmplayer_cancel_eos_timer(player);
4317
4318         /* cleanup gst stuffs */
4319         if (player->pipeline) {
4320                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4321                 GstTagList *tag_list = player->pipeline->tag_list;
4322
4323                 /* first we need to disconnect all signal hander */
4324                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4325
4326                 if (mainbin) {
4327                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4328                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4329                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4330                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4331                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4332                         gst_object_unref(bus);
4333
4334                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4335                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4336                         if (ret != MM_ERROR_NONE) {
4337                                 LOGE("fail to change state to NULL");
4338                                 return MM_ERROR_PLAYER_INTERNAL;
4339                         }
4340
4341                         LOGW("succeeded in changing state to NULL");
4342
4343                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4344
4345                         /* free fakesink */
4346                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4347                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4348
4349                         /* free avsysaudiosink
4350                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4351                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4352                         */
4353                         MMPLAYER_FREEIF(audiobin);
4354                         MMPLAYER_FREEIF(videobin);
4355                         MMPLAYER_FREEIF(textbin);
4356                         MMPLAYER_FREEIF(mainbin);
4357                 }
4358
4359                 if (tag_list)
4360                         gst_tag_list_unref(tag_list);
4361
4362                 MMPLAYER_FREEIF(player->pipeline);
4363         }
4364         MMPLAYER_FREEIF(player->album_art);
4365
4366         if (player->v_stream_caps) {
4367                 gst_caps_unref(player->v_stream_caps);
4368                 player->v_stream_caps = NULL;
4369         }
4370
4371         if (player->a_stream_caps) {
4372                 gst_caps_unref(player->a_stream_caps);
4373                 player->a_stream_caps = NULL;
4374         }
4375
4376         if (player->s_stream_caps) {
4377                 gst_caps_unref(player->s_stream_caps);
4378                 player->s_stream_caps = NULL;
4379         }
4380         _mmplayer_track_destroy(player);
4381
4382         if (player->sink_elements)
4383                 g_list_free(player->sink_elements);
4384         player->sink_elements = NULL;
4385
4386         if (player->bufmgr) {
4387                 tbm_bufmgr_deinit(player->bufmgr);
4388                 player->bufmgr = NULL;
4389         }
4390
4391         LOGW("finished destroy pipeline");
4392
4393         MMPLAYER_FLEAVE();
4394
4395         return ret;
4396 }
4397
4398 static int
4399 __mmplayer_gst_realize(mmplayer_t *player)
4400 {
4401         gint timeout = 0;
4402         int ret = MM_ERROR_NONE;
4403
4404         MMPLAYER_FENTER();
4405
4406         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4407
4408         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4409
4410         ret = __mmplayer_gst_create_pipeline(player);
4411         if (ret) {
4412                 LOGE("failed to create pipeline");
4413                 return ret;
4414         }
4415
4416         /* set pipeline state to READY */
4417         /* NOTE : state change to READY must be performed sync. */
4418         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4419         ret = _mmplayer_gst_set_state(player,
4420                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4421
4422         if (ret != MM_ERROR_NONE) {
4423                 /* return error if failed to set state */
4424                 LOGE("failed to set READY state");
4425                 return ret;
4426         }
4427
4428         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4429
4430         /* create dot before error-return. for debugging */
4431         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4432
4433         MMPLAYER_FLEAVE();
4434
4435         return ret;
4436 }
4437
4438 static int
4439 __mmplayer_gst_unrealize(mmplayer_t *player)
4440 {
4441         int ret = MM_ERROR_NONE;
4442
4443         MMPLAYER_FENTER();
4444
4445         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4446
4447         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4448         MMPLAYER_PRINT_STATE(player);
4449
4450         /* release miscellaneous information */
4451         __mmplayer_release_misc(player);
4452
4453         /* destroy pipeline */
4454         ret = __mmplayer_gst_destroy_pipeline(player);
4455         if (ret != MM_ERROR_NONE) {
4456                 LOGE("failed to destory pipeline");
4457                 return ret;
4458         }
4459
4460         /* release miscellaneous information.
4461            these info needs to be released after pipeline is destroyed. */
4462         __mmplayer_release_misc_post(player);
4463
4464         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4465
4466         MMPLAYER_FLEAVE();
4467
4468         return ret;
4469 }
4470
4471 static int
4472 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4473 {
4474         MMPLAYER_FENTER();
4475
4476         if (!player) {
4477                 LOGW("set_message_callback is called with invalid player handle");
4478                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4479         }
4480
4481         player->msg_cb = callback;
4482         player->msg_cb_param = user_param;
4483
4484         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4485
4486         MMPLAYER_FLEAVE();
4487
4488         return MM_ERROR_NONE;
4489 }
4490
4491 int
4492 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4493 {
4494         int ret = MM_ERROR_NONE;
4495         char *path = NULL;
4496
4497         MMPLAYER_FENTER();
4498
4499         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4500         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4501         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4502
4503         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4504
4505         if (strstr(uri, "es_buff://")) {
4506                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4507         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4508                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4509         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4510                 gchar *tmp = NULL;
4511                 tmp = g_ascii_strdown(uri, strlen(uri));
4512                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4513                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4514                 else
4515                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4516                 g_free(tmp);
4517         } else if (strstr(uri, "mms://")) {
4518                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4519         } else if ((path = strstr(uri, "mem://"))) {
4520                 ret = __mmplayer_set_mem_uri(data, path, param);
4521         } else {
4522                 ret = __mmplayer_set_file_uri(data, uri);
4523         }
4524
4525         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4526                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4527         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4528                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4529
4530         /* dump parse result */
4531         SECURE_LOGW("incoming uri : %s", uri);
4532         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4533                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4534
4535         MMPLAYER_FLEAVE();
4536
4537         return ret;
4538 }
4539
4540 static gboolean
4541 __mmplayer_can_do_interrupt(mmplayer_t *player)
4542 {
4543         if (!player || !player->pipeline || !player->attrs) {
4544                 LOGW("not initialized");
4545                 goto FAILED;
4546         }
4547
4548         if (player->audio_decoded_cb) {
4549                 LOGW("not support in pcm extraction mode");
4550                 goto FAILED;
4551         }
4552
4553         /* check if seeking */
4554         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4555                 MMMessageParamType msg_param;
4556                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4557                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4558                 player->seek_state = MMPLAYER_SEEK_NONE;
4559                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4560                 goto FAILED;
4561         }
4562
4563         /* check other thread */
4564         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4565                 LOGW("locked already, cmd state : %d", player->cmd);
4566
4567                 /* check application command */
4568                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4569                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4570
4571                         /* lock will be released at mrp_resource_release_cb() */
4572                         MMPLAYER_CMD_LOCK(player);
4573                         goto INTERRUPT;
4574                 }
4575                 LOGW("nothing to do");
4576                 goto FAILED;
4577         } else {
4578                 LOGW("can interrupt immediately");
4579                 goto INTERRUPT;
4580         }
4581
4582 FAILED:    /* with CMD UNLOCKED */
4583         return FALSE;
4584
4585 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4586         return TRUE;
4587 }
4588
4589 static int
4590 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4591                 void *user_data)
4592 {
4593         mmplayer_t *player = NULL;
4594         MMMessageParamType msg = {0, };
4595         gint64 pos = 0;
4596         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4597
4598         MMPLAYER_FENTER();
4599
4600         if (!user_data) {
4601                 LOGE("user_data is null");
4602                 return FALSE;
4603         }
4604         player = (mmplayer_t *)user_data;
4605
4606         if (!__mmplayer_can_do_interrupt(player)) {
4607                 LOGW("no need to interrupt, so leave");
4608                 /* FIXME: there is no way to avoid releasing resource. */
4609                 return FALSE;
4610         }
4611
4612         player->interrupted_by_resource = TRUE;
4613
4614         /* get last play position */
4615         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4616                 msg.union_type = MM_MSG_UNION_TIME;
4617                 msg.time.elapsed = pos;
4618                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4619         } else {
4620                 LOGW("failed to get play position.");
4621         }
4622
4623         LOGD("video resource conflict so, resource will be freed by unrealizing");
4624         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4625                 LOGE("failed to unrealize");
4626
4627         /* lock is called in __mmplayer_can_do_interrupt() */
4628         MMPLAYER_CMD_UNLOCK(player);
4629
4630         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4631                 player->hw_resource[res_idx] = NULL;
4632         }
4633
4634         MMPLAYER_FLEAVE();
4635         return TRUE; /* release all the resources */
4636 }
4637
4638 static void
4639 __mmplayer_initialize_video_roi(mmplayer_t *player)
4640 {
4641         player->video_roi.scale_x = 0.0;
4642         player->video_roi.scale_y = 0.0;
4643         player->video_roi.scale_width = 1.0;
4644         player->video_roi.scale_height = 1.0;
4645 }
4646
4647 int
4648 _mmplayer_create_player(MMHandleType handle)
4649 {
4650         int ret = MM_ERROR_PLAYER_INTERNAL;
4651         bool enabled = false;
4652
4653         mmplayer_t *player = MM_PLAYER_CAST(handle);
4654
4655         MMPLAYER_FENTER();
4656
4657         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4658
4659         /* initialize player state */
4660         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4661         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4662         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4663         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4664
4665         /* check current state */
4666         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4667
4668         /* construct attributes */
4669         player->attrs = _mmplayer_construct_attribute(handle);
4670
4671         if (!player->attrs) {
4672                 LOGE("Failed to construct attributes");
4673                 return ret;
4674         }
4675
4676         /* initialize gstreamer with configured parameter */
4677         if (!__mmplayer_init_gstreamer(player)) {
4678                 LOGE("Initializing gstreamer failed");
4679                 _mmplayer_deconstruct_attribute(handle);
4680                 return ret;
4681         }
4682
4683         /* create lock. note that g_tread_init() has already called in gst_init() */
4684         g_mutex_init(&player->fsink_lock);
4685
4686         /* create update tag lock */
4687         g_mutex_init(&player->update_tag_lock);
4688
4689         /* create gapless play mutex */
4690         g_mutex_init(&player->gapless_play_thread_mutex);
4691
4692         /* create gapless play cond */
4693         g_cond_init(&player->gapless_play_thread_cond);
4694
4695         /* create gapless play thread */
4696         player->gapless_play_thread =
4697                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4698         if (!player->gapless_play_thread) {
4699                 LOGE("failed to create gapless play thread");
4700                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4701                 g_mutex_clear(&player->gapless_play_thread_mutex);
4702                 g_cond_clear(&player->gapless_play_thread_cond);
4703                 goto ERROR;
4704         }
4705
4706         player->bus_msg_q = g_queue_new();
4707         if (!player->bus_msg_q) {
4708                 LOGE("failed to create queue for bus_msg");
4709                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4710                 goto ERROR;
4711         }
4712
4713         ret = _mmplayer_initialize_video_capture(player);
4714         if (ret != MM_ERROR_NONE) {
4715                 LOGE("failed to initialize video capture");
4716                 goto ERROR;
4717         }
4718
4719         /* initialize resource manager */
4720         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4721                 __resource_release_cb, player, &player->resource_manager)
4722                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4723                 LOGE("failed to initialize resource manager");
4724                 ret = MM_ERROR_PLAYER_INTERNAL;
4725                 goto ERROR;
4726         }
4727
4728         /* create video bo lock and cond */
4729         g_mutex_init(&player->video_bo_mutex);
4730         g_cond_init(&player->video_bo_cond);
4731
4732         /* create subtitle info lock and cond */
4733         g_mutex_init(&player->subtitle_info_mutex);
4734         g_cond_init(&player->subtitle_info_cond);
4735
4736         player->streaming_type = STREAMING_SERVICE_NONE;
4737
4738         /* give default value of audio effect setting */
4739         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4740         player->sound.rg_enable = false;
4741         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4742
4743         player->play_subtitle = FALSE;
4744         player->has_closed_caption = FALSE;
4745         player->pending_resume = FALSE;
4746         if (player->ini.dump_element_keyword[0][0] == '\0')
4747                 player->ini.set_dump_element_flag = FALSE;
4748         else
4749                 player->ini.set_dump_element_flag = TRUE;
4750
4751         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4752         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4753         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4754
4755         /* Set video360 settings to their defaults for just-created player.
4756          * */
4757
4758         player->is_360_feature_enabled = FALSE;
4759         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4760                 LOGI("spherical feature info: %d", enabled);
4761                 if (enabled)
4762                         player->is_360_feature_enabled = TRUE;
4763         } else {
4764                 LOGE("failed to get spherical feature info");
4765         }
4766
4767         player->is_content_spherical = FALSE;
4768         player->is_video360_enabled = TRUE;
4769         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4770         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4771         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4772         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4773         player->video360_zoom = 1.0f;
4774         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4775         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4776
4777         __mmplayer_initialize_video_roi(player);
4778
4779         /* set player state to null */
4780         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4781         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4782
4783         MMPLAYER_FLEAVE();
4784
4785         return MM_ERROR_NONE;
4786
4787 ERROR:
4788         /* free lock */
4789         g_mutex_clear(&player->fsink_lock);
4790         /* free update tag lock */
4791         g_mutex_clear(&player->update_tag_lock);
4792         g_queue_free(player->bus_msg_q);
4793         player->bus_msg_q = NULL;
4794         /* free gapless play thread */
4795         if (player->gapless_play_thread) {
4796                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4797                 player->gapless_play_thread_exit = TRUE;
4798                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4799                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4800
4801                 g_thread_join(player->gapless_play_thread);
4802                 player->gapless_play_thread = NULL;
4803
4804                 g_mutex_clear(&player->gapless_play_thread_mutex);
4805                 g_cond_clear(&player->gapless_play_thread_cond);
4806         }
4807
4808         /* release attributes */
4809         _mmplayer_deconstruct_attribute(handle);
4810
4811         MMPLAYER_FLEAVE();
4812
4813         return ret;
4814 }
4815
4816 static gboolean
4817 __mmplayer_init_gstreamer(mmplayer_t *player)
4818 {
4819         static gboolean initialized = FALSE;
4820         static const int max_argc = 50;
4821         gint *argc = NULL;
4822         gchar **argv = NULL;
4823         gchar **argv2 = NULL;
4824         GError *err = NULL;
4825         int i = 0;
4826         int arg_count = 0;
4827
4828         if (initialized) {
4829                 LOGD("gstreamer already initialized.");
4830                 return TRUE;
4831         }
4832
4833         /* alloc */
4834         argc = malloc(sizeof(int));
4835         argv = malloc(sizeof(gchar *) * max_argc);
4836         argv2 = malloc(sizeof(gchar *) * max_argc);
4837
4838         if (!argc || !argv || !argv2)
4839                 goto ERROR;
4840
4841         memset(argv, 0, sizeof(gchar *) * max_argc);
4842         memset(argv2, 0, sizeof(gchar *) * max_argc);
4843
4844         /* add initial */
4845         *argc = 1;
4846         argv[0] = g_strdup("mmplayer");
4847
4848         /* add gst_param */
4849         for (i = 0; i < 5; i++) {
4850                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4851                 if (strlen(player->ini.gst_param[i]) > 0) {
4852                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4853                         (*argc)++;
4854                 }
4855         }
4856
4857         /* we would not do fork for scanning plugins */
4858         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4859         (*argc)++;
4860
4861         /* check disable registry scan */
4862         if (player->ini.skip_rescan) {
4863                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4864                 (*argc)++;
4865         }
4866
4867         /* check disable segtrap */
4868         if (player->ini.disable_segtrap) {
4869                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4870                 (*argc)++;
4871         }
4872
4873         LOGD("initializing gstreamer with following parameter");
4874         LOGD("argc : %d", *argc);
4875         arg_count = *argc;
4876
4877         for (i = 0; i < arg_count; i++) {
4878                 argv2[i] = argv[i];
4879                 LOGD("argv[%d] : %s", i, argv2[i]);
4880         }
4881
4882         /* initializing gstreamer */
4883         if (!gst_init_check(argc, &argv, &err)) {
4884                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4885                 if (err)
4886                         g_error_free(err);
4887
4888                 goto ERROR;
4889         }
4890         /* release */
4891         for (i = 0; i < arg_count; i++) {
4892 #ifdef __DEBUG__
4893                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4894 #endif
4895                 MMPLAYER_FREEIF(argv2[i]);
4896         }
4897
4898         MMPLAYER_FREEIF(argv);
4899         MMPLAYER_FREEIF(argv2);
4900         MMPLAYER_FREEIF(argc);
4901
4902         /* done */
4903         initialized = TRUE;
4904
4905         return TRUE;
4906
4907 ERROR:
4908
4909         /* release */
4910         for (i = 0; i < arg_count; i++) {
4911                 LOGD("free[%d] : %s", i, argv2[i]);
4912                 MMPLAYER_FREEIF(argv2[i]);
4913         }
4914
4915         MMPLAYER_FREEIF(argv);
4916         MMPLAYER_FREEIF(argv2);
4917         MMPLAYER_FREEIF(argc);
4918
4919         return FALSE;
4920 }
4921
4922 static void
4923 __mmplayer_check_async_state_transition(mmplayer_t *player)
4924 {
4925         GstState element_state = GST_STATE_VOID_PENDING;
4926         GstState element_pending_state = GST_STATE_VOID_PENDING;
4927         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4928         GstElement *element = NULL;
4929         gboolean async = FALSE;
4930
4931         /* check player handle */
4932         MMPLAYER_RETURN_IF_FAIL(player &&
4933                                                 player->pipeline &&
4934                                                 player->pipeline->mainbin &&
4935                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4936
4937         if (player->attrs)
4938                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4939
4940         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4941                 LOGD("don't need to check the pipeline state");
4942                 return;
4943         }
4944
4945         MMPLAYER_PRINT_STATE(player);
4946
4947         /* wait for state transition */
4948         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4949         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4950
4951         if (ret == GST_STATE_CHANGE_FAILURE) {
4952                 LOGE(" [%s] state : %s   pending : %s",
4953                         GST_ELEMENT_NAME(element),
4954                         gst_element_state_get_name(element_state),
4955                         gst_element_state_get_name(element_pending_state));
4956
4957                 /* dump state of all element */
4958                 _mmplayer_dump_pipeline_state(player);
4959
4960                 return;
4961         }
4962
4963         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4964         return;
4965 }
4966
4967 int
4968 _mmplayer_destroy(MMHandleType handle)
4969 {
4970         mmplayer_t *player = MM_PLAYER_CAST(handle);
4971
4972         MMPLAYER_FENTER();
4973
4974         /* check player handle */
4975         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4976
4977         /* destroy can called at anytime */
4978         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4979
4980         /* check async state transition */
4981         __mmplayer_check_async_state_transition(player);
4982
4983         /* release gapless play thread */
4984         if (player->gapless_play_thread) {
4985                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4986                 player->gapless_play_thread_exit = TRUE;
4987                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4988                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4989
4990                 LOGD("waitting for gapless play thread exit");
4991                 g_thread_join(player->gapless_play_thread);
4992                 g_mutex_clear(&player->gapless_play_thread_mutex);
4993                 g_cond_clear(&player->gapless_play_thread_cond);
4994                 LOGD("gapless play thread released");
4995         }
4996
4997         _mmplayer_release_video_capture(player);
4998
4999         /* de-initialize resource manager */
5000         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5001                         player->resource_manager))
5002                 LOGE("failed to deinitialize resource manager");
5003
5004         /* release miscellaneous information */
5005         __mmplayer_release_misc(player);
5006
5007         /* release pipeline */
5008         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5009                 LOGE("failed to destory pipeline");
5010                 return MM_ERROR_PLAYER_INTERNAL;
5011         }
5012
5013         g_queue_free(player->bus_msg_q);
5014
5015         /* release subtitle info lock and cond */
5016         g_mutex_clear(&player->subtitle_info_mutex);
5017         g_cond_clear(&player->subtitle_info_cond);
5018
5019         __mmplayer_release_dump_list(player->dump_list);
5020
5021         /* release miscellaneous information.
5022            these info needs to be released after pipeline is destroyed. */
5023         __mmplayer_release_misc_post(player);
5024
5025         /* release attributes */
5026         _mmplayer_deconstruct_attribute(handle);
5027
5028         if (player->uri_info.uri_list) {
5029                 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5030                 player->uri_info.uri_list = NULL;
5031         }
5032
5033         /* release lock */
5034         g_mutex_clear(&player->fsink_lock);
5035
5036         /* release lock */
5037         g_mutex_clear(&player->update_tag_lock);
5038
5039         /* release video bo lock and cond */
5040         g_mutex_clear(&player->video_bo_mutex);
5041         g_cond_clear(&player->video_bo_cond);
5042
5043         MMPLAYER_FLEAVE();
5044
5045         return MM_ERROR_NONE;
5046 }
5047
5048 int
5049 _mmplayer_realize(MMHandleType hplayer)
5050 {
5051         mmplayer_t *player = (mmplayer_t *)hplayer;
5052         int ret = MM_ERROR_NONE;
5053         char *uri = NULL;
5054         void *param = NULL;
5055         MMHandleType attrs = 0;
5056         int video_codec_type = 0;
5057         int audio_codec_type = 0;
5058         int default_codec_type = 0;
5059         MMPLAYER_FENTER();
5060
5061         /* check player handle */
5062         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5063
5064         /* check current state */
5065         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5066
5067         attrs = MMPLAYER_GET_ATTRS(player);
5068         if (!attrs) {
5069                 LOGE("fail to get attributes.");
5070                 return MM_ERROR_PLAYER_INTERNAL;
5071         }
5072         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5073         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
5074
5075         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5076                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5077
5078                 if (ret != MM_ERROR_NONE) {
5079                         LOGE("failed to parse profile");
5080                         return ret;
5081                 }
5082         }
5083
5084         if (uri && (strstr(uri, "es_buff://"))) {
5085                 if (strstr(uri, "es_buff://push_mode"))
5086                         player->es_player_push_mode = TRUE;
5087                 else
5088                         player->es_player_push_mode = FALSE;
5089         }
5090
5091         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5092                 LOGW("mms protocol is not supported format.");
5093                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5094         }
5095
5096         if (MMPLAYER_IS_STREAMING(player))
5097                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5098         else
5099                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5100
5101         player->smooth_streaming = FALSE;
5102         player->videodec_linked  = 0;
5103         player->audiodec_linked  = 0;
5104         player->textsink_linked = 0;
5105         player->is_external_subtitle_present = FALSE;
5106         player->is_external_subtitle_added_now = FALSE;
5107         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5108         player->video360_metadata.is_spherical = -1;
5109         player->is_openal_plugin_used = FALSE;
5110         player->subtitle_language_list = NULL;
5111         player->is_subtitle_force_drop = FALSE;
5112
5113         _mmplayer_track_initialize(player);
5114         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5115
5116         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5117                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5118
5119                 player->streamer = _mm_player_streaming_create();
5120                 _mm_player_streaming_initialize(player->streamer, TRUE);
5121
5122                 mm_attrs_multiple_get(player->attrs, NULL,
5123                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5124                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5125
5126                 if (prebuffer_ms > 0) {
5127                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5128                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5129                 }
5130
5131                 if (rebuffer_ms > 0) {
5132                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5133                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5134                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5135                 }
5136
5137                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5138                                                                 player->streamer->buffering_req.rebuffer_time);
5139         }
5140
5141         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5142         if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5143                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5144         else
5145                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5146
5147         if (audio_codec_type != default_codec_type) {
5148                 LOGD("audio dec sorting is required");
5149                 player->need_audio_dec_sorting = TRUE;
5150         }
5151
5152         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5153         if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5154                 LOGD("video dec sorting is required");
5155                 player->need_video_dec_sorting = TRUE;
5156         }
5157
5158         /* realize pipeline */
5159         ret = __mmplayer_gst_realize(player);
5160         if (ret != MM_ERROR_NONE)
5161                 LOGE("fail to realize the player.");
5162
5163         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5164
5165         MMPLAYER_FLEAVE();
5166
5167         return ret;
5168 }
5169
5170 int
5171 _mmplayer_unrealize(MMHandleType hplayer)
5172 {
5173         mmplayer_t *player = (mmplayer_t *)hplayer;
5174         int ret = MM_ERROR_NONE;
5175
5176         MMPLAYER_FENTER();
5177
5178         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5179
5180         MMPLAYER_CMD_UNLOCK(player);
5181         _mmplayer_bus_watcher_remove(player);
5182         /* destroy the gst bus msg thread which is created during realize.
5183            this funct have to be called before getting cmd lock. */
5184         _mmplayer_bus_msg_thread_destroy(player);
5185         MMPLAYER_CMD_LOCK(player);
5186
5187         /* check current state */
5188         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5189
5190         /* check async state transition */
5191         __mmplayer_check_async_state_transition(player);
5192
5193         /* unrealize pipeline */
5194         ret = __mmplayer_gst_unrealize(player);
5195
5196         if (!player->interrupted_by_resource) {
5197                 int rm_ret = MM_ERROR_NONE;
5198                 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5199
5200                 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5201                         rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5202                         if (rm_ret != MM_ERROR_NONE)
5203                                 LOGE("failed to release [%d] resources", res_idx);
5204                 }
5205         }
5206
5207         MMPLAYER_FLEAVE();
5208         return ret;
5209 }
5210
5211 int
5212 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5213 {
5214         mmplayer_t *player = (mmplayer_t *)hplayer;
5215
5216         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5217
5218         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5219 }
5220
5221 int
5222 _mmplayer_get_state(MMHandleType hplayer, int *state)
5223 {
5224         mmplayer_t *player = (mmplayer_t *)hplayer;
5225
5226         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5227
5228         *state = MMPLAYER_CURRENT_STATE(player);
5229
5230         return MM_ERROR_NONE;
5231 }
5232
5233 static int
5234 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5235 {
5236         GstElement *vol_element = NULL;
5237         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5238
5239         MMPLAYER_FENTER();
5240         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5241         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5242
5243         /* check pipeline handle */
5244         if (!player->pipeline || !player->pipeline->audiobin) {
5245                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5246
5247                 /* NOTE : stored value will be used in create_audiobin
5248                  * returning MM_ERROR_NONE here makes application to able to
5249                  * set audio volume or mute at anytime.
5250                  */
5251                 return MM_ERROR_NONE;
5252         }
5253
5254         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5255                 volume_elem_id = MMPLAYER_A_SINK;
5256
5257         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5258         if (!vol_element) {
5259                 LOGE("failed to get vol element %d", volume_elem_id);
5260                 return MM_ERROR_PLAYER_INTERNAL;
5261         }
5262
5263         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5264
5265         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5266                 LOGE("there is no '%s' property", prop_name);
5267                 return MM_ERROR_PLAYER_INTERNAL;
5268         }
5269
5270         if (!strcmp(prop_name, "volume")) {
5271                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5272         } else if (!strcmp(prop_name, "mute")) {
5273                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5274         } else {
5275                 LOGE("invalid property %s", prop_name);
5276                 return MM_ERROR_PLAYER_INTERNAL;
5277         }
5278
5279         return MM_ERROR_NONE;
5280 }
5281
5282 int
5283 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5284 {
5285         int ret = MM_ERROR_NONE;
5286         mmplayer_t *player = (mmplayer_t *)hplayer;
5287
5288         MMPLAYER_FENTER();
5289         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5290
5291         LOGD("volume = %f", volume);
5292
5293         /* invalid factor range or not */
5294         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5295                 LOGE("Invalid volume value");
5296                 return MM_ERROR_INVALID_ARGUMENT;
5297         }
5298
5299         player->sound.volume = volume;
5300
5301         ret = __mmplayer_gst_set_volume_property(player, "volume");
5302
5303         MMPLAYER_FLEAVE();
5304         return ret;
5305 }
5306
5307 int
5308 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5309 {
5310         mmplayer_t *player = (mmplayer_t *)hplayer;
5311
5312         MMPLAYER_FENTER();
5313
5314         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5315         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5316
5317         *volume = player->sound.volume;
5318
5319         LOGD("current vol = %f", *volume);
5320
5321         MMPLAYER_FLEAVE();
5322         return MM_ERROR_NONE;
5323 }
5324
5325 int
5326 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5327 {
5328         int ret = MM_ERROR_NONE;
5329         mmplayer_t *player = (mmplayer_t *)hplayer;
5330
5331         MMPLAYER_FENTER();
5332         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333
5334         LOGD("mute = %d", mute);
5335
5336         player->sound.mute = mute;
5337
5338         ret = __mmplayer_gst_set_volume_property(player, "mute");
5339
5340         MMPLAYER_FLEAVE();
5341         return ret;
5342 }
5343
5344 int
5345 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5346 {
5347         mmplayer_t *player = (mmplayer_t *)hplayer;
5348
5349         MMPLAYER_FENTER();
5350
5351         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5352         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5353
5354         *mute = player->sound.mute;
5355
5356         LOGD("current mute = %d", *mute);
5357
5358         MMPLAYER_FLEAVE();
5359
5360         return MM_ERROR_NONE;
5361 }
5362
5363 int
5364 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5365 {
5366         mmplayer_t *player = (mmplayer_t *)hplayer;
5367
5368         MMPLAYER_FENTER();
5369
5370         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5371
5372         player->audio_stream_changed_cb = callback;
5373         player->audio_stream_changed_cb_user_param = user_param;
5374         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5375
5376         MMPLAYER_FLEAVE();
5377
5378         return MM_ERROR_NONE;
5379 }
5380
5381 int
5382 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5383 {
5384         mmplayer_t *player = (mmplayer_t *)hplayer;
5385
5386         MMPLAYER_FENTER();
5387
5388         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5389
5390         player->audio_decoded_cb = callback;
5391         player->audio_decoded_cb_user_param = user_param;
5392         player->audio_extract_opt = opt;
5393         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5394
5395         MMPLAYER_FLEAVE();
5396
5397         return MM_ERROR_NONE;
5398 }
5399
5400 int
5401 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5402 {
5403         mmplayer_t *player = (mmplayer_t *)hplayer;
5404
5405         MMPLAYER_FENTER();
5406
5407         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5408
5409         if (callback && !player->bufmgr)
5410                 player->bufmgr = tbm_bufmgr_init(-1);
5411
5412         player->set_mode.video_export = (callback) ? true : false;
5413         player->video_decoded_cb = callback;
5414         player->video_decoded_cb_user_param = user_param;
5415
5416         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5417
5418         MMPLAYER_FLEAVE();
5419
5420         return MM_ERROR_NONE;
5421 }
5422
5423 int
5424 _mmplayer_start(MMHandleType hplayer)
5425 {
5426         mmplayer_t *player = (mmplayer_t *)hplayer;
5427         gint ret = MM_ERROR_NONE;
5428
5429         MMPLAYER_FENTER();
5430
5431         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5432
5433         /* check current state */
5434         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5435
5436         /* start pipeline */
5437         ret = _mmplayer_gst_start(player);
5438         if (ret != MM_ERROR_NONE)
5439                 LOGE("failed to start player.");
5440
5441         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5442                 LOGD("force playing start even during buffering");
5443                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5444         }
5445
5446         MMPLAYER_FLEAVE();
5447
5448         return ret;
5449 }
5450
5451 /* NOTE: post "not supported codec message" to application
5452  * when one codec is not found during AUTOPLUGGING in MSL.
5453  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5454  * And, if any codec is not found, don't send message here.
5455  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5456  */
5457 int
5458 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5459 {
5460         MMMessageParamType msg_param;
5461         memset(&msg_param, 0, sizeof(MMMessageParamType));
5462         gboolean post_msg_direct = FALSE;
5463
5464         MMPLAYER_FENTER();
5465
5466         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5467
5468         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5469                         player->not_supported_codec, player->can_support_codec);
5470
5471         if (player->not_found_demuxer) {
5472                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5473                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5474
5475                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5476                 MMPLAYER_FREEIF(msg_param.data);
5477
5478                 return MM_ERROR_NONE;
5479         }
5480
5481         if (player->not_supported_codec) {
5482                 if (player->can_support_codec) {
5483                         // There is one codec to play
5484                         post_msg_direct = TRUE;
5485                 } else {
5486                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5487                                 post_msg_direct = TRUE;
5488                 }
5489
5490                 if (post_msg_direct) {
5491                         MMMessageParamType msg_param;
5492                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5493
5494                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5495                                 LOGW("not found AUDIO codec, posting error code to application.");
5496
5497                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5498                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5499                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5500                                 LOGW("not found VIDEO codec, posting error code to application.");
5501
5502                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5503                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5504                         }
5505
5506                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5507
5508                         MMPLAYER_FREEIF(msg_param.data);
5509
5510                         return MM_ERROR_NONE;
5511                 } else {
5512                         // no any supported codec case
5513                         LOGW("not found any codec, posting error code to application.");
5514
5515                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5516                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5517                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5518                         } else {
5519                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5520                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5521                         }
5522
5523                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5524
5525                         MMPLAYER_FREEIF(msg_param.data);
5526                 }
5527         }
5528
5529         MMPLAYER_FLEAVE();
5530
5531         return MM_ERROR_NONE;
5532 }
5533
5534 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5535 {
5536         GstState element_state = GST_STATE_VOID_PENDING;
5537         GstState element_pending_state = GST_STATE_VOID_PENDING;
5538         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5539         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5540
5541         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5542
5543         MMPLAYER_RECONFIGURE_LOCK(player);
5544         if (!player->gapless.reconfigure) {
5545                 MMPLAYER_RECONFIGURE_UNLOCK(player);
5546                 return;
5547         }
5548
5549         LOGI("reconfigure is under process");
5550         MMPLAYER_RECONFIGURE_WAIT(player);
5551         MMPLAYER_RECONFIGURE_UNLOCK(player);
5552         LOGI("reconfigure is completed.");
5553
5554         result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5555                                 &element_state, &element_pending_state, timeout * GST_SECOND);
5556         if (result == GST_STATE_CHANGE_FAILURE)
5557                 LOGW("failed to get pipeline state in %d sec", timeout);
5558
5559         return;
5560 }
5561
5562 /* NOTE : it should be able to call 'stop' anytime*/
5563 int
5564 _mmplayer_stop(MMHandleType hplayer)
5565 {
5566         mmplayer_t *player = (mmplayer_t *)hplayer;
5567         int ret = MM_ERROR_NONE;
5568
5569         MMPLAYER_FENTER();
5570
5571         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5572
5573         /* check current state */
5574         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5575
5576         /* need to wait till the rebuilding pipeline is completed */
5577         __mmplayer_check_pipeline_reconfigure_state(player);
5578         MMPLAYER_RECONFIGURE_LOCK(player);
5579         __mmplayer_reset_gapless_state(player);
5580         MMPLAYER_RECONFIGURE_UNLOCK(player);
5581
5582         /* NOTE : application should not wait for EOS after calling STOP */
5583         _mmplayer_cancel_eos_timer(player);
5584
5585         /* reset */
5586         player->seek_state = MMPLAYER_SEEK_NONE;
5587
5588         /* stop pipeline */
5589         ret = _mmplayer_gst_stop(player);
5590
5591         if (ret != MM_ERROR_NONE)
5592                 LOGE("failed to stop player.");
5593
5594         MMPLAYER_FLEAVE();
5595
5596         return ret;
5597 }
5598
5599 int
5600 _mmplayer_pause(MMHandleType hplayer)
5601 {
5602         mmplayer_t *player = (mmplayer_t *)hplayer;
5603         gint64 pos_nsec = 0;
5604         gboolean async = FALSE;
5605         gint ret = MM_ERROR_NONE;
5606
5607         MMPLAYER_FENTER();
5608
5609         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5610
5611         /* check current state */
5612         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5613
5614         /* check pipline reconfigure state */
5615         __mmplayer_check_pipeline_reconfigure_state(player);
5616
5617         switch (MMPLAYER_CURRENT_STATE(player)) {
5618         case MM_PLAYER_STATE_READY:
5619                 {
5620                         /* check prepare async or not.
5621                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5622                          */
5623                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5624                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5625
5626                         /* Changing back sync of rtspsrc to async */
5627                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5628                                 LOGD("async prepare working mode for rtsp");
5629                                 async = TRUE;
5630                         }
5631                 }
5632                 break;
5633
5634         case MM_PLAYER_STATE_PLAYING:
5635                 {
5636                         /* NOTE : store current point to overcome some bad operation
5637                         *(returning zero when getting current position in paused state) of some
5638                         * elements
5639                         */
5640                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5641                                 LOGW("getting current position failed in paused");
5642
5643                         player->last_position = pos_nsec;
5644
5645                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5646                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5647                            This causes problem is position calculation during normal pause resume scenarios also.
5648                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5649                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5650                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5651                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5652                         }
5653                 }
5654                 break;
5655         }
5656
5657         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5658                 LOGD("doing async pause in case of ms buff src");
5659                 async = TRUE;
5660         }
5661
5662         /* pause pipeline */
5663         ret = _mmplayer_gst_pause(player, async);
5664
5665         if (ret != MM_ERROR_NONE)
5666                 LOGE("failed to pause player. ret : 0x%x", ret);
5667
5668         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5669                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5670                         LOGE("failed to update display_rotation");
5671         }
5672
5673         MMPLAYER_FLEAVE();
5674
5675         return ret;
5676 }
5677
5678 /* in case of streaming, pause could take long time.*/
5679 int
5680 _mmplayer_abort_pause(MMHandleType hplayer)
5681 {
5682         mmplayer_t *player = (mmplayer_t *)hplayer;
5683         int ret = MM_ERROR_NONE;
5684
5685         MMPLAYER_FENTER();
5686
5687         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5688                                                 player->pipeline &&
5689                                                 player->pipeline->mainbin,
5690                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5691
5692         LOGD("set the pipeline state to READY");
5693
5694         /* set state to READY */
5695         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5696                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5697         if (ret != MM_ERROR_NONE) {
5698                 LOGE("fail to change state to READY");
5699                 return MM_ERROR_PLAYER_INTERNAL;
5700         }
5701
5702         LOGD("succeeded in changing state to READY");
5703         return ret;
5704 }
5705
5706 int
5707 _mmplayer_resume(MMHandleType hplayer)
5708 {
5709         mmplayer_t *player = (mmplayer_t *)hplayer;
5710         int ret = MM_ERROR_NONE;
5711         gboolean async = FALSE;
5712
5713         MMPLAYER_FENTER();
5714
5715         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716
5717         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5718                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5719                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5720                         return ret;
5721                 }
5722
5723                 /* Changing back sync mode rtspsrc to async */
5724                 LOGD("async resume for rtsp case");
5725                 async = TRUE;
5726         }
5727
5728         /* check current state */
5729         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5730
5731         ret = _mmplayer_gst_resume(player, async);
5732         if (ret != MM_ERROR_NONE)
5733                 LOGE("failed to resume player.");
5734
5735         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5736                 LOGD("force resume even during buffering");
5737                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5738         }
5739
5740         MMPLAYER_FLEAVE();
5741
5742         return ret;
5743 }
5744
5745 int
5746 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5747 {
5748         mmplayer_t *player = (mmplayer_t *)hplayer;
5749         gint64 pos_nsec = 0;
5750         int ret = MM_ERROR_NONE;
5751         bool mute = false;
5752         signed long long start = 0, stop = 0;
5753         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5754         MMPLAYER_FENTER();
5755
5756         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5757         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5758
5759         /* The sound of video is not supported under 0.0 and over 2.0. */
5760         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5761                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5762                         mute = true;
5763         }
5764         _mmplayer_set_mute(hplayer, mute);
5765
5766         if (player->playback_rate == rate)
5767                 return MM_ERROR_NONE;
5768
5769         /* If the position is reached at start potion during fast backward, EOS is posted.
5770          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5771          */
5772         player->playback_rate = rate;
5773
5774         current_state = MMPLAYER_CURRENT_STATE(player);
5775
5776         if (current_state != MM_PLAYER_STATE_PAUSED)
5777                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5778
5779         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5780
5781         if ((current_state == MM_PLAYER_STATE_PAUSED)
5782                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5783                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5784                 pos_nsec = player->last_position;
5785         }
5786
5787         if (rate >= 0) {
5788                 start = pos_nsec;
5789                 stop = GST_CLOCK_TIME_NONE;
5790         } else {
5791                 start = GST_CLOCK_TIME_NONE;
5792                 stop = pos_nsec;
5793         }
5794
5795         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5796                                 player->playback_rate,
5797                                 GST_FORMAT_TIME,
5798                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5799                                 GST_SEEK_TYPE_SET, start,
5800                                 GST_SEEK_TYPE_SET, stop)) {
5801                 LOGE("failed to set speed playback");
5802                 return MM_ERROR_PLAYER_SEEK;
5803         }
5804
5805         LOGD("succeeded to set speed playback as %0.1f", rate);
5806
5807         MMPLAYER_FLEAVE();
5808
5809         return MM_ERROR_NONE;;
5810 }
5811
5812 int
5813 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5814 {
5815         mmplayer_t *player = (mmplayer_t *)hplayer;
5816         int ret = MM_ERROR_NONE;
5817
5818         MMPLAYER_FENTER();
5819
5820         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5821
5822         /* check pipline reconfigure state */
5823         __mmplayer_check_pipeline_reconfigure_state(player);
5824
5825         ret = _mmplayer_gst_set_position(player, position, FALSE);
5826
5827         MMPLAYER_FLEAVE();
5828
5829         return ret;
5830 }
5831
5832 int
5833 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5834 {
5835         mmplayer_t *player = (mmplayer_t *)hplayer;
5836         int ret = MM_ERROR_NONE;
5837
5838         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5839         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5840
5841         if (g_strrstr(player->type, "video/mpegts"))
5842                 __mmplayer_update_duration_value(player);
5843
5844         *duration = player->duration;
5845         return ret;
5846 }
5847
5848 int
5849 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5850 {
5851         mmplayer_t *player = (mmplayer_t *)hplayer;
5852         int ret = MM_ERROR_NONE;
5853
5854         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5855
5856         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5857
5858         return ret;
5859 }
5860
5861 int
5862 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5863 {
5864         mmplayer_t *player = (mmplayer_t *)hplayer;
5865         int ret = MM_ERROR_NONE;
5866
5867         MMPLAYER_FENTER();
5868
5869         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5870
5871         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5872
5873         MMPLAYER_FLEAVE();
5874
5875         return ret;
5876 }
5877
5878 static gboolean
5879 __mmplayer_is_midi_type(gchar *str_caps)
5880 {
5881         if ((g_strrstr(str_caps, "audio/midi")) ||
5882                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5883                 (g_strrstr(str_caps, "application/x-smaf")) ||
5884                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5885                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5886                 (g_strrstr(str_caps, "audio/xmf")) ||
5887                 (g_strrstr(str_caps, "audio/mxmf"))) {
5888                 LOGD("midi");
5889                 return TRUE;
5890         }
5891
5892         return FALSE;
5893 }
5894
5895 static gboolean
5896 __mmplayer_is_only_mp3_type(gchar *str_caps)
5897 {
5898         if (g_strrstr(str_caps, "application/x-id3") ||
5899                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5900                 return TRUE;
5901         return FALSE;
5902 }
5903
5904 void
5905 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5906 {
5907         GstStructure *caps_structure = NULL;
5908         gint samplerate = 0;
5909         gint channels = 0;
5910
5911         MMPLAYER_FENTER();
5912         MMPLAYER_RETURN_IF_FAIL(player && caps);
5913
5914         caps_structure = gst_caps_get_structure(caps, 0);
5915
5916         /* set stream information */
5917         gst_structure_get_int(caps_structure, "rate", &samplerate);
5918         gst_structure_get_int(caps_structure, "channels", &channels);
5919
5920         mm_player_set_attribute((MMHandleType)player, NULL,
5921                         "content_audio_samplerate", samplerate,
5922                         "content_audio_channels", channels, NULL);
5923
5924         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5925 }
5926
5927 static void
5928 __mmplayer_update_content_type_info(mmplayer_t *player)
5929 {
5930         MMPLAYER_FENTER();
5931         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5932
5933         if (__mmplayer_is_midi_type(player->type)) {
5934                 player->bypass_audio_effect = TRUE;
5935                 return;
5936         }
5937
5938         if (!player->streamer) {
5939                 LOGD("no need to check streaming type");
5940                 return;
5941         }
5942
5943         if (g_strrstr(player->type, "application/x-hls")) {
5944                 /* If it can't know exact type when it parses uri because of redirection case,
5945                  * it will be fixed by typefinder or when doing autoplugging.
5946                  */
5947                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5948                 player->streamer->is_adaptive_streaming = TRUE;
5949         } else if (g_strrstr(player->type, "application/dash+xml")) {
5950                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5951                 player->streamer->is_adaptive_streaming = TRUE;
5952         }
5953
5954         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5955         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5956                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5957
5958                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5959                         if (player->streamer->is_adaptive_streaming)
5960                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5961                         else
5962                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5963                 }
5964         }
5965
5966         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5967         MMPLAYER_FLEAVE();
5968 }
5969
5970 void
5971 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5972         GstCaps *caps, gpointer data)
5973 {
5974         mmplayer_t *player = (mmplayer_t *)data;
5975
5976         MMPLAYER_FENTER();
5977
5978         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5979
5980         /* store type string */
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         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8891
8892         MMPLAYER_FENTER();
8893         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8894
8895         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8896                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8897                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8898
8899         switch (stream_type) {
8900         case MM_PLAYER_STREAM_TYPE_AUDIO:
8901         /* to support audio codec selection, codec info have to be added in ini file as below.
8902            audio codec element hw = xxxx
8903            audio codec element sw = avdec
8904            and in case of audio hw codec is supported and selected,
8905            audio filter elements should be applied depending on the hw capabilities.
8906          */
8907                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8908                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8909                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8910                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8911                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8912                         return MM_ERROR_PLAYER_NO_OP;
8913                 }
8914         break;
8915         case MM_PLAYER_STREAM_TYPE_VIDEO:
8916         /* to support video codec selection, codec info have to be added in ini file as below.
8917            video codec element hw = omx
8918            video codec element sw = avdec */
8919                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8920                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8921                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8922                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8923                         LOGE("There is no video codec info for codec_type %d", codec_type);
8924                         return MM_ERROR_PLAYER_NO_OP;
8925                 }
8926         break;
8927         default:
8928                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8929                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8930         break;
8931         }
8932
8933         LOGD("update %s codec_type to %d", attr_name, codec_type);
8934         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8935
8936         MMPLAYER_FLEAVE();
8937         return MM_ERROR_NONE;
8938 }
8939
8940 int
8941 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8942 {
8943         mmplayer_t *player = (mmplayer_t *)hplayer;
8944         GstElement *rg_vol_element = NULL;
8945
8946         MMPLAYER_FENTER();
8947
8948         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8949
8950         player->sound.rg_enable = enabled;
8951
8952         /* just hold rgvolume enable value if pipeline is not ready */
8953         if (!player->pipeline || !player->pipeline->audiobin) {
8954                 LOGD("pipeline is not ready. holding rgvolume enable value");
8955                 return MM_ERROR_NONE;
8956         }
8957
8958         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8959
8960         if (!rg_vol_element) {
8961                 LOGD("rgvolume element is not created");
8962                 return MM_ERROR_PLAYER_INTERNAL;
8963         }
8964
8965         if (enabled)
8966                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8967         else
8968                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8969
8970         MMPLAYER_FLEAVE();
8971
8972         return MM_ERROR_NONE;
8973 }
8974
8975 int
8976 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8977 {
8978         mmplayer_t *player = (mmplayer_t *)hplayer;
8979         GstElement *rg_vol_element = NULL;
8980         gboolean enable = FALSE;
8981
8982         MMPLAYER_FENTER();
8983
8984         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8985         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8986
8987         /* just hold enable_rg value if pipeline is not ready */
8988         if (!player->pipeline || !player->pipeline->audiobin) {
8989                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8990                 *enabled = player->sound.rg_enable;
8991                 return MM_ERROR_NONE;
8992         }
8993
8994         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8995
8996         if (!rg_vol_element) {
8997                 LOGD("rgvolume element is not created");
8998                 return MM_ERROR_PLAYER_INTERNAL;
8999         }
9000
9001         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9002         *enabled = (bool)enable;
9003
9004         MMPLAYER_FLEAVE();
9005
9006         return MM_ERROR_NONE;
9007 }
9008
9009 int
9010 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9011 {
9012         mmplayer_t *player = (mmplayer_t *)hplayer;
9013         MMHandleType attrs = 0;
9014         int handle = 0;
9015         int ret = MM_ERROR_NONE;
9016
9017         MMPLAYER_FENTER();
9018
9019         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9020
9021         attrs = MMPLAYER_GET_ATTRS(player);
9022         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9023
9024         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9025         if (!handle) {
9026                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9027                 return MM_ERROR_PLAYER_INTERNAL;
9028         }
9029
9030         player->video_roi.scale_x = scale_x;
9031         player->video_roi.scale_y = scale_y;
9032         player->video_roi.scale_width = scale_width;
9033         player->video_roi.scale_height = scale_height;
9034
9035         /* check video sinkbin is created */
9036         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9037                 return MM_ERROR_NONE;
9038
9039         if (!gst_video_overlay_set_video_roi_area(
9040                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9041                 scale_x, scale_y, scale_width, scale_height))
9042                 ret = MM_ERROR_PLAYER_INTERNAL;
9043         else
9044                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9045                         scale_x, scale_y, scale_width, scale_height);
9046
9047         MMPLAYER_FLEAVE();
9048
9049         return ret;
9050 }
9051
9052 int
9053 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9054 {
9055         mmplayer_t *player = (mmplayer_t *)hplayer;
9056         int ret = MM_ERROR_NONE;
9057
9058         MMPLAYER_FENTER();
9059
9060         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9061         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9062
9063         *scale_x = player->video_roi.scale_x;
9064         *scale_y = player->video_roi.scale_y;
9065         *scale_width = player->video_roi.scale_width;
9066         *scale_height = player->video_roi.scale_height;
9067
9068         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9069                 *scale_x, *scale_y, *scale_width, *scale_height);
9070
9071         return ret;
9072 }
9073
9074 int
9075 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9076 {
9077         mmplayer_t *player = (mmplayer_t *)hplayer;
9078
9079         MMPLAYER_FENTER();
9080
9081         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9082
9083         player->client_pid = pid;
9084
9085         LOGD("client pid[%d] %p", pid, player);
9086
9087         MMPLAYER_FLEAVE();
9088
9089         return MM_ERROR_NONE;
9090 }
9091
9092 int
9093 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9094 {
9095         mmplayer_t *player = (mmplayer_t *)hplayer;
9096         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9097         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9098
9099         MMPLAYER_FENTER();
9100
9101         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9102         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9103
9104         *available = true;
9105         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9106
9107         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9108
9109         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9110                 return MM_ERROR_NONE;
9111
9112         /* in case of audio codec default type is HW */
9113         switch(opt) {
9114                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9115                         if (player->ini.support_audio_effect)
9116                                 return MM_ERROR_NONE;
9117                         elem_id = MMPLAYER_A_FILTER;
9118                 break;
9119                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9120                         if (player->ini.support_replaygain_control)
9121                                 return MM_ERROR_NONE;
9122                         elem_id = MMPLAYER_A_RGVOL;
9123                 break;
9124                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9125                         if (player->ini.support_pitch_control)
9126                                 return MM_ERROR_NONE;
9127                         elem_id = MMPLAYER_A_PITCH;
9128                 break;
9129                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9130                         if (player->ini.support_audio_effect)
9131                                 return MM_ERROR_NONE;
9132                 break;
9133                 /* default case handling is not required */
9134         }
9135
9136         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9137                 LOGW("audio control option [%d] is not available", opt);
9138                 *available = false;
9139         } else {
9140                 /* setting pcm exporting option is allowed before READY state */
9141                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9142                         return MM_ERROR_PLAYER_INVALID_STATE;
9143
9144                 /* check whether the audio filter exist or not after READY state,
9145                    because the sw codec could be added during auto-plugging in some cases */
9146                 if (!player->pipeline ||
9147                         !player->pipeline->audiobin ||
9148                         !player->pipeline->audiobin[elem_id].gst) {
9149                         LOGW("there is no audio elem [%d]", elem_id);
9150                         *available = false;
9151                 }
9152         }
9153
9154         LOGD("audio control opt %d, available %d", opt, *available);
9155
9156         MMPLAYER_FLEAVE();
9157
9158         return MM_ERROR_NONE;
9159 }
9160
9161 static gboolean
9162 __mmplayer_update_duration_value(mmplayer_t *player)
9163 {
9164         gboolean ret = FALSE;
9165         gint64 dur_nsec = 0;
9166         LOGD("try to update duration");
9167
9168         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9169                 player->duration = dur_nsec;
9170                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9171                 ret = TRUE;
9172         }
9173
9174         if (player->duration < 0) {
9175                 LOGW("duration is Non-Initialized !!!");
9176                 player->duration = 0;
9177         }
9178
9179         /* update streaming service type */
9180         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9181
9182         /* check duration is OK */
9183         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9184                 /* FIXIT : find another way to get duration here. */
9185                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9186
9187         return ret;
9188 }
9189
9190 static gboolean
9191 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9192 {
9193         /* update audio params
9194         NOTE : We need original audio params and it can be only obtained from src pad of audio
9195         decoder. Below code only valid when we are not using 'resampler' just before
9196         'audioconverter'. */
9197         GstCaps *caps_a = NULL;
9198         GstPad *pad = NULL;
9199         gint samplerate = 0, channels = 0;
9200         GstStructure *p = NULL;
9201         GstElement *aconv = NULL;
9202
9203         LOGD("try to update audio attrs");
9204
9205         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9206
9207         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9208                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9209         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9210                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9211         } else {
9212                 LOGE("there is no audio converter");
9213                 return FALSE;
9214         }
9215
9216         pad = gst_element_get_static_pad(aconv, "sink");
9217
9218         if (!pad) {
9219                 LOGW("failed to get pad from audio converter");
9220                 return FALSE;
9221         }
9222
9223         caps_a = gst_pad_get_current_caps(pad);
9224         if (!caps_a) {
9225                 LOGW("not ready to get audio caps");
9226                 gst_object_unref(pad);
9227                 return FALSE;
9228         }
9229
9230         p = gst_caps_get_structure(caps_a, 0);
9231
9232         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9233
9234         gst_structure_get_int(p, "rate", &samplerate);
9235         gst_structure_get_int(p, "channels", &channels);
9236
9237         mm_player_set_attribute((MMHandleType)player, NULL,
9238                         "content_audio_samplerate", samplerate,
9239                         "content_audio_channels", channels, NULL);
9240
9241         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9242
9243         gst_caps_unref(caps_a);
9244         gst_object_unref(pad);
9245
9246         return TRUE;
9247 }
9248
9249 static gboolean
9250 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9251 {
9252         LOGD("try to update video attrs");
9253
9254         GstCaps *caps_v = NULL;
9255         GstPad *pad = NULL;
9256         gint tmpNu, tmpDe;
9257         gint width, height;
9258         GstStructure *p = NULL;
9259
9260         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9261         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9262
9263         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9264         if (!pad) {
9265                 LOGD("no videosink sink pad");
9266                 return FALSE;
9267         }
9268
9269         caps_v = gst_pad_get_current_caps(pad);
9270         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9271         if (!caps_v && player->v_stream_caps) {
9272                 caps_v = player->v_stream_caps;
9273                 gst_caps_ref(caps_v);
9274         }
9275
9276         if (!caps_v) {
9277                 LOGD("no negitiated caps from videosink");
9278                 gst_object_unref(pad);
9279                 return FALSE;
9280         }
9281
9282         p = gst_caps_get_structure(caps_v, 0);
9283         gst_structure_get_int(p, "width", &width);
9284         gst_structure_get_int(p, "height", &height);
9285
9286         mm_player_set_attribute((MMHandleType)player, NULL,
9287                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9288
9289         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9290
9291         SECURE_LOGD("width : %d     height : %d", width, height);
9292
9293         gst_caps_unref(caps_v);
9294         gst_object_unref(pad);
9295
9296         if (tmpDe > 0) {
9297                 mm_player_set_attribute((MMHandleType)player, NULL,
9298                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9299                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9300         }
9301
9302         return TRUE;
9303 }
9304
9305 static gboolean
9306 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9307 {
9308         gboolean ret = FALSE;
9309         guint64 data_size = 0;
9310         gchar *path = NULL;
9311         struct stat sb;
9312
9313         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9314         if (!player->duration)
9315                 return FALSE;
9316
9317         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9318                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9319                 if (stat(path, &sb) == 0)
9320                         data_size = (guint64)sb.st_size;
9321
9322         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9323                 data_size = player->http_content_size;
9324         }
9325
9326         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9327
9328         if (data_size) {
9329                 guint64 bitrate = 0;
9330                 guint64 msec_dur = 0;
9331
9332                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9333                 if (msec_dur > 0) {
9334                         bitrate = data_size * 8 * 1000 / msec_dur;
9335                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9336                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9337                         mm_player_set_attribute((MMHandleType)player, NULL,
9338                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9339                         ret = TRUE;
9340                 } else {
9341                         LOGD("player duration is less than 0");
9342                 }
9343         }
9344
9345         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9346                 if (player->total_bitrate) {
9347                         mm_player_set_attribute((MMHandleType)player, NULL,
9348                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9349                         ret = TRUE;
9350                 }
9351         }
9352
9353         return ret;
9354 }
9355
9356 static void
9357 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9358 {
9359         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9360         data->uri_type = uri_type;
9361 }
9362
9363 static int
9364 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9365 {
9366         int ret = MM_ERROR_PLAYER_INVALID_URI;
9367         int mem_size = 0;
9368         char *buffer = NULL;
9369         char *seperator = strchr(path, ',');
9370         char ext[100] = {0,}, size[100] = {0,};
9371
9372         if (seperator) {
9373                 if ((buffer = strstr(path, "ext="))) {
9374                         buffer += strlen("ext=");
9375
9376                         if (strlen(buffer)) {
9377                                 strncpy(ext, buffer, 99);
9378
9379                                 if ((seperator = strchr(ext, ','))
9380                                         || (seperator = strchr(ext, ' '))
9381                                         || (seperator = strchr(ext, '\0'))) {
9382                                         seperator[0] = '\0';
9383                                 }
9384                         }
9385                 }
9386
9387                 if ((buffer = strstr(path, "size="))) {
9388                         buffer += strlen("size=");
9389
9390                         if (strlen(buffer) > 0) {
9391                                 strncpy(size, buffer, 99);
9392
9393                                 if ((seperator = strchr(size, ','))
9394                                         || (seperator = strchr(size, ' '))
9395                                         || (seperator = strchr(size, '\0'))) {
9396                                         seperator[0] = '\0';
9397                                 }
9398
9399                                 mem_size = atoi(size);
9400                         }
9401                 }
9402         }
9403
9404         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9405
9406         if (mem_size && param) {
9407                 if (data->input_mem.buf)
9408                         free(data->input_mem.buf);
9409                 data->input_mem.buf = malloc(mem_size);
9410
9411                 if (data->input_mem.buf) {
9412                         memcpy(data->input_mem.buf, param, mem_size);
9413                         data->input_mem.len = mem_size;
9414                         ret = MM_ERROR_NONE;
9415                 } else {
9416                         LOGE("failed to alloc mem %d", mem_size);
9417                         ret = MM_ERROR_PLAYER_INTERNAL;
9418                 }
9419
9420                 data->input_mem.offset = 0;
9421                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9422         }
9423
9424         return ret;
9425 }
9426
9427 static int
9428 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9429 {
9430         gchar *location = NULL;
9431         GError *err = NULL;
9432         char *path = NULL;
9433         int ret = MM_ERROR_NONE;
9434
9435         if ((path = strstr(uri, "file://"))) {
9436                 location = g_filename_from_uri(uri, NULL, &err);
9437                 if (!location || (err != NULL)) {
9438                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9439                                 (err != NULL) ? err->message : "unknown error");
9440                         if (err)
9441                                 g_error_free(err);
9442
9443                         MMPLAYER_FREEIF(location);
9444
9445                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9446                         return MM_ERROR_PLAYER_INVALID_URI;
9447                 }
9448                 LOGD("path from uri: %s", location);
9449         }
9450
9451         path = (location != NULL) ? (location) : ((char *)uri);
9452
9453
9454         ret = _mmplayer_exist_file_path(path);
9455
9456         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9457         if (ret == MM_ERROR_NONE) {
9458                 if (_mmplayer_is_sdp_file(path)) {
9459                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9460                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9461                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9462                 } else {
9463                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9464                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9465                 }
9466         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9467                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9468         } else {
9469                 LOGE("invalid uri, could not play..");
9470                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9471         }
9472
9473         MMPLAYER_FREEIF(location);
9474
9475         return ret;
9476 }
9477
9478 static mmplayer_video_decoded_data_info_t *
9479 __mmplayer_create_stream_from_pad(GstPad *pad)
9480 {
9481         GstCaps *caps = NULL;
9482         GstStructure *structure = NULL;
9483         unsigned int fourcc = 0;
9484         const gchar *string_format = NULL;
9485         mmplayer_video_decoded_data_info_t *stream = NULL;
9486         gint width, height;
9487         MMPixelFormatType format;
9488         GstVideoInfo info;
9489
9490         caps = gst_pad_get_current_caps(pad);
9491         if (!caps) {
9492                 LOGE("Caps is NULL.");
9493                 return NULL;
9494         }
9495
9496 #ifdef __DEBUG__
9497         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9498 #endif
9499         structure = gst_caps_get_structure(caps, 0);
9500         gst_structure_get_int(structure, "width", &width);
9501         gst_structure_get_int(structure, "height", &height);
9502         string_format = gst_structure_get_string(structure, "format");
9503
9504         if (string_format)
9505                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9506         format = _mmplayer_get_pixtype(fourcc);
9507         gst_video_info_from_caps(&info, caps);
9508         gst_caps_unref(caps);
9509
9510         /* moved here */
9511         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9512                 LOGE("Wrong condition!!");
9513                 return NULL;
9514         }
9515
9516         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9517         if (!stream) {
9518                 LOGE("failed to alloc mem for video data");
9519                 return NULL;
9520         }
9521
9522         stream->width = width;
9523         stream->height = height;
9524         stream->format = format;
9525         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9526
9527         return stream;
9528 }
9529
9530 static void
9531 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9532 {
9533         unsigned int pitch = 0;
9534         unsigned int size = 0;
9535         int index = 0;
9536         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9537         tbm_bo bo = NULL;
9538
9539         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9540                 bo = gst_tizen_memory_get_bos(mem, index);
9541                 if (bo)
9542                         stream->bo[index] = tbm_bo_ref(bo);
9543                 else
9544                         LOGE("failed to get bo for index %d", index);
9545         }
9546
9547         for (index = 0; index < stream->plane_num; index++) {
9548                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9549                 stream->stride[index] = pitch;
9550                 if (pitch)
9551                         stream->elevation[index] = size / pitch;
9552                 else
9553                         stream->elevation[index] = stream->height;
9554         }
9555 }
9556
9557 static gboolean
9558 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9559 {
9560         if (stream->format == MM_PIXEL_FORMAT_I420) {
9561                 int ret = TBM_SURFACE_ERROR_NONE;
9562                 tbm_surface_h surface;
9563                 tbm_surface_info_s info;
9564
9565                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9566
9567                 ret = tbm_surface_get_info(surface, &info);
9568                 if (ret != TBM_SURFACE_ERROR_NONE) {
9569                         tbm_surface_destroy(surface);
9570                         return FALSE;
9571                 }
9572
9573                 tbm_surface_destroy(surface);
9574                 stream->stride[0] = info.planes[0].stride;
9575                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9576                 stream->stride[1] = info.planes[1].stride;
9577                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9578                 stream->stride[2] = info.planes[2].stride;
9579                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9580                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9581         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9582                 stream->stride[0] = stream->width * 4;
9583                 stream->elevation[0] = stream->height;
9584                 stream->bo_size = stream->stride[0] * stream->height;
9585         } else {
9586                 LOGE("Not support format %d", stream->format);
9587                 return FALSE;
9588         }
9589
9590         return TRUE;
9591 }
9592
9593 static gboolean
9594 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9595 {
9596         tbm_bo_handle thandle;
9597         gboolean is_mapped;
9598         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9599         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9600         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9601         int i = 0;
9602         int j = 0;
9603         int k = 0;
9604         unsigned char *src = NULL;
9605         unsigned char *dest = NULL;
9606         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9607
9608         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9609         if (!is_mapped) {
9610                 LOGE("fail to gst_memory_map");
9611                 return FALSE;
9612         }
9613
9614         if (!mapinfo.data) {
9615                 LOGE("data pointer is wrong");
9616                 goto ERROR;
9617         }
9618
9619         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9620         if (!stream->bo[0]) {
9621                 LOGE("Fail to tbm_bo_alloc!!");
9622                 goto ERROR;
9623         }
9624
9625         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9626         if (!thandle.ptr) {
9627                 LOGE("thandle pointer is wrong");
9628                 goto ERROR;
9629         }
9630
9631         if (stream->format == MM_PIXEL_FORMAT_I420) {
9632                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9633                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9634                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9635                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9636
9637                 dest_offset[0] = 0;
9638                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9639                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9640
9641                 for (i = 0; i < 3; i++) {
9642                         src = mapinfo.data + src_offset[i];
9643                         dest = thandle.ptr + dest_offset[i];
9644
9645                         if (i > 0)
9646                                 k = 1;
9647
9648                         for (j = 0; j < stream->height >> k; j++) {
9649                                 memcpy(dest, src, stream->width>>k);
9650                                 src += src_stride[i];
9651                                 dest += stream->stride[i];
9652                         }
9653                 }
9654         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9655                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9656         } else {
9657                 LOGE("Not support format %d", stream->format);
9658                 goto ERROR;
9659         }
9660
9661         tbm_bo_unmap(stream->bo[0]);
9662         gst_memory_unmap(mem, &mapinfo);
9663
9664         return TRUE;
9665
9666 ERROR:
9667         if (stream->bo[0])
9668                 tbm_bo_unmap(stream->bo[0]);
9669
9670         if (is_mapped)
9671                 gst_memory_unmap(mem, &mapinfo);
9672
9673         return FALSE;
9674 }
9675
9676 static void
9677 __mmplayer_set_pause_state(mmplayer_t *player)
9678 {
9679         if (player->sent_bos)
9680                 return;
9681
9682         /* rtsp case, get content attrs by GstMessage */
9683         if (MMPLAYER_IS_RTSP_STREAMING(player))
9684                 return;
9685
9686         /* it's first time to update all content attrs. */
9687         _mmplayer_update_content_attrs(player, ATTR_ALL);
9688 }
9689
9690 static void
9691 __mmplayer_set_playing_state(mmplayer_t *player)
9692 {
9693         gchar *audio_codec = NULL;
9694
9695         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9696                 /* initialize because auto resume is done well. */
9697                 player->resumed_by_rewind = FALSE;
9698                 player->playback_rate = 1.0;
9699         }
9700
9701         if (player->sent_bos)
9702                 return;
9703
9704         /* try to get content metadata */
9705
9706         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9707          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9708          * legacy mmfw-player api
9709          */
9710         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9711
9712         if ((player->cmd == MMPLAYER_COMMAND_START)
9713                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9714                 __mmplayer_handle_missed_plugin(player);
9715         }
9716
9717         /* check audio codec field is set or not
9718          * we can get it from typefinder or codec's caps.
9719          */
9720         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9721
9722         /* The codec format can't be sent for audio only case like amr, mid etc.
9723          * Because, parser don't make related TAG.
9724          * So, if it's not set yet, fill it with found data.
9725          */
9726         if (!audio_codec) {
9727                 if (g_strrstr(player->type, "audio/midi"))
9728                         audio_codec = "MIDI";
9729                 else if (g_strrstr(player->type, "audio/x-amr"))
9730                         audio_codec = "AMR";
9731                 else if (g_strrstr(player->type, "audio/mpeg")
9732                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9733                         audio_codec = "AAC";
9734                 else
9735                         audio_codec = "unknown";
9736
9737                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9738                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9739                         LOGE("failed to set attribute");
9740
9741                 LOGD("set audio codec type with caps");
9742         }
9743
9744         return;
9745 }