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