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