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