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