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