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