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