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