[0.6.266] release video resource
[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         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7589
7590         MMPLAYER_FENTER();
7591         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7592
7593         LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7594
7595         if (MMPLAYER_USE_DECODEBIN(player))
7596                 return;
7597
7598         if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7599                 return;
7600
7601         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7602
7603         __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7604
7605         LOGD("remove videobin");
7606         ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7607                                 GST_STATE_NULL, FALSE, timeout);
7608         if (ret != MM_ERROR_NONE) {
7609                 LOGE("fail to change state of videobin to NULL");
7610                 return;
7611         }
7612
7613         if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7614                 LOGE("failed to remove videobin");
7615                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7616         }
7617
7618         LOGD("remove concat");
7619         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7620                                 GST_STATE_NULL, FALSE, timeout);
7621         if (ret != MM_ERROR_NONE) {
7622                 LOGE("fail to change state of concat to NULL");
7623                 return;
7624         }
7625
7626         if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7627                 LOGE("failed to remove video concat");
7628                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7629         }
7630
7631         mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7632         mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7633         MMPLAYER_FREEIF(player->pipeline->videobin);
7634
7635         ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7636         if (ret != MM_ERROR_NONE)
7637                 LOGE("failed to release overlay resources");
7638
7639         player->videodec_linked = 0;
7640
7641         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7642         MMPLAYER_FLEAVE();
7643 }
7644
7645 void
7646 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7647 {
7648         mmplayer_t *player = (mmplayer_t *)data;
7649
7650         MMPLAYER_FENTER();
7651         MMPLAYER_RETURN_IF_FAIL(player);
7652
7653         LOGD("got about to finish signal");
7654
7655         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7656                 LOGW("Fail to get cmd lock");
7657                 return;
7658         }
7659
7660         if (!__mmplayer_verify_gapless_play_path(player)) {
7661                 LOGD("decoding is finished.");
7662                 MMPLAYER_CMD_UNLOCK(player);
7663                 return;
7664         }
7665
7666         _mmplayer_set_reconfigure_state(player, TRUE);
7667         MMPLAYER_CMD_UNLOCK(player);
7668
7669         MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7670         __mmplayer_deactivate_old_path(player);
7671
7672         MMPLAYER_FLEAVE();
7673 }
7674
7675 void
7676 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7677 {
7678         mmplayer_t *player = (mmplayer_t *)data;
7679         GstIterator *iter = NULL;
7680         GValue item = { 0, };
7681         GstPad *pad = NULL;
7682         gboolean done = FALSE;
7683         gboolean is_all_drained = TRUE;
7684
7685         MMPLAYER_FENTER();
7686         MMPLAYER_RETURN_IF_FAIL(player);
7687
7688         LOGD("got drained signal");
7689
7690         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7691                 LOGW("Fail to get cmd lock");
7692                 return;
7693         }
7694
7695         if (!__mmplayer_verify_gapless_play_path(player)) {
7696                 LOGD("decoding is finished.");
7697                 MMPLAYER_CMD_UNLOCK(player);
7698                 return;
7699         }
7700
7701         _mmplayer_set_reconfigure_state(player, TRUE);
7702         MMPLAYER_CMD_UNLOCK(player);
7703
7704         /* check decodebin src pads whether they received EOS or not */
7705         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7706
7707         while (!done) {
7708                 switch (gst_iterator_next(iter, &item)) {
7709                 case GST_ITERATOR_OK:
7710                         pad = g_value_get_object(&item);
7711                         if (pad && !GST_PAD_IS_EOS(pad)) {
7712                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7713                                 is_all_drained = FALSE;
7714                                 break;
7715                         }
7716                         g_value_reset(&item);
7717                         break;
7718                 case GST_ITERATOR_RESYNC:
7719                         gst_iterator_resync(iter);
7720                         break;
7721                 case GST_ITERATOR_ERROR:
7722                 case GST_ITERATOR_DONE:
7723                         done = TRUE;
7724                         break;
7725                 }
7726         }
7727         g_value_unset(&item);
7728         gst_iterator_free(iter);
7729
7730         if (!is_all_drained) {
7731                 LOGD("Wait util the all pads get EOS.");
7732                 MMPLAYER_FLEAVE();
7733                 return;
7734         }
7735
7736         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7737         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7738
7739         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7740         MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7741         __mmplayer_deactivate_old_path(player);
7742
7743         MMPLAYER_FLEAVE();
7744 }
7745
7746 void
7747 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7748 {
7749         mmplayer_t *player = (mmplayer_t *)data;
7750         const gchar *klass = NULL;
7751         gchar *factory_name = NULL;
7752
7753         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7754         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7755
7756         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7757
7758         if (__mmplayer_add_dump_buffer_probe(player, element))
7759                 LOGD("add buffer probe");
7760
7761         if (g_strrstr(klass, "Decoder")) {
7762                 if (g_strrstr(klass, "Audio")) {
7763                         player->audio_decoders = g_list_append(player->audio_decoders,
7764                                                                                                                                         g_strdup(GST_ELEMENT_NAME(element)));
7765
7766                         /* update codec info */
7767                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7768                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7769                         player->audiodec_linked = 1;
7770                 } else if (g_strrstr(klass, "Video")) {
7771                         GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7772                         /* update codec info */
7773                         player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7774                         player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7775                         player->videodec_linked = 1;
7776
7777                         if (video_parse) {
7778                                 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7779                                 if (srcpad) {
7780                                         GstCaps *caps = NULL;
7781                                         GstStructure *str = NULL;
7782                                         const gchar *name = NULL;
7783                                         gboolean caps_ret = TRUE;
7784
7785                                         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7786                                         if (caps_ret && str) {
7787                                                 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7788                                                 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7789                                                         if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7790                                                                 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7791                                                                 LOGD("Send SPS and PPS Insertion every IDR frame");
7792                                                         }
7793                                                 }
7794                                         }
7795                                         gst_object_unref(GST_OBJECT(srcpad));
7796                                 }
7797                         }
7798                 }
7799         } else if (g_strrstr(klass, "Demuxer")) {
7800                 if (g_strrstr(klass, "Adaptive")) {
7801                         player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7802                         player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7803
7804                         LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7805                                                         player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7806
7807                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7808                                                         "max-bandwidth", player->adaptive_info.limit.bandwidth,
7809                                                         "max-video-width", player->adaptive_info.limit.width,
7810                                                         "max-video-height", player->adaptive_info.limit.height, NULL);
7811                 } else {
7812 #ifdef __DEBUG__
7813                         LOGD("plugged element is demuxer. take it");
7814 #endif
7815                         player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7816                         player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7817                 }
7818         } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7819                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7820                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7821         }
7822
7823         if (g_strrstr(factory_name, "mpegaudioparse")) {
7824                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7825                         (__mmplayer_is_only_mp3_type(player->type))) {
7826                         LOGD("[mpegaudioparse] set streaming pull mode.");
7827                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7828                 }
7829         } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7830                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7831                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7832
7833                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7834                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7835
7836                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7837                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7838                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7839                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7840                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7841                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7842                 }
7843         }
7844
7845         return;
7846 }
7847
7848 static void
7849 __mmplayer_release_misc(mmplayer_t *player)
7850 {
7851         int i;
7852         bool cur_mode = player->set_mode.rich_audio;
7853         MMPLAYER_FENTER();
7854
7855         MMPLAYER_RETURN_IF_FAIL(player);
7856
7857         player->sent_bos = FALSE;
7858         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7859
7860         player->seek_state = MMPLAYER_SEEK_NONE;
7861
7862         player->total_bitrate = 0;
7863         player->total_maximum_bitrate = 0;
7864
7865         player->not_found_demuxer = 0;
7866
7867         player->last_position = 0;
7868         player->duration = 0;
7869         player->http_content_size = 0;
7870         player->not_supported_codec = MISSING_PLUGIN_NONE;
7871         player->can_support_codec = FOUND_PLUGIN_NONE;
7872         player->pending_seek.is_pending = false;
7873         player->pending_seek.pos = 0;
7874         player->msg_posted = FALSE;
7875         player->has_many_types = FALSE;
7876         player->is_subtitle_force_drop = FALSE;
7877         player->play_subtitle = FALSE;
7878         player->adjust_subtitle_pos = 0;
7879         player->has_closed_caption = FALSE;
7880         player->set_mode.video_export = false;
7881         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7882         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7883         /* recover mode */
7884         player->set_mode.rich_audio = cur_mode;
7885
7886         if (player->audio_device_cb_id > 0 &&
7887                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7888                 LOGW("failed to remove audio device_connected_callback");
7889         player->audio_device_cb_id = 0;
7890
7891         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7892                 player->bitrate[i] = 0;
7893                 player->maximum_bitrate[i] = 0;
7894         }
7895
7896         /* free memory related to audio effect */
7897         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7898
7899         if (player->adaptive_info.var_list) {
7900                 g_list_free_full(player->adaptive_info.var_list, g_free);
7901                 player->adaptive_info.var_list = NULL;
7902         }
7903
7904         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7905         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7906         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7907
7908         /* Reset video360 settings to their defaults in case if the pipeline is to be
7909          * re-created.
7910          * */
7911         player->video360_metadata.is_spherical = -1;
7912         player->is_openal_plugin_used = FALSE;
7913
7914         player->is_content_spherical = FALSE;
7915         player->is_video360_enabled = TRUE;
7916         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7917         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7918         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7919         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7920         player->video360_zoom = 1.0f;
7921         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7922         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7923
7924         player->sound.rg_enable = false;
7925
7926         __mmplayer_initialize_video_roi(player);
7927         MMPLAYER_FLEAVE();
7928 }
7929
7930 static void
7931 __mmplayer_release_misc_post(mmplayer_t *player)
7932 {
7933         gchar *original_uri = NULL;
7934         MMPLAYER_FENTER();
7935
7936         /* player->pipeline is already released before. */
7937         MMPLAYER_RETURN_IF_FAIL(player);
7938
7939         player->video_decoded_cb = NULL;
7940         player->video_decoded_cb_user_param = NULL;
7941         player->video_stream_prerolled = false;
7942
7943         player->audio_decoded_cb = NULL;
7944         player->audio_decoded_cb_user_param = NULL;
7945         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7946
7947         player->audio_stream_changed_cb = NULL;
7948         player->audio_stream_changed_cb_user_param = NULL;
7949
7950         mm_player_set_attribute((MMHandleType)player, NULL,
7951                 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7952
7953         /* clean found audio decoders */
7954         if (player->audio_decoders) {
7955                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7956                 player->audio_decoders = NULL;
7957         }
7958
7959         /* clean the uri list except original uri */
7960         if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7961                 GList *tmp = NULL;
7962                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7963                 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7964                 g_list_free_full(tmp, (GDestroyNotify)g_free);
7965
7966                 if (!original_uri)
7967                         LOGW("failed to get original uri info");
7968
7969                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7970                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7971                 MMPLAYER_FREEIF(original_uri);
7972         }
7973
7974         /* clear the audio stream buffer list */
7975         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7976
7977         /* clear the video stream bo list */
7978         __mmplayer_video_stream_destroy_bo_list(player);
7979         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7980
7981         if (player->profile.input_mem.buf) {
7982                 free(player->profile.input_mem.buf);
7983                 player->profile.input_mem.buf = NULL;
7984         }
7985         player->profile.input_mem.len = 0;
7986         player->profile.input_mem.offset = 0;
7987
7988         player->uri_info.uri_idx = 0;
7989         MMPLAYER_FLEAVE();
7990 }
7991
7992 gboolean
7993 __mmplayer_check_subtitle(mmplayer_t *player)
7994 {
7995         MMHandleType attrs = 0;
7996         char *subtitle_uri = NULL;
7997
7998         MMPLAYER_FENTER();
7999
8000         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8001
8002         /* get subtitle attribute */
8003         attrs = MMPLAYER_GET_ATTRS(player);
8004         if (!attrs)
8005                 return FALSE;
8006
8007         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8008         if (!subtitle_uri || !strlen(subtitle_uri))
8009                 return FALSE;
8010
8011         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8012         player->is_external_subtitle_present = TRUE;
8013
8014         MMPLAYER_FLEAVE();
8015
8016         return TRUE;
8017 }
8018
8019 void
8020 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8021 {
8022         MMPLAYER_RETURN_IF_FAIL(player);
8023
8024         if (player->eos_timer) {
8025                 LOGD("cancel eos timer");
8026                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8027                 player->eos_timer = 0;
8028         }
8029
8030         return;
8031 }
8032
8033 static void
8034 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8035 {
8036         MMPLAYER_FENTER();
8037
8038         MMPLAYER_RETURN_IF_FAIL(player);
8039         MMPLAYER_RETURN_IF_FAIL(sink);
8040
8041         if (first)
8042                 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8043         else
8044                 player->sink_elements = g_list_append(player->sink_elements, sink);
8045
8046         MMPLAYER_FLEAVE();
8047 }
8048
8049 static void
8050 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8051 {
8052         MMPLAYER_FENTER();
8053
8054         MMPLAYER_RETURN_IF_FAIL(player);
8055         MMPLAYER_RETURN_IF_FAIL(sink);
8056
8057         player->sink_elements = g_list_remove(player->sink_elements, sink);
8058
8059         MMPLAYER_FLEAVE();
8060 }
8061
8062 void
8063 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8064         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8065 {
8066         mmplayer_signal_item_t *item = NULL;
8067
8068         MMPLAYER_FENTER();
8069         MMPLAYER_RETURN_IF_FAIL(player);
8070
8071         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8072                 LOGE("invalid signal type [%d]", type);
8073                 return;
8074         }
8075
8076         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8077         if (!item) {
8078                 LOGE("cannot connect signal [%s]", signal);
8079                 return;
8080         }
8081
8082         item->obj = object;
8083         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8084         player->signals[type] = g_list_append(player->signals[type], item);
8085
8086         MMPLAYER_FLEAVE();
8087         return;
8088 }
8089
8090 /* NOTE : be careful with calling this api. please refer to below glib comment
8091  * glib comment : Note that there is a bug in GObject that makes this function much
8092  * less useful than it might seem otherwise. Once gobject is disposed, the callback
8093  * will no longer be called, but, the signal handler is not currently disconnected.
8094  * If the instance is itself being freed at the same time than this doesn't matter,
8095  * since the signal will automatically be removed, but if instance persists,
8096  * then the signal handler will leak. You should not remove the signal yourself
8097  * because in a future versions of GObject, the handler will automatically be
8098  * disconnected.
8099  *
8100  * It's possible to work around this problem in a way that will continue to work
8101  * with future versions of GObject by checking that the signal handler is still
8102  * connected before disconnected it:
8103  *
8104  *  if (g_signal_handler_is_connected(instance, id))
8105  *    g_signal_handler_disconnect(instance, id);
8106  */
8107 static void
8108 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8109 {
8110         GList *sig_list = NULL;
8111         mmplayer_signal_item_t *item = NULL;
8112
8113         MMPLAYER_FENTER();
8114
8115         MMPLAYER_RETURN_IF_FAIL(player);
8116
8117         LOGD("release signals type : %d", type);
8118
8119         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8120                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8121                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8122                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8123                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8124                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8125                 return;
8126         }
8127
8128         sig_list = player->signals[type];
8129
8130         for (; sig_list; sig_list = sig_list->next) {
8131                 item = sig_list->data;
8132
8133                 if (item && item->obj) {
8134                         if (g_signal_handler_is_connected(item->obj, item->sig))
8135                                 g_signal_handler_disconnect(item->obj, item->sig);
8136                 }
8137
8138                 MMPLAYER_FREEIF(item);
8139         }
8140
8141         g_list_free(player->signals[type]);
8142         player->signals[type] = NULL;
8143
8144         MMPLAYER_FLEAVE();
8145
8146         return;
8147 }
8148
8149 int
8150 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8151 {
8152         mmplayer_t *player = 0;
8153         int prev_display_surface_type = 0;
8154
8155         MMPLAYER_FENTER();
8156
8157         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8158
8159         player = MM_PLAYER_CAST(handle);
8160
8161         /* check video sinkbin is created */
8162         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8163                 LOGW("Videosink is already created");
8164                 return MM_ERROR_NONE;
8165         }
8166
8167         LOGD("videosink element is not yet ready");
8168
8169         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8170                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8171                 MMPLAYER_FLEAVE();
8172                 return MM_ERROR_INVALID_ARGUMENT;
8173         }
8174
8175         /* load previous attributes */
8176         if (player->attrs) {
8177                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8178                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8179                 if (prev_display_surface_type == surface_type) {
8180                         LOGD("incoming display surface type is same as previous one, do nothing..");
8181                         MMPLAYER_FLEAVE();
8182                         return MM_ERROR_NONE;
8183                 }
8184         } else {
8185                 LOGE("failed to load attributes");
8186                 MMPLAYER_FLEAVE();
8187                 return MM_ERROR_PLAYER_INTERNAL;
8188         }
8189
8190         /* videobin is not created yet, so we just set attributes related to display surface */
8191         LOGD("store display attribute for given surface type(%d)", surface_type);
8192         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8193                         "display_overlay", wl_surface_id, NULL);
8194
8195         MMPLAYER_FLEAVE();
8196         return MM_ERROR_NONE;
8197 }
8198
8199 /* Note : if silent is true, then subtitle would not be displayed. :*/
8200 int
8201 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8202 {
8203         mmplayer_t *player = (mmplayer_t *)hplayer;
8204
8205         MMPLAYER_FENTER();
8206
8207         /* check player handle */
8208         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8209
8210         player->set_mode.subtitle_off = silent;
8211
8212         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8213
8214         MMPLAYER_FLEAVE();
8215
8216         return MM_ERROR_NONE;
8217 }
8218
8219 int
8220 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8221 {
8222         mmplayer_gst_element_t *mainbin = NULL;
8223         mmplayer_gst_element_t *textbin = NULL;
8224         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8225         GstState current_state = GST_STATE_VOID_PENDING;
8226         GstState element_state = GST_STATE_VOID_PENDING;
8227         GstState element_pending_state = GST_STATE_VOID_PENDING;
8228         gint64 time = 0;
8229         GstEvent *event = NULL;
8230         int result = MM_ERROR_NONE;
8231
8232         GstClock *curr_clock = NULL;
8233         GstClockTime base_time, start_time, curr_time;
8234
8235
8236         MMPLAYER_FENTER();
8237
8238         /* check player handle */
8239         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8240                                                                 player->pipeline &&
8241                                                                 player->pipeline->mainbin &&
8242                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8243
8244         mainbin = player->pipeline->mainbin;
8245         textbin = player->pipeline->textbin;
8246
8247         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8248
8249         // sync clock with current pipeline
8250         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8251         curr_time = gst_clock_get_time(curr_clock);
8252
8253         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8254         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8255
8256         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8257                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8258
8259         if (current_state > GST_STATE_READY) {
8260                 // sync state with current pipeline
8261                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8262                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8263                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8264
8265                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8266                 if (GST_STATE_CHANGE_FAILURE == ret) {
8267                         LOGE("fail to state change.");
8268                         result = MM_ERROR_PLAYER_INTERNAL;
8269                         goto ERROR;
8270                 }
8271         }
8272         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8273         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8274
8275         if (curr_clock) {
8276                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8277                 gst_object_unref(curr_clock);
8278         }
8279
8280         // seek to current position
8281         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8282                 result = MM_ERROR_PLAYER_INVALID_STATE;
8283                 LOGE("gst_element_query_position failed, invalid state");
8284                 goto ERROR;
8285         }
8286
8287         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8288         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);
8289         if (event) {
8290                 _mmplayer_gst_send_event_to_sink(player, event);
8291         } else {
8292                 result = MM_ERROR_PLAYER_INTERNAL;
8293                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8294                 goto ERROR;
8295         }
8296
8297         /* sync state with current pipeline */
8298         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8299         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8300         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8301
8302         return MM_ERROR_NONE;
8303
8304 ERROR:
8305         /* release text pipeline resource */
8306         player->textsink_linked = 0;
8307
8308         /* release signal */
8309         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8310
8311         /* release textbin with it's children */
8312         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8313         MMPLAYER_FREEIF(player->pipeline->textbin);
8314         player->pipeline->textbin = NULL;
8315
8316         /* release subtitle elem */
8317         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8318         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8319
8320         return result;
8321 }
8322
8323 static int
8324 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8325 {
8326         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8327         GstState current_state = GST_STATE_VOID_PENDING;
8328
8329         MMHandleType attrs = 0;
8330         mmplayer_gst_element_t *mainbin = NULL;
8331         mmplayer_gst_element_t *textbin = NULL;
8332
8333         gchar *subtitle_uri = NULL;
8334         int result = MM_ERROR_NONE;
8335         const gchar *charset = NULL;
8336
8337         MMPLAYER_FENTER();
8338
8339         /* check player handle */
8340         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8341                                                                 player->pipeline &&
8342                                                                 player->pipeline->mainbin &&
8343                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8344         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8345
8346         mainbin = player->pipeline->mainbin;
8347         textbin = player->pipeline->textbin;
8348
8349         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8350         if (current_state < GST_STATE_READY) {
8351                 result = MM_ERROR_PLAYER_INVALID_STATE;
8352                 LOGE("Pipeline is not in proper state");
8353                 goto EXIT;
8354         }
8355
8356         attrs = MMPLAYER_GET_ATTRS(player);
8357         if (!attrs) {
8358                 LOGE("cannot get content attribute");
8359                 result = MM_ERROR_PLAYER_INTERNAL;
8360                 goto EXIT;
8361         }
8362
8363         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8364         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8365                 LOGE("subtitle uri is not proper filepath");
8366                 result = MM_ERROR_PLAYER_INVALID_URI;
8367                 goto EXIT;
8368         }
8369
8370         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8371                 LOGE("failed to get storage info of subtitle path");
8372                 result = MM_ERROR_PLAYER_INVALID_URI;
8373                 goto EXIT;
8374         }
8375
8376         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8377         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8378
8379         if (!strcmp(filepath, subtitle_uri)) {
8380                 LOGD("subtitle path is not changed");
8381                 goto EXIT;
8382         } else {
8383                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8384                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8385                         LOGE("failed to set attribute");
8386                         goto EXIT;
8387                 }
8388         }
8389
8390         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8391         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8392         player->subtitle_language_list = NULL;
8393         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8394
8395         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8396         if (ret != GST_STATE_CHANGE_SUCCESS) {
8397                 LOGE("failed to change state of textbin to READY");
8398                 result = MM_ERROR_PLAYER_INTERNAL;
8399                 goto EXIT;
8400         }
8401
8402         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8403         if (ret != GST_STATE_CHANGE_SUCCESS) {
8404                 LOGE("failed to change state of subparse to READY");
8405                 result = MM_ERROR_PLAYER_INTERNAL;
8406                 goto EXIT;
8407         }
8408
8409         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8410         if (ret != GST_STATE_CHANGE_SUCCESS) {
8411                 LOGE("failed to change state of filesrc to READY");
8412                 result = MM_ERROR_PLAYER_INTERNAL;
8413                 goto EXIT;
8414         }
8415
8416         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8417
8418         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8419
8420         charset = _mmplayer_get_charset(filepath);
8421         if (charset) {
8422                 LOGD("detected charset is %s", charset);
8423                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8424         }
8425
8426         result = _mmplayer_sync_subtitle_pipeline(player);
8427
8428 EXIT:
8429         MMPLAYER_FLEAVE();
8430         return result;
8431 }
8432
8433 /* API to switch between external subtitles */
8434 int
8435 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8436 {
8437         int result = MM_ERROR_NONE;
8438         mmplayer_t *player = (mmplayer_t *)hplayer;
8439         char *path = NULL;
8440
8441         MMPLAYER_FENTER();
8442
8443         /* check player handle */
8444         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8445
8446         /* filepath can be null in idle state */
8447         if (filepath) {
8448                 /* check file path */
8449                 if ((path = strstr(filepath, "file://")))
8450                         result = _mmplayer_exist_file_path(path + 7);
8451                 else
8452                         result = _mmplayer_exist_file_path(filepath);
8453
8454                 if (result != MM_ERROR_NONE) {
8455                         LOGE("invalid subtitle path 0x%X", result);
8456                         return result; /* file not found or permission denied */
8457                 }
8458         }
8459
8460         if (!player->pipeline) {
8461                 /* IDLE state */
8462                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8463                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8464                         LOGE("failed to set attribute");
8465                         return MM_ERROR_PLAYER_INTERNAL;
8466                 }
8467         } else {
8468                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8469                 /* check filepath */
8470                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8471
8472                 if (!__mmplayer_check_subtitle(player)) {
8473                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8474                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8475                                 LOGE("failed to set attribute");
8476                                 return MM_ERROR_PLAYER_INTERNAL;
8477                         }
8478
8479                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8480                                 LOGE("fail to create text pipeline");
8481                                 return MM_ERROR_PLAYER_INTERNAL;
8482                         }
8483
8484                         result = _mmplayer_sync_subtitle_pipeline(player);
8485                 } else {
8486                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8487                 }
8488
8489                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8490                 player->is_external_subtitle_added_now = TRUE;
8491
8492                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8493                 if (!player->subtitle_language_list) {
8494                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8495                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8496                                 LOGW("subtitle language list is not updated yet");
8497                 }
8498                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8499         }
8500
8501         MMPLAYER_FLEAVE();
8502         return result;
8503 }
8504
8505 static int
8506 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8507 {
8508         guint active_idx = 0;
8509         GstStream *stream = NULL;
8510         GList *streams = NULL;
8511         GstCaps *caps = NULL;
8512
8513         MMPLAYER_FENTER();
8514         LOGD("Switching Streams... type: %d, index: %d", type, index);
8515
8516         player->track[type].active_track_index = index;
8517
8518         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8519                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8520                 LOGD("track type:%d, total: %d, active: %d", i,
8521                                 player->track[i].total_track_num, player->track[i].active_track_index);
8522                 if (player->track[i].total_track_num > 0 &&
8523                         player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8524                         active_idx = player->track[i].active_track_index;
8525                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8526                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8527                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8528
8529                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8530                                 caps = gst_stream_get_caps(stream);
8531                                 if (caps) {
8532                                         _mmplayer_set_audio_attrs(player, caps);
8533                                         gst_caps_unref(caps);
8534                                 }
8535                         }
8536                 }
8537         }
8538
8539         if (streams) {
8540                 LOGD("send select stream event");
8541                 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8542                                 gst_event_new_select_streams(streams));
8543                 g_list_free(streams);
8544         }
8545
8546         /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8547         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8548                 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8549
8550                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8551                         pos_nsec = player->last_position;
8552
8553                 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8554
8555                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8556                                         player->playback_rate, GST_FORMAT_TIME,
8557                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8558                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8559                         LOGW("failed to seek");
8560                         return MM_ERROR_PLAYER_INTERNAL;
8561                 }
8562         }
8563
8564         MMPLAYER_FLEAVE();
8565         return MM_ERROR_NONE;
8566 }
8567
8568 static int
8569 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8570 {
8571         int result = MM_ERROR_NONE;
8572         gchar *change_pad_name = NULL;
8573         GstPad *sinkpad = NULL;
8574         mmplayer_gst_element_t *mainbin = NULL;
8575         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8576         GstCaps *caps = NULL;
8577         gint total_track_num = 0;
8578
8579         MMPLAYER_FENTER();
8580
8581         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8582                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8583
8584         LOGD("Change Track(%d) to %d", type, index);
8585
8586         mainbin = player->pipeline->mainbin;
8587
8588         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8589                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8590         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8591                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8592         } else {
8593                 /* Changing Video Track is not supported. */
8594                 LOGE("Track Type Error");
8595                 goto EXIT;
8596         }
8597
8598         if (mainbin[elem_idx].gst == NULL) {
8599                 result = MM_ERROR_PLAYER_NO_OP;
8600                 LOGD("Req track doesn't exist");
8601                 goto EXIT;
8602         }
8603
8604         total_track_num = player->track[type].total_track_num;
8605         if (total_track_num <= 0) {
8606                 result = MM_ERROR_PLAYER_NO_OP;
8607                 LOGD("Language list is not available");
8608                 goto EXIT;
8609         }
8610
8611         if ((index < 0) || (index >= total_track_num)) {
8612                 result = MM_ERROR_INVALID_ARGUMENT;
8613                 LOGD("Not a proper index : %d", index);
8614                 goto EXIT;
8615         }
8616
8617         /*To get the new pad from the selector*/
8618         change_pad_name = g_strdup_printf("sink_%u", index);
8619         if (change_pad_name == NULL) {
8620                 result = MM_ERROR_PLAYER_INTERNAL;
8621                 LOGD("Pad does not exists");
8622                 goto EXIT;
8623         }
8624
8625         LOGD("new active pad name: %s", change_pad_name);
8626
8627         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8628         if (sinkpad == NULL) {
8629                 LOGD("sinkpad is NULL");
8630                 result = MM_ERROR_PLAYER_INTERNAL;
8631                 goto EXIT;
8632         }
8633
8634         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8635         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8636
8637         caps = gst_pad_get_current_caps(sinkpad);
8638         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8639
8640         if (sinkpad)
8641                 gst_object_unref(sinkpad);
8642
8643         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8644                 _mmplayer_set_audio_attrs(player, caps);
8645
8646         if (caps)
8647                 gst_caps_unref(caps);
8648
8649 EXIT:
8650         MMPLAYER_FREEIF(change_pad_name);
8651         return result;
8652 }
8653
8654 int
8655 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8656 {
8657         int result = MM_ERROR_NONE;
8658         mmplayer_t *player = NULL;
8659         mmplayer_gst_element_t *mainbin = NULL;
8660
8661         gint current_active_index = 0;
8662
8663         GstState current_state = GST_STATE_VOID_PENDING;
8664         gint64 time = 0;
8665
8666         MMPLAYER_FENTER();
8667
8668         player = (mmplayer_t *)hplayer;
8669         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670
8671         if (!player->pipeline) {
8672                 LOGE("Track %d pre setting -> %d", type, index);
8673
8674                 player->track[type].active_track_index = index;
8675                 goto EXIT;
8676         }
8677
8678         mainbin = player->pipeline->mainbin;
8679
8680         current_active_index = player->track[type].active_track_index;
8681
8682         /*If index is same as running index no need to change the pad*/
8683         if (current_active_index == index)
8684                 goto EXIT;
8685
8686         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8687                 result = MM_ERROR_PLAYER_INVALID_STATE;
8688                 goto EXIT;
8689         }
8690
8691         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8692         if (current_state < GST_STATE_PAUSED) {
8693                 result = MM_ERROR_PLAYER_INVALID_STATE;
8694                 LOGW("Pipeline not in proper state");
8695                 goto EXIT;
8696         }
8697
8698         if (MMPLAYER_USE_DECODEBIN(player))
8699                 result = __mmplayer_change_selector_pad(player, type, index);
8700         else
8701                 result = __mmplayer_switch_stream(player, type, index);
8702
8703         if (result != MM_ERROR_NONE) {
8704                 LOGE("failed to change track");
8705                 goto EXIT;
8706         }
8707
8708         player->track[type].active_track_index = index;
8709
8710         if (MMPLAYER_USE_DECODEBIN(player)) {
8711                 GstEvent *event = NULL;
8712                 if (current_state == GST_STATE_PLAYING) {
8713                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8714                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8715                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8716                         if (event) {
8717                                 _mmplayer_gst_send_event_to_sink(player, event);
8718                         } else {
8719                                 result = MM_ERROR_PLAYER_INTERNAL;
8720                                 goto EXIT;
8721                         }
8722                 }
8723         }
8724
8725 EXIT:
8726         return result;
8727 }
8728
8729 int
8730 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8731 {
8732         mmplayer_t *player = (mmplayer_t *)hplayer;
8733
8734         MMPLAYER_FENTER();
8735
8736         /* check player handle */
8737         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8738
8739         *silent = player->set_mode.subtitle_off;
8740
8741         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8742
8743         MMPLAYER_FLEAVE();
8744
8745         return MM_ERROR_NONE;
8746 }
8747
8748 static gboolean
8749 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8750 {
8751         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8752         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8753
8754         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8755         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8756
8757         int idx = 0;
8758
8759         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8760                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8761                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8762                         mmplayer_dump_t *dump_s;
8763                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8764                         if (dump_s == NULL) {
8765                                 LOGE("malloc fail");
8766                                 return FALSE;
8767                         }
8768
8769                         dump_s->dump_element_file = NULL;
8770                         dump_s->dump_pad = NULL;
8771                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8772
8773                         if (dump_s->dump_pad) {
8774                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8775                                 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]);
8776                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8777                                 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);
8778                                 /* add list for removed buffer probe and close FILE */
8779                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8780                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8781                                 return TRUE;
8782                         } else {
8783                                 MMPLAYER_FREEIF(dump_s);
8784                                 LOGE("failed to get %s sink pad added", factory_name);
8785                         }
8786                 }
8787         }
8788         return FALSE;
8789 }
8790
8791 static GstPadProbeReturn
8792 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8793 {
8794         FILE *dump_data = (FILE *)u_data;
8795 //      int written = 0;
8796         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8797         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8798
8799         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8800
8801         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8802 #ifdef __DEBUG__
8803         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8804 #endif
8805         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8806
8807         gst_buffer_unmap(buffer, &probe_info);
8808
8809         return GST_PAD_PROBE_OK;
8810 }
8811
8812 static void
8813 __mmplayer_release_dump_list(GList *dump_list)
8814 {
8815         GList *d_list = dump_list;
8816
8817         if (!d_list)
8818                 return;
8819
8820         for (; d_list; d_list = g_list_next(d_list)) {
8821                 mmplayer_dump_t *dump_s = d_list->data;
8822                 if (dump_s->dump_pad) {
8823                         if (dump_s->probe_handle_id)
8824                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8825                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8826                 }
8827                 if (dump_s->dump_element_file) {
8828                         fclose(dump_s->dump_element_file);
8829                         dump_s->dump_element_file = NULL;
8830                 }
8831                 MMPLAYER_FREEIF(dump_s);
8832         }
8833         g_list_free(dump_list);
8834         dump_list = NULL;
8835 }
8836
8837 int
8838 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8839 {
8840         mmplayer_t *player = (mmplayer_t *)hplayer;
8841
8842         MMPLAYER_FENTER();
8843
8844         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8845         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8846
8847         *exist = (bool)player->has_closed_caption;
8848
8849         MMPLAYER_FLEAVE();
8850
8851         return MM_ERROR_NONE;
8852 }
8853
8854 void
8855 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8856 {
8857         MMPLAYER_FENTER();
8858         if (buffer) {
8859 #ifdef __DEBUG__
8860                 LOGD("unref internal gst buffer %p", buffer);
8861 #endif
8862                 gst_buffer_unref((GstBuffer *)buffer);
8863                 buffer = NULL;
8864         }
8865         MMPLAYER_FLEAVE();
8866 }
8867
8868 int
8869 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8870 {
8871         mmplayer_t *player = (mmplayer_t *)hplayer;
8872
8873         MMPLAYER_FENTER();
8874
8875         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8876         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8877
8878         if (MMPLAYER_IS_STREAMING(player))
8879                 *timeout = (int)player->ini.live_state_change_timeout;
8880         else
8881                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8882
8883         LOGD("timeout = %d", *timeout);
8884
8885         MMPLAYER_FLEAVE();
8886         return MM_ERROR_NONE;
8887 }
8888
8889 static void
8890 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8891 {
8892         int i = 0;
8893         MMPLAYER_FENTER();
8894         MMPLAYER_RETURN_IF_FAIL(player);
8895
8896         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8897
8898                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8899                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8900                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8901                         player->storage_info[i].id = -1;
8902                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8903
8904                         if (path_type != MMPLAYER_PATH_MAX)
8905                                 break;
8906                 }
8907         }
8908
8909         MMPLAYER_FLEAVE();
8910 }
8911
8912 int
8913 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8914 {
8915         int ret = MM_ERROR_NONE;
8916         mmplayer_t *player = (mmplayer_t *)hplayer;
8917         MMMessageParamType msg_param = {0, };
8918
8919         MMPLAYER_FENTER();
8920         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8921
8922         LOGW("state changed storage %d:%d", id, state);
8923
8924         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8925                 return MM_ERROR_NONE;
8926
8927         /* FIXME: text path should be handled separately. */
8928         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8929                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8930                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8931                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8932                 LOGW("external storage is removed");
8933
8934                 if (player->msg_posted == FALSE) {
8935                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8936                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8937                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8938                         player->msg_posted = TRUE;
8939                 }
8940
8941                 /* unrealize the player */
8942                 ret = _mmplayer_unrealize(hplayer);
8943                 if (ret != MM_ERROR_NONE)
8944                         LOGE("failed to unrealize");
8945         }
8946
8947         MMPLAYER_FLEAVE();
8948         return ret;
8949 }
8950
8951 int
8952 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8953 {
8954         int ret = MM_ERROR_NONE;
8955         mmplayer_t *player = (mmplayer_t *)hplayer;
8956         int idx = 0, total = 0;
8957         gchar *result = NULL, *tmp = NULL;
8958
8959         MMPLAYER_FENTER();
8960         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8961         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8962
8963         total = *num = g_list_length(player->adaptive_info.var_list);
8964         if (total <= 0) {
8965                 LOGW("There is no stream variant info.");
8966                 return ret;
8967         }
8968
8969         result = g_strdup("");
8970         for (idx = 0 ; idx < total ; idx++) {
8971                 stream_variant_t *v_data = NULL;
8972                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8973
8974                 if (v_data) {
8975                         gchar data[64] = {0};
8976                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8977
8978                         tmp = g_strconcat(result, data, NULL);
8979                         g_free(result);
8980                         result = tmp;
8981                 } else {
8982                         LOGW("There is no variant data in %d", idx);
8983                         (*num)--;
8984                 }
8985         }
8986
8987         *var_info = (char *)result;
8988
8989         LOGD("variant info %d:%s", *num, *var_info);
8990         MMPLAYER_FLEAVE();
8991         return ret;
8992 }
8993
8994 int
8995 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8996 {
8997         int ret = MM_ERROR_NONE;
8998         mmplayer_t *player = (mmplayer_t *)hplayer;
8999
9000         MMPLAYER_FENTER();
9001         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9002
9003         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9004
9005         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9006         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9007         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9008
9009         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9010                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9011                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9012                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9013
9014                 /* FIXME: seek to current position for applying new variant limitation */
9015         }
9016
9017         MMPLAYER_FLEAVE();
9018         return ret;
9019
9020 }
9021
9022 int
9023 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9024 {
9025         int ret = MM_ERROR_NONE;
9026         mmplayer_t *player = (mmplayer_t *)hplayer;
9027
9028         MMPLAYER_FENTER();
9029         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9031
9032         *bandwidth = player->adaptive_info.limit.bandwidth;
9033         *width = player->adaptive_info.limit.width;
9034         *height = player->adaptive_info.limit.height;
9035
9036         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9037
9038         MMPLAYER_FLEAVE();
9039         return ret;
9040 }
9041
9042 int
9043 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9044 {
9045         int ret = MM_ERROR_NONE;
9046         mmplayer_t *player = (mmplayer_t *)hplayer;
9047
9048         MMPLAYER_FENTER();
9049         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9050         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9051         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9052
9053         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9054
9055         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9056                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9057         else /* live case */
9058                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9059
9060         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9061
9062         MMPLAYER_FLEAVE();
9063         return ret;
9064 }
9065
9066 int
9067 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9068 {
9069 #define IDX_FIRST_SW_CODEC 0
9070         mmplayer_t *player = (mmplayer_t *)hplayer;
9071         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9072         const char *attr_name = NULL;
9073         const char *default_type = NULL;
9074         const char *element_hw = NULL;
9075         const char *element_sw = NULL;
9076
9077         MMPLAYER_FENTER();
9078         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9079
9080         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9081
9082         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9083         switch (stream_type) {
9084         case MM_PLAYER_STREAM_TYPE_AUDIO:
9085                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9086                 default_type = player->ini.audiocodec_default_type;
9087                 element_hw = player->ini.audiocodec_element_hw;
9088                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9089                 break;
9090         case MM_PLAYER_STREAM_TYPE_VIDEO:
9091                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9092                 default_type = player->ini.videocodec_default_type;
9093                 element_hw = player->ini.videocodec_element_hw;
9094                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9095                 break;
9096         default:
9097                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9098                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9099                 break;
9100         }
9101
9102         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9103
9104         if (!strcmp(default_type, "sw"))
9105                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9106         else
9107                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9108
9109         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9110                 codec_type = default_codec_type;
9111
9112         /* to support codec selection, codec info have to be added in ini file.
9113            in case of hw codec is selected, filter elements should be applied
9114            depending on the hw capabilities. */
9115         if (codec_type != default_codec_type) {
9116                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9117                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9118                         LOGE("There is no codec for type %d", codec_type);
9119                         return MM_ERROR_PLAYER_NO_OP;
9120                 }
9121
9122                 LOGD("sorting is required");
9123                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9124                         player->need_audio_dec_sorting = TRUE;
9125                 else
9126                         player->need_video_dec_sorting = TRUE;
9127         }
9128
9129         LOGD("update %s codec_type to %d", attr_name, codec_type);
9130         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9131
9132         MMPLAYER_FLEAVE();
9133         return MM_ERROR_NONE;
9134 }
9135
9136 int
9137 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9138 {
9139         mmplayer_t *player = (mmplayer_t *)hplayer;
9140         GstElement *rg_vol_element = NULL;
9141
9142         MMPLAYER_FENTER();
9143
9144         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9145
9146         player->sound.rg_enable = enabled;
9147
9148         /* just hold rgvolume enable value if pipeline is not ready */
9149         if (!player->pipeline || !player->pipeline->audiobin) {
9150                 LOGD("pipeline is not ready. holding rgvolume enable value");
9151                 return MM_ERROR_NONE;
9152         }
9153
9154         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9155
9156         if (!rg_vol_element) {
9157                 LOGD("rgvolume element is not created");
9158                 return MM_ERROR_PLAYER_INTERNAL;
9159         }
9160
9161         if (enabled)
9162                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9163         else
9164                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9165
9166         MMPLAYER_FLEAVE();
9167
9168         return MM_ERROR_NONE;
9169 }
9170
9171 int
9172 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9173 {
9174         mmplayer_t *player = (mmplayer_t *)hplayer;
9175         GstElement *rg_vol_element = NULL;
9176         gboolean enable = FALSE;
9177
9178         MMPLAYER_FENTER();
9179
9180         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9181         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9182
9183         /* just hold enable_rg value if pipeline is not ready */
9184         if (!player->pipeline || !player->pipeline->audiobin) {
9185                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9186                 *enabled = player->sound.rg_enable;
9187                 return MM_ERROR_NONE;
9188         }
9189
9190         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9191
9192         if (!rg_vol_element) {
9193                 LOGD("rgvolume element is not created");
9194                 return MM_ERROR_PLAYER_INTERNAL;
9195         }
9196
9197         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9198         *enabled = (bool)enable;
9199
9200         MMPLAYER_FLEAVE();
9201
9202         return MM_ERROR_NONE;
9203 }
9204
9205 int
9206 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9207 {
9208         mmplayer_t *player = (mmplayer_t *)hplayer;
9209         MMHandleType attrs = 0;
9210         int handle = 0;
9211         int ret = MM_ERROR_NONE;
9212
9213         MMPLAYER_FENTER();
9214
9215         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9216
9217         attrs = MMPLAYER_GET_ATTRS(player);
9218         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9219
9220         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9221         if (!handle) {
9222                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9223                 return MM_ERROR_PLAYER_INTERNAL;
9224         }
9225
9226         player->video_roi.scale_x = scale_x;
9227         player->video_roi.scale_y = scale_y;
9228         player->video_roi.scale_width = scale_width;
9229         player->video_roi.scale_height = scale_height;
9230
9231         /* check video sinkbin is created */
9232         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9233                 return MM_ERROR_NONE;
9234
9235         if (!gst_video_overlay_set_video_roi_area(
9236                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9237                 scale_x, scale_y, scale_width, scale_height))
9238                 ret = MM_ERROR_PLAYER_INTERNAL;
9239         else
9240                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9241                         scale_x, scale_y, scale_width, scale_height);
9242
9243         MMPLAYER_FLEAVE();
9244
9245         return ret;
9246 }
9247
9248 int
9249 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9250 {
9251         mmplayer_t *player = (mmplayer_t *)hplayer;
9252         int ret = MM_ERROR_NONE;
9253
9254         MMPLAYER_FENTER();
9255
9256         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9257         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9258
9259         *scale_x = player->video_roi.scale_x;
9260         *scale_y = player->video_roi.scale_y;
9261         *scale_width = player->video_roi.scale_width;
9262         *scale_height = player->video_roi.scale_height;
9263
9264         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9265                 *scale_x, *scale_y, *scale_width, *scale_height);
9266
9267         return ret;
9268 }
9269
9270 int
9271 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9272 {
9273         mmplayer_t *player = (mmplayer_t *)hplayer;
9274
9275         MMPLAYER_FENTER();
9276
9277         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9278
9279         player->client_pid = pid;
9280
9281         LOGD("client pid[%d] %p", pid, player);
9282
9283         MMPLAYER_FLEAVE();
9284
9285         return MM_ERROR_NONE;
9286 }
9287
9288 int
9289 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9290 {
9291         mmplayer_t *player = (mmplayer_t *)hplayer;
9292         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9293         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9294
9295         MMPLAYER_FENTER();
9296
9297         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9298         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9299
9300         *available = true;
9301         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9302
9303         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9304
9305         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9306                 return MM_ERROR_NONE;
9307
9308         /* in case of audio codec default type is HW */
9309         switch(opt) {
9310                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9311                         if (player->ini.support_audio_effect)
9312                                 return MM_ERROR_NONE;
9313                         elem_id = MMPLAYER_A_FILTER;
9314                 break;
9315                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9316                         if (player->ini.support_replaygain_control)
9317                                 return MM_ERROR_NONE;
9318                         elem_id = MMPLAYER_A_RGVOL;
9319                 break;
9320                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9321                         if (player->ini.support_pitch_control)
9322                                 return MM_ERROR_NONE;
9323                         elem_id = MMPLAYER_A_PITCH;
9324                 break;
9325                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9326                         if (player->ini.support_audio_effect)
9327                                 return MM_ERROR_NONE;
9328                 break;
9329                 /* default case handling is not required */
9330         }
9331
9332         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9333                 LOGW("audio control option [%d] is not available", opt);
9334                 *available = false;
9335         } else {
9336                 /* setting pcm exporting option is allowed before READY state */
9337                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9338                         return MM_ERROR_PLAYER_INVALID_STATE;
9339
9340                 /* check whether the audio filter exist or not after READY state,
9341                    because the sw codec could be added during auto-plugging in some cases */
9342                 if (!player->pipeline ||
9343                         !player->pipeline->audiobin ||
9344                         !player->pipeline->audiobin[elem_id].gst) {
9345                         LOGW("there is no audio elem [%d]", elem_id);
9346                         *available = false;
9347                 }
9348         }
9349
9350         LOGD("audio control opt %d, available %d", opt, *available);
9351
9352         MMPLAYER_FLEAVE();
9353
9354         return MM_ERROR_NONE;
9355 }
9356
9357 static gboolean
9358 __mmplayer_update_duration_value(mmplayer_t *player)
9359 {
9360         gboolean ret = FALSE;
9361         gint64 dur_nsec = 0;
9362         LOGD("try to update duration");
9363
9364         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9365                 player->duration = dur_nsec;
9366                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9367                 ret = TRUE;
9368         }
9369
9370         if (player->duration < 0) {
9371                 LOGW("duration is Non-Initialized !!!");
9372                 player->duration = 0;
9373         }
9374
9375         /* update streaming service type */
9376         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9377
9378         /* check duration is OK */
9379         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9380                 /* FIXIT : find another way to get duration here. */
9381                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9382
9383         return ret;
9384 }
9385
9386 static gboolean
9387 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9388 {
9389         /* update audio params
9390         NOTE : We need original audio params and it can be only obtained from src pad of audio
9391         decoder. Below code only valid when we are not using 'resampler' just before
9392         'audioconverter'. */
9393         GstCaps *caps_a = NULL;
9394         GstPad *pad = NULL;
9395         gint samplerate = 0, channels = 0;
9396         GstStructure *p = NULL;
9397         GstElement *aconv = NULL;
9398
9399         LOGD("try to update audio attrs");
9400
9401         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9402
9403         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9404                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9405         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9406                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9407         } else {
9408                 LOGE("there is no audio converter");
9409                 return FALSE;
9410         }
9411
9412         pad = gst_element_get_static_pad(aconv, "sink");
9413
9414         if (!pad) {
9415                 LOGW("failed to get pad from audio converter");
9416                 return FALSE;
9417         }
9418
9419         caps_a = gst_pad_get_current_caps(pad);
9420         if (!caps_a) {
9421                 LOGW("not ready to get audio caps");
9422                 gst_object_unref(pad);
9423                 return FALSE;
9424         }
9425
9426         p = gst_caps_get_structure(caps_a, 0);
9427         gst_structure_get_int(p, "rate", &samplerate);
9428         gst_structure_get_int(p, "channels", &channels);
9429
9430         mm_player_set_attribute((MMHandleType)player, NULL,
9431                         "content_audio_samplerate", samplerate,
9432                         "content_audio_channels", channels, NULL);
9433
9434         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9435
9436         gst_caps_unref(caps_a);
9437         gst_object_unref(pad);
9438
9439         return TRUE;
9440 }
9441
9442 static gboolean
9443 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9444 {
9445         LOGD("try to update video attrs");
9446
9447         GstCaps *caps_v = NULL;
9448         GstPad *pad = NULL;
9449         gint tmpNu, tmpDe;
9450         gint width, height;
9451         GstStructure *p = NULL;
9452
9453         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9454         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9455
9456         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9457         if (!pad) {
9458                 LOGD("no videosink sink pad");
9459                 return FALSE;
9460         }
9461
9462         caps_v = gst_pad_get_current_caps(pad);
9463         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9464         if (!caps_v && player->v_stream_caps) {
9465                 caps_v = player->v_stream_caps;
9466                 gst_caps_ref(caps_v);
9467         }
9468
9469         if (!caps_v) {
9470                 LOGD("no negotiated caps from videosink");
9471                 gst_object_unref(pad);
9472                 return FALSE;
9473         }
9474
9475         p = gst_caps_get_structure(caps_v, 0);
9476         gst_structure_get_int(p, "width", &width);
9477         gst_structure_get_int(p, "height", &height);
9478
9479         mm_player_set_attribute((MMHandleType)player, NULL,
9480                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9481
9482         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9483
9484         SECURE_LOGD("width : %d     height : %d", width, height);
9485
9486         gst_caps_unref(caps_v);
9487         gst_object_unref(pad);
9488
9489         if (tmpDe > 0) {
9490                 mm_player_set_attribute((MMHandleType)player, NULL,
9491                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9492                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9493         }
9494
9495         return TRUE;
9496 }
9497
9498 static gboolean
9499 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9500 {
9501         gboolean ret = FALSE;
9502         guint64 data_size = 0;
9503         gchar *path = NULL;
9504         struct stat sb;
9505
9506         /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9507         if (!player->duration)
9508                 return FALSE;
9509
9510         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9511                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9512                 if (stat(path, &sb) == 0)
9513                         data_size = (guint64)sb.st_size;
9514
9515         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9516                 data_size = player->http_content_size;
9517         }
9518
9519         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9520
9521         if (data_size) {
9522                 guint64 bitrate = 0;
9523                 guint64 msec_dur = 0;
9524
9525                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9526                 if (msec_dur > 0) {
9527                         bitrate = data_size * 8 * 1000 / msec_dur;
9528                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9529                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9530                         mm_player_set_attribute((MMHandleType)player, NULL,
9531                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9532                         ret = TRUE;
9533                 } else {
9534                         LOGD("player duration is less than 0");
9535                 }
9536         }
9537
9538         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9539                 if (player->total_bitrate) {
9540                         mm_player_set_attribute((MMHandleType)player, NULL,
9541                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9542                         ret = TRUE;
9543                 }
9544         }
9545
9546         return ret;
9547 }
9548
9549 static void
9550 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9551 {
9552         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9553         data->uri_type = uri_type;
9554 }
9555
9556 static int
9557 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9558 {
9559         int ret = MM_ERROR_PLAYER_INVALID_URI;
9560         int mem_size = 0;
9561         char *buffer = NULL;
9562         char *seperator = strchr(path, ',');
9563         char ext[100] = {0,}, size[100] = {0,};
9564
9565         if (seperator) {
9566                 if ((buffer = strstr(path, "ext="))) {
9567                         buffer += strlen("ext=");
9568
9569                         if (strlen(buffer)) {
9570                                 strncpy(ext, buffer, 99);
9571
9572                                 if ((seperator = strchr(ext, ','))
9573                                         || (seperator = strchr(ext, ' '))
9574                                         || (seperator = strchr(ext, '\0'))) {
9575                                         seperator[0] = '\0';
9576                                 }
9577                         }
9578                 }
9579
9580                 if ((buffer = strstr(path, "size="))) {
9581                         buffer += strlen("size=");
9582
9583                         if (strlen(buffer) > 0) {
9584                                 strncpy(size, buffer, 99);
9585
9586                                 if ((seperator = strchr(size, ','))
9587                                         || (seperator = strchr(size, ' '))
9588                                         || (seperator = strchr(size, '\0'))) {
9589                                         seperator[0] = '\0';
9590                                 }
9591
9592                                 mem_size = atoi(size);
9593                         }
9594                 }
9595         }
9596
9597         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9598
9599         if (mem_size && param) {
9600                 if (data->input_mem.buf)
9601                         free(data->input_mem.buf);
9602                 data->input_mem.buf = malloc(mem_size);
9603
9604                 if (data->input_mem.buf) {
9605                         memcpy(data->input_mem.buf, param, mem_size);
9606                         data->input_mem.len = mem_size;
9607                         ret = MM_ERROR_NONE;
9608                 } else {
9609                         LOGE("failed to alloc mem %d", mem_size);
9610                         ret = MM_ERROR_PLAYER_INTERNAL;
9611                 }
9612
9613                 data->input_mem.offset = 0;
9614                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9615         }
9616
9617         return ret;
9618 }
9619
9620 static int
9621 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9622 {
9623         gchar *location = NULL;
9624         GError *err = NULL;
9625         char *path = NULL;
9626         int ret = MM_ERROR_NONE;
9627
9628         if ((path = strstr(uri, "file://"))) {
9629                 location = g_filename_from_uri(uri, NULL, &err);
9630                 if (!location || (err != NULL)) {
9631                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9632                                 (err != NULL) ? err->message : "unknown error");
9633                         if (err)
9634                                 g_error_free(err);
9635
9636                         MMPLAYER_FREEIF(location);
9637
9638                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9639                         return MM_ERROR_PLAYER_INVALID_URI;
9640                 }
9641                 LOGD("path from uri: %s", location);
9642         }
9643
9644         path = (location != NULL) ? (location) : ((char *)uri);
9645
9646
9647         ret = _mmplayer_exist_file_path(path);
9648
9649         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9650         if (ret == MM_ERROR_NONE) {
9651                 if (_mmplayer_is_sdp_file(path)) {
9652                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9653                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9654                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9655                 } else {
9656                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9657                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9658                 }
9659         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9660                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9661         } else {
9662                 LOGE("invalid uri, could not play..");
9663                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9664         }
9665
9666         MMPLAYER_FREEIF(location);
9667
9668         return ret;
9669 }
9670
9671 static mmplayer_video_decoded_data_info_t *
9672 __mmplayer_create_stream_from_pad(GstPad *pad)
9673 {
9674         GstCaps *caps = NULL;
9675         GstStructure *structure = NULL;
9676         unsigned int fourcc = 0;
9677         const gchar *string_format = NULL;
9678         mmplayer_video_decoded_data_info_t *stream = NULL;
9679         gint width, height;
9680         MMPixelFormatType format;
9681         GstVideoInfo info;
9682
9683         caps = gst_pad_get_current_caps(pad);
9684         if (!caps) {
9685                 LOGE("Caps is NULL.");
9686                 return NULL;
9687         }
9688
9689 #ifdef __DEBUG__
9690         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9691 #endif
9692         structure = gst_caps_get_structure(caps, 0);
9693         gst_structure_get_int(structure, "width", &width);
9694         gst_structure_get_int(structure, "height", &height);
9695         string_format = gst_structure_get_string(structure, "format");
9696
9697         if (string_format)
9698                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9699         format = _mmplayer_get_pixtype(fourcc);
9700         gst_video_info_from_caps(&info, caps);
9701         gst_caps_unref(caps);
9702
9703         /* moved here */
9704         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9705                 LOGE("Wrong condition!!");
9706                 return NULL;
9707         }
9708
9709         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9710         if (!stream) {
9711                 LOGE("failed to alloc mem for video data");
9712                 return NULL;
9713         }
9714
9715         stream->width = width;
9716         stream->height = height;
9717         stream->format = format;
9718         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9719
9720         return stream;
9721 }
9722
9723 static void
9724 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9725 {
9726         unsigned int pitch = 0;
9727         unsigned int size = 0;
9728         int index = 0;
9729         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9730         tbm_bo bo = NULL;
9731
9732         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9733                 bo = gst_tizen_memory_get_bos(mem, index);
9734                 if (bo)
9735                         stream->bo[index] = tbm_bo_ref(bo);
9736                 else
9737                         LOGE("failed to get bo for index %d", index);
9738         }
9739
9740         for (index = 0; index < stream->plane_num; index++) {
9741                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9742                 stream->stride[index] = pitch;
9743                 if (pitch)
9744                         stream->elevation[index] = size / pitch;
9745                 else
9746                         stream->elevation[index] = stream->height;
9747         }
9748 }
9749
9750 static gboolean
9751 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9752 {
9753         if (stream->format == MM_PIXEL_FORMAT_I420) {
9754                 int ret = TBM_SURFACE_ERROR_NONE;
9755                 tbm_surface_h surface;
9756                 tbm_surface_info_s info;
9757
9758                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9759
9760                 ret = tbm_surface_get_info(surface, &info);
9761                 if (ret != TBM_SURFACE_ERROR_NONE) {
9762                         tbm_surface_destroy(surface);
9763                         return FALSE;
9764                 }
9765
9766                 tbm_surface_destroy(surface);
9767                 stream->stride[0] = info.planes[0].stride;
9768                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9769                 stream->stride[1] = info.planes[1].stride;
9770                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9771                 stream->stride[2] = info.planes[2].stride;
9772                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9773                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9774         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9775                 stream->stride[0] = stream->width * 4;
9776                 stream->elevation[0] = stream->height;
9777                 stream->bo_size = stream->stride[0] * stream->height;
9778         } else {
9779                 LOGE("Not support format %d", stream->format);
9780                 return FALSE;
9781         }
9782
9783         return TRUE;
9784 }
9785
9786 static gboolean
9787 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9788 {
9789         tbm_bo_handle thandle;
9790         gboolean is_mapped;
9791         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9792         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9793         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9794         int i = 0;
9795         int j = 0;
9796         int k = 0;
9797         unsigned char *src = NULL;
9798         unsigned char *dest = NULL;
9799         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9800
9801         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9802         if (!is_mapped) {
9803                 LOGE("fail to gst_memory_map");
9804                 return FALSE;
9805         }
9806
9807         if (!mapinfo.data) {
9808                 LOGE("data pointer is wrong");
9809                 goto ERROR;
9810         }
9811
9812         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9813         if (!stream->bo[0]) {
9814                 LOGE("Fail to tbm_bo_alloc!!");
9815                 goto ERROR;
9816         }
9817
9818         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9819         if (!thandle.ptr) {
9820                 LOGE("thandle pointer is wrong");
9821                 goto ERROR;
9822         }
9823
9824         if (stream->format == MM_PIXEL_FORMAT_I420) {
9825                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9826                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9827                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9828                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9829
9830                 dest_offset[0] = 0;
9831                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9832                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9833
9834                 for (i = 0; i < 3; i++) {
9835                         src = mapinfo.data + src_offset[i];
9836                         dest = thandle.ptr + dest_offset[i];
9837
9838                         if (i > 0)
9839                                 k = 1;
9840
9841                         for (j = 0; j < stream->height >> k; j++) {
9842                                 memcpy(dest, src, stream->width>>k);
9843                                 src += src_stride[i];
9844                                 dest += stream->stride[i];
9845                         }
9846                 }
9847         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9848                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9849         } else {
9850                 LOGE("Not support format %d", stream->format);
9851                 goto ERROR;
9852         }
9853
9854         tbm_bo_unmap(stream->bo[0]);
9855         gst_memory_unmap(mem, &mapinfo);
9856
9857         return TRUE;
9858
9859 ERROR:
9860         if (stream->bo[0])
9861                 tbm_bo_unmap(stream->bo[0]);
9862
9863         if (is_mapped)
9864                 gst_memory_unmap(mem, &mapinfo);
9865
9866         return FALSE;
9867 }
9868
9869 static void
9870 __mmplayer_set_pause_state(mmplayer_t *player)
9871 {
9872         if (player->sent_bos)
9873                 return;
9874
9875         /* rtsp case, get content attrs by GstMessage */
9876         if (MMPLAYER_IS_RTSP_STREAMING(player))
9877                 return;
9878
9879         /* it's first time to update all content attrs. */
9880         _mmplayer_update_content_attrs(player, ATTR_ALL);
9881 }
9882
9883 static void
9884 __mmplayer_set_playing_state(mmplayer_t *player)
9885 {
9886         gchar *audio_codec = NULL;
9887
9888         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9889                 /* initialize because auto resume is done well. */
9890                 player->resumed_by_rewind = FALSE;
9891                 player->playback_rate = 1.0;
9892         }
9893
9894         if (player->sent_bos)
9895                 return;
9896
9897         /* try to get content metadata */
9898
9899         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9900          * c-api since c-api doesn't use _start() anymore. It may not work properly with
9901          * legacy mmfw-player api
9902          */
9903         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9904
9905         if ((player->cmd == MMPLAYER_COMMAND_START)
9906                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9907                 __mmplayer_handle_missed_plugin(player);
9908         }
9909
9910         /* check audio codec field is set or not
9911          * we can get it from typefinder or codec's caps.
9912          */
9913         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9914
9915         /* The codec format can't be sent for audio only case like amr, mid etc.
9916          * Because, parser don't make related TAG.
9917          * So, if it's not set yet, fill it with found data.
9918          */
9919         if (!audio_codec) {
9920                 if (g_strrstr(player->type, "audio/midi"))
9921                         audio_codec = "MIDI";
9922                 else if (g_strrstr(player->type, "audio/x-amr"))
9923                         audio_codec = "AMR";
9924                 else if (g_strrstr(player->type, "audio/mpeg")
9925                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9926                         audio_codec = "AAC";
9927                 else
9928                         audio_codec = "unknown";
9929
9930                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9931                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9932                         LOGE("failed to set attribute");
9933
9934                 LOGD("set audio codec type with caps");
9935         }
9936
9937         return;
9938 }