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