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